Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add C implementation for stats/base/dists/binomial/cdf #3463

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,48 @@
}; \
NAPI_MODULE( NODE_GYP_MODULE_NAME, stdlib_math_base_napi_dii_d_init )

/**
* Macro for registering a Node-API module exporting an interface invoking a ternary function accepting a double-precision floating-point number and two signed 64-bit integers and returning a double-precision floating-point number.
*
* @param fcn ternary function
*
* @example
* #include <stdint.h>
*
* static double fcn( const int_64 x, const int_64 y, const double z ) {
* // ...
* }
*
* // ...
*
* // Register a Node-API module:
* STDLIB_MATH_BASE_NAPI_MODULE_LLD_D( fcn );
*/
#define STDLIB_MATH_BASE_NAPI_MODULE_LLD_D( fcn ) \
static napi_value stdlib_math_base_napi_lld_d_wrapper( \
napi_env env, \
napi_callback_info info \
) { \
return stdlib_math_base_napi_lld_d( env, info, fcn ); \
}; \
static napi_value stdlib_math_base_napi_lld_d_init( \
napi_env env, \
napi_value exports \
) { \
napi_value fcn; \
napi_status status = napi_create_function( \
env, \
"exports", \
NAPI_AUTO_LENGTH, \
stdlib_math_base_napi_lld_d_wrapper, \
NULL, \
&fcn \
); \
assert( status == napi_ok ); \
return fcn; \
}; \
NAPI_MODULE( NODE_GYP_MODULE_NAME, stdlib_math_base_napi_lld_d_init )

/*
* If C++, prevent name mangling so that the compiler emits a ternary file having undecorated names, thus mirroring the behavior of a C compiler.
*/
Expand All @@ -165,6 +207,10 @@ napi_value stdlib_math_base_napi_fff_f( napi_env env, napi_callback_info info, f
* Invokes a ternary function accepting a double-precision floating-point number and two signed 32-bit integers and returning a double-precision floating-point number.
*/
napi_value stdlib_math_base_napi_dii_d( napi_env env, napi_callback_info info, double (*fcn)( double, int32_t, int32_t ) );
/**
* Invokes a ternary function accepting a double-precision floating-point number and two signed 64-bit integers and returning a double-precision floating-point number.
*/
napi_value stdlib_math_base_napi_lld_d( napi_env env, napi_callback_info info, double (*fcn)( int64_t, int64_t, double ) );

#ifdef __cplusplus
}
Expand Down
76 changes: 76 additions & 0 deletions lib/node_modules/@stdlib/math/base/napi/ternary/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,79 @@ napi_value stdlib_math_base_napi_dii_d( napi_env env, napi_callback_info info, d

return v;
}

/**
* Invokes a ternary function accepting a double-precision floating-point number and two signed 64-bit integers and returning a double-precision floating-point number.
*
* ## Notes
*
* - This function expects that the callback `info` argument provides access to the following JavaScript arguments:
*
* - `x`: input value.
* - `y`: input value.
* - `z`: input value.
*
* @param env environment under which the function is invoked
* @param info callback data
* @param fcn ternary function
* @return function return value as a Node-API double-precision floating-point number
*/
napi_value stdlib_math_base_napi_lld_d( napi_env env, napi_callback_info info, double (*fcn)( int64_t, int64_t, double ) ) {
napi_status status;

size_t argc = 3;
napi_value argv[ 3 ];
status = napi_get_cb_info( env, info, &argc, argv, NULL, NULL );
assert( status == napi_ok );

if ( argc < 3 ) {
status = napi_throw_error( env, NULL, "invalid invocation. Must provide three numbers." );
assert( status == napi_ok );
return NULL;
}

napi_valuetype vtype0;
status = napi_typeof( env, argv[ 0 ], &vtype0 );
assert( status == napi_ok );
if ( vtype0 != napi_number ) {
status = napi_throw_type_error( env, NULL, "invalid argument. First argument must be a number." );
assert( status == napi_ok );
return NULL;
}

napi_valuetype vtype1;
status = napi_typeof( env, argv[ 1 ], &vtype1 );
assert( status == napi_ok );
if ( vtype1 != napi_number ) {
status = napi_throw_type_error( env, NULL, "invalid argument. Second argument must be a number." );
assert( status == napi_ok );
return NULL;
}

napi_valuetype vtype2;
status = napi_typeof( env, argv[ 2 ], &vtype2 );
assert( status == napi_ok );
if ( vtype2 != napi_number ) {
status = napi_throw_type_error( env, NULL, "invalid argument. Third argument must be a number." );
assert( status == napi_ok );
return NULL;
}

int64_t x;
status = napi_get_value_int64( env, argv[ 0 ], &x );
assert( status == napi_ok );

int64_t y;
status = napi_get_value_int64( env, argv[ 1 ], &y );
assert( status == napi_ok );

double z;
status = napi_get_value_double( env, argv[ 2 ], &z );
assert( status == napi_ok );

napi_value v;
status = napi_create_double( env, fcn( x, y, z ), &v );
assert( status == napi_ok );

return v;
}
97 changes: 97 additions & 0 deletions lib/node_modules/@stdlib/stats/base/dists/binomial/cdf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,103 @@ for ( i = 0; i < 10; i++ ) {

<!-- /.examples -->

<!-- C interface documentation. -->

* * *

<section class="c">

## C APIs

<!-- Section to include introductory text. Make sure to keep an empty line after the intro `section` element and another before the `/section` close. -->

<section class="intro">

</section>

<!-- /.intro -->

<!-- C usage documentation. -->

<section class="usage">

### Usage

```c
#include "stdlib/stats/base/dists/binomial/cdf.h"
```

#### stdlib_base_dists_binomial_cdf( k, n, p )

Evaluates the cumulative distribution function (CDF) for a binomial distribution.

```c
double out = stdlib_base_dists_binomial_cdf( 5, 10, 0.5 );
// returns ~0.623
```

The function accepts the following arguments:

- **k**: `[in] int` input value.
- **n**: `[in] int` number of trials.
- **p**: `[in] double` success probability.

```c
double stdlib_base_dists_binomial_cdf( const int64_t k, const int64_t n, const double p );
```
</section>
<!-- /.usage -->
<!-- C API usage notes. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
<section class="notes">
</section>
<!-- /.notes -->
<!-- C API usage examples. -->
<section class="examples">
### Examples
```c
#include "stdlib/stats/base/dists/binomial/cdf.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
static double random_uniform( const double min, const double max ) {
double v = (double)rand() / ( (double)RAND_MAX + 1.0 );
return min + ( v*(max-min) );
}
int main( void ) {
int64_t k;
int64_t n;
double p;
double y;
int i;
for ( i = 0; i < 25; i++ ) {
k = (int64_t)random_uniform(0.0,10.0); // Random integer between 0 and 10
n = k+(int64_t)random_uniform(0.0,10.0); // Random integer between k and 20
p = random_uniform(0.0,1.0); // Random double between 0.0 and 1.0
y = stdlib_base_dists_binomial_cdf( k, n, p );
printf( "k: %d, n: %d, p: %lf, F(k;n,p): %lf\n", k, n, p, y );
}
}
```

</section>

<!-- /.examples -->

</section>

<!-- /.c -->

<!-- Section for related `stdlib` packages. Do not manually edit this section, as it is automatically populated. -->

<section class="related">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,64 +21,74 @@
// MODULES //

var bench = require( '@stdlib/bench' );
var ceil = require( '@stdlib/math/base/special/ceil' );
var Float64Array = require( '@stdlib/array/float64' );
var uniform = require( '@stdlib/random/array/uniform' );
var randu = require( '@stdlib/random/base/randu' );
var floor = require( '@stdlib/math/base/special/floor' );
var isnan = require( '@stdlib/math/base/assert/is-nan' );
var pkg = require( './../package.json' ).name;
var cdf = require( './../lib' );


// MAIN //

bench( pkg, function benchmark( b ) {
bench(pkg, function benchmark(b) {
var len;
var k;
var n;
var p;
var x;
var y;
var i;

len = 100;
k = new Float64Array(len);
n = new Float64Array(len);
p = new Float64Array(len);
for (i = 0; i < len; i++) {
k[i] = floor(randu() * 11);
n[i] = floor(randu() * 21);
p[i] = randu();
}

b.tic();
for ( i = 0; i < b.iterations; i++ ) {
x = randu() * 100.0;
n = ceil( randu()*100.0 );
p = randu();
y = cdf( x, n, p );
if ( isnan( y ) ) {
b.fail( 'should not return NaN' );
for (i = 0; i < b.iterations; i++) {
y = cdf(k[i % len], n[i % len], p[i % len]);
if (isnan(y)) {
b.fail('should not return NaN');
}
}
b.toc();
if ( isnan( y ) ) {
b.fail( 'should not return NaN' );
if (isnan(y)) {
b.fail('should not return NaN');
}
b.pass( 'benchmark finished' );
b.pass('benchmark finished');
b.end();
});

bench( pkg+':factory', function benchmark( b ) {
bench(pkg + ':factory', function benchmark(b) {
var mycdf;
var n;
var p;
var x;
var k;
var y;
var i;

n = 80;
p = 0.4;
mycdf = cdf.factory( n, p );
n = 10;
p = 0.5;
mycdf = cdf.factory(n, p);
k = uniform(100, 0, n);

b.tic();
for ( i = 0; i < b.iterations; i++ ) {
x = randu() * 80.0;
y = mycdf( x );
if ( isnan( y ) ) {
b.fail( 'should not return NaN' );
for (i = 0; i < b.iterations; i++) {
y = mycdf(k[i % k.length]);
if (isnan(y)) {
b.fail('should not return NaN');
}
}
b.toc();
if ( isnan( y ) ) {
b.fail( 'should not return NaN' );
if (isnan(y)) {
b.fail('should not return NaN');
}
b.pass( 'benchmark finished' );
b.pass('benchmark finished');
b.end();
});
Loading
Loading