Skip to content

Commit 72d37f3

Browse files
gunjjoshikgryte
andauthored
refactor!: modify C implementation to accept float values instead of int32 in math/base/special/binomcoeff
This commit updates the signature of the C API to accept a float rather than int32. The rationale was so that users get the same results/behavior in both JavaScript and C. This arose in the context of ufuncs, where the diverging type signatures meant differences in what dtypes would be permissible. Instead, we decided to unify and ensure the behavior is consistent. BREAKING CHANGE: update signature to accept floats User code should behave similarly in the primary case of providing integer-valued input values. However, no longer will real-values truncate. Now, real-valued inputs will result in `NaN`, which is, arguably, better behavior, as real-to-integer truncation can be a source of silent bugs. PR-URL: #7946 Co-authored-by: Athan Reines <[email protected]> Reviewed-by: Athan Reines <[email protected]>
1 parent 0681f24 commit 72d37f3

File tree

7 files changed

+42
-36
lines changed

7 files changed

+42
-36
lines changed

lib/node_modules/@stdlib/math/base/special/binomcoeff/README.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,17 @@ logEachMap( 'binomcoeff(%d,%d) = %0.4f', n, k, binomcoeff );
162162
Evaluates the [binomial coefficient][binomial-coefficient] of two integers `n` and `k` as a single-precision floating-point number.
163163

164164
```c
165-
float v = stdlib_base_binomcoeff( 8, 2 );
165+
float v = stdlib_base_binomcoeff( 8.0f, 2.0f );
166166
// returns 28.0f
167167
```
168168

169169
The function accepts the following arguments:
170170

171-
- **n**: `[in] int32_t` input value.
172-
- **k**: `[in] int32_t` input value.
171+
- **n**: `[in] float` input value.
172+
- **k**: `[in] float` input value.
173173

174174
```c
175-
float stdlib_base_binomcoeff( const int32_t n, const int32_t k );
175+
float stdlib_base_binomcoeff( const float n, const float k );
176176
```
177177
178178
</section>
@@ -196,17 +196,16 @@ float stdlib_base_binomcoeff( const int32_t n, const int32_t k );
196196
```c
197197
#include "stdlib/math/base/special/binomcoeff.h"
198198
#include <stdio.h>
199-
#include <stdint.h>
200199
201200
int main( void ) {
202-
const int32_t a[] = { 24, 32, 48, 116, 33 };
203-
const int32_t b[] = { 12, 6, 15, 52, 22 };
201+
const float a[] = { 24.0f, 32.0f, 48.0f, 116.0f, 33.0f };
202+
const float b[] = { 12.0f, 6.0f, 15.0f, 52.0f, 22.0f };
204203
205204
float out;
206205
int i;
207206
for ( i = 0; i < 5; i++ ) {
208207
out = stdlib_base_binomcoeff( a[ i ], b[ i ] );
209-
printf( "binomcoeff(%d, %d) = %f\n", a[ i ], b[ i ], out );
208+
printf( "binomcoeff(%f, %f) = %f\n", a[ i ], b[ i ], out );
210209
}
211210
}
212211
```

lib/node_modules/@stdlib/math/base/special/binomcoeff/benchmark/c/native/benchmark.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,16 @@ static float rand_float( void ) {
9090
* @return elapsed time in seconds
9191
*/
9292
static double benchmark( void ) {
93-
int32_t n[ 100 ];
94-
int32_t k[ 100 ];
93+
float n[ 100 ];
94+
float k[ 100 ];
9595
double elapsed;
9696
double t;
9797
float y;
9898
int i;
9999

100100
for ( i = 0; i < 100; i++ ) {
101-
n[ i ] = (int32_t)round( 100.0 * rand_float() );
102-
k[ i ] = (int32_t)round( 100.0 * rand_float() );
101+
n[ i ] = roundf( 100.0f * rand_float() );
102+
k[ i ] = roundf( 100.0f * rand_float() );
103103
}
104104

105105
t = tic();

lib/node_modules/@stdlib/math/base/special/binomcoeff/examples/c/example.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,15 @@
1818

1919
#include "stdlib/math/base/special/binomcoeff.h"
2020
#include <stdio.h>
21-
#include <stdint.h>
2221

2322
int main( void ) {
24-
const int32_t a[] = { 24, 32, 48, 116, 33 };
25-
const int32_t b[] = { 12, 6, 15, 52, 22 };
23+
const float a[] = { 24.0f, 32.0f, 48.0f, 116.0f, 33.0f };
24+
const float b[] = { 12.0f, 6.0f, 15.0f, 52.0f, 22.0f };
2625

2726
float out;
2827
int i;
2928
for ( i = 0; i < 5; i++ ) {
3029
out = stdlib_base_binomcoeff( a[ i ], b[ i ] );
31-
printf( "binomcoeff(%d, %d) = %f\n", a[ i ], b[ i ], out );
30+
printf( "binomcoeff(%f, %f) = %f\n", a[ i ], b[ i ], out );
3231
}
3332
}

lib/node_modules/@stdlib/math/base/special/binomcoeff/include/stdlib/math/base/special/binomcoeff.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#ifndef STDLIB_MATH_BASE_SPECIAL_BINOMCOEFF_H
2020
#define STDLIB_MATH_BASE_SPECIAL_BINOMCOEFF_H
2121

22-
#include <stdint.h>
23-
2422
/*
2523
* If C++, prevent name mangling so that the compiler emits a binary file having undecorated names, thus mirroring the behavior of a C compiler.
2624
*/
@@ -31,7 +29,7 @@ extern "C" {
3129
/**
3230
* Computes the binomial coefficient of two integers as a single-precision floating-point number.
3331
*/
34-
float stdlib_base_binomcoeff( const int32_t n, const int32_t k );
32+
float stdlib_base_binomcoeff( const float n, const float k );
3533

3634
#ifdef __cplusplus
3735
}

lib/node_modules/@stdlib/math/base/special/binomcoeff/manifest.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@
4242
"@stdlib/math/base/special/floorf",
4343
"@stdlib/math/base/special/gcdf",
4444
"@stdlib/constants/float32/pinf",
45-
"@stdlib/constants/float32/max-safe-integer"
45+
"@stdlib/constants/float32/max-safe-integer",
46+
"@stdlib/math/base/assert/is-integerf",
47+
"@stdlib/math/base/assert/is-oddf"
4648
]
4749
},
4850
{
@@ -61,7 +63,9 @@
6163
"@stdlib/math/base/special/floorf",
6264
"@stdlib/math/base/special/gcdf",
6365
"@stdlib/constants/float32/pinf",
64-
"@stdlib/constants/float32/max-safe-integer"
66+
"@stdlib/constants/float32/max-safe-integer",
67+
"@stdlib/math/base/assert/is-integerf",
68+
"@stdlib/math/base/assert/is-oddf"
6569
]
6670
},
6771
{
@@ -80,7 +84,9 @@
8084
"@stdlib/math/base/special/floorf",
8185
"@stdlib/math/base/special/gcdf",
8286
"@stdlib/constants/float32/pinf",
83-
"@stdlib/constants/float32/max-safe-integer"
87+
"@stdlib/constants/float32/max-safe-integer",
88+
"@stdlib/math/base/assert/is-integerf",
89+
"@stdlib/math/base/assert/is-oddf"
8490
]
8591
}
8692
]

lib/node_modules/@stdlib/math/base/special/binomcoeff/src/addon.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@
1919
#include "stdlib/math/base/special/binomcoeff.h"
2020
#include "stdlib/math/base/napi/binary.h"
2121

22-
STDLIB_MATH_BASE_NAPI_MODULE_II_F( stdlib_base_binomcoeff )
22+
STDLIB_MATH_BASE_NAPI_MODULE_FF_F( stdlib_base_binomcoeff )

lib/node_modules/@stdlib/math/base/special/binomcoeff/src/main.c

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
*/
1818

1919
#include "stdlib/math/base/special/binomcoeff.h"
20+
#include "stdlib/math/base/assert/is_integerf.h"
21+
#include "stdlib/math/base/assert/is_oddf.h"
2022
#include "stdlib/math/base/special/floorf.h"
2123
#include "stdlib/math/base/special/gcdf.h"
2224
#include "stdlib/constants/float32/pinf.h"
2325
#include "stdlib/constants/float32/max_safe_integer.h"
24-
#include <stdint.h>
2526

2627
/**
2728
* Computes the binomial coefficient of two integers as a single-precision floating-point number.
@@ -31,28 +32,31 @@
3132
* @return function value
3233
*
3334
* @example
34-
* float out = stdlib_base_binomcoeff( 8, 2 );
35+
* float out = stdlib_base_binomcoeff( 8.0f, 2.0f );
3536
* // returns 28.0f
3637
*/
37-
float stdlib_base_binomcoeff( const int32_t n, const int32_t k ) {
38-
int32_t nc;
39-
int32_t kc;
40-
int32_t d;
38+
float stdlib_base_binomcoeff( const float n, const float k ) {
4139
float res;
4240
float sgn;
41+
float nc;
42+
float kc;
43+
float d;
4344
float b;
4445
float c;
4546
float g;
4647
float s;
4748

49+
if ( !stdlib_base_is_integerf( n ) || !stdlib_base_is_integerf( k ) ) {
50+
return 0.0f / 0.0f; // NaN
51+
}
4852
if ( k < 0 ) {
4953
return 0.0f;
5054
}
5155
sgn = 1.0f;
5256
nc = n;
5357
if ( nc < 0 ) {
5458
nc = -nc + k - 1;
55-
if ( k & 1 ) {
59+
if ( stdlib_base_is_oddf( k ) ) {
5660
sgn *= -1.0f;
5761
}
5862
}
@@ -63,25 +67,25 @@ float stdlib_base_binomcoeff( const int32_t n, const int32_t k ) {
6367
return sgn;
6468
}
6569
if ( k == 1 || k == nc - 1 ) {
66-
return sgn * (float)nc;
70+
return sgn * nc;
6771
}
6872

6973
// Minimize the number of computed terms by leveraging symmetry:
7074
kc = k;
7175
if ( nc - kc < kc ) {
7276
kc = nc - kc;
7377
}
74-
s = stdlib_base_floorf( (float)STDLIB_CONSTANT_FLOAT32_MAX_SAFE_INTEGER / (float)nc );
78+
s = stdlib_base_floorf( (float)STDLIB_CONSTANT_FLOAT32_MAX_SAFE_INTEGER / nc );
7579

7680
// Use a standard algorithm for computing the binomial coefficient
7781
res = 1.0f;
78-
for ( d = 1; d <= kc; d++ ) {
82+
for ( d = 1.0f; d <= kc; d++ ) {
7983
// Check for potential overflow...
8084
if ( res > s ) {
8185
break;
8286
}
83-
res *= (float)nc;
84-
res /= (float)d;
87+
res *= nc;
88+
res /= d;
8589
nc -= 1;
8690
}
8791

@@ -110,7 +114,7 @@ float stdlib_base_binomcoeff( const int32_t n, const int32_t k ) {
110114
if ( b == STDLIB_CONSTANT_FLOAT32_PINF ) {
111115
return sgn * b;
112116
}
113-
c = stdlib_base_binomcoeff( kc, kc-d+1 ) ;
117+
c = stdlib_base_binomcoeff( kc, kc-d+1 );
114118

115119
/*
116120
* At this point, the result should be `res*b/c`.

0 commit comments

Comments
 (0)