Skip to content

Commit d88cd86

Browse files
authored
refactor: use constants, FI_F for addon and style fixes in math/base/special/ldexpf
PR-URL: #2868 Reviewed-by: Philipp Burckhardt <pburckhardt@outlook.com> Reviewed-by: Athan Reines <kgryte@gmail.com>
1 parent a4ca598 commit d88cd86

File tree

9 files changed

+83
-128
lines changed

9 files changed

+83
-128
lines changed

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var ldexpf = require( '@stdlib/math/base/special/ldexpf' );
3232

3333
#### ldexpf( frac, exp )
3434

35-
Multiplies a [single-precision floating-point number][ieee754] by an `integer` power of two (i.e., `x = frac * 2^exp`).
35+
Multiplies a [single-precision floating-point number][ieee754] by an integer power of two (i.e., `x = frac * 2^exp`).
3636

3737
```javascript
3838
var x = ldexpf( 0.5, 3 ); // => 0.5 * 2^3 = 0.5 * 8
@@ -67,9 +67,7 @@ x = ldexpf( -Infinity, -118 );
6767

6868
## Notes
6969

70-
// TODO: update this once we have `frexpf`.
71-
72-
- This function is the inverse of [`frexp`][@stdlib/math/base/special/frexp].
70+
- This function is the inverse of [`frexpf`][@stdlib/math/base/special/frexpf].
7371

7472
</section>
7573

@@ -201,7 +199,8 @@ int main( void ) {
201199
<section class="links">
202200

203201
[ieee754]: https://en.wikipedia.org/wiki/IEEE_754-1985
204-
[@stdlib/math/base/special/frexp]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/math/base/special/frexp
202+
203+
[@stdlib/math/base/special/frexpf]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/math/base/special/frexpf
205204

206205
<!-- <related-links> -->
207206

lib/node_modules/@stdlib/math/base/special/ldexpf/docs/repl.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
{{alias}}( frac, exp )
33
Multiplies a single-precision floating-point number by an integer power of
4-
two; i.e., `x = frac * 2^exp`.
4+
two (i.e., `x = frac * 2^exp`).
55

66
If `frac` equals positive or negative `zero`, `NaN`, or positive or negative
77
infinity, the function returns a value equal to `frac`.

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@
2222

2323
int main( void ) {
2424
float y;
25-
int i;
25+
int i;
2626

2727
const float frac[] = { 0.5f, 5.0f, 0.0f, 3.5f, 7.9f };
2828
const int32_t exp[] = { 3, -2, 20, 39, 14 };
2929

30-
for ( i = 0; i < 5; i++ ) {
31-
y = stdlib_base_ldexpf( frac[ i ], exp[ i ] );
32-
printf( "ldexpf(%f, %d) = %f\n", frac[ i ], exp[ i ], y );
33-
}
30+
for ( i = 0; i < 5; i++ ) {
31+
y = stdlib_base_ldexpf( frac[ i ], exp[ i ] );
32+
printf( "ldexpf(%f, %d) = %f\n", frac[ i ], exp[ i ], y );
33+
}
3434
}

lib/node_modules/@stdlib/math/base/special/ldexpf/lib/main.js

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,17 @@ var copysignf = require( '@stdlib/math/base/special/copysignf' );
3939
var toWord = require( '@stdlib/number/float32/base/to-word' );
4040
var fromWord = require( '@stdlib/number/float32/base/from-word' );
4141
var float64ToFloat32 = require( '@stdlib/number/float64/base/to-float32' );
42+
var FLOAT32_EXPONENT_MASK = require( '@stdlib/constants/float32/exponent-mask' );
43+
var FLOAT32_PRECISION = require( '@stdlib/constants/float32/precision' );
44+
var FLOAT32_ABS_MASK = require( '@stdlib/constants/float32/abs-mask' );
4245

4346

4447
// VARIABLES //
4548

4649
var TWO25 = 33554432.0; // 0x4c000000
4750
var TWOM25 = 2.9802322387695312e-8; // 0x33000000
51+
var FLOAT32_SIGNIFICAND_MASK_WITH_SIGN = 0x807fffff; // 1 00000000 11111111111111111111111
52+
var ALL_ONES = 0xff; // 0xff = 255 => 11111111
4853

4954

5055
// MAIN //
@@ -91,51 +96,51 @@ function ldexpf( frac, exp ) {
9196
frac = float64ToFloat32( frac );
9297
ix = toWord( frac );
9398

94-
// Extract exponent
95-
k = ( ix & 0x7f800000 ) >> 23;
99+
// Extract exponent:
100+
k = ( ix & FLOAT32_EXPONENT_MASK ) >> ( FLOAT32_PRECISION - 1 );
96101

97-
// 0 or subnormal frac
102+
// 0 or subnormal frac:
98103
if ( k === 0 ) {
99-
if ( ( ix & 0x7fffffff ) === 0 ) {
100-
// +-0
104+
if ( ( ix & FLOAT32_ABS_MASK ) === 0 ) {
105+
// +-0:
101106
return frac;
102107
}
103108
frac = float64ToFloat32( frac * TWO25 );
104109
ix = toWord( frac );
105-
k = ( ( ix & 0x7f800000 ) >> 23 ) - 25;
110+
k = ( ( ix & FLOAT32_EXPONENT_MASK ) >> ( FLOAT32_PRECISION - 1 ) ) - 25;
106111
if ( exp < -50000 ) {
107-
// Underflow
112+
// Underflow:
108113
return 0.0;
109114
}
110115
}
111116

112-
// NaN or Inf
113-
if ( k === 0xff ) {
117+
// NaN or Inf:
118+
if ( k === ALL_ONES ) {
114119
return float64ToFloat32( frac + frac );
115120
}
116-
k += exp;
117-
if ( k > 0xfe ) {
118-
// Overflow
121+
k = ( k + exp ) | 0;
122+
if ( k > ALL_ONES - 1 ) {
123+
// Overflow:
119124
return copysignf( PINF, frac );
120125
}
121126
if ( k > 0 ) {
122-
// Normal result
123-
frac = fromWord( ( ix & 0x807fffff ) | ( k << 23 ) );
127+
// Normal result:
128+
frac = fromWord( ( ix & FLOAT32_SIGNIFICAND_MASK_WITH_SIGN ) | ( k << ( FLOAT32_PRECISION - 1 ) ) );
124129
return frac;
125130
}
126131
if ( k <= -25 ) {
127132
if ( exp > 50000 ) {
128-
// In case of integer overflow in n + k
133+
// In case of integer overflow in n + k:
129134
return copysignf( PINF, frac );
130135
}
131136

132-
// Underflow
137+
// Underflow:
133138
return copysignf( 0.0, frac );
134139
}
135140

136-
// Subnormal result
141+
// Subnormal result:
137142
k += 25;
138-
frac = fromWord( ( ix & 0x807fffff ) | ( k << 23 ) );
143+
frac = fromWord( ( ix & FLOAT32_SIGNIFICAND_MASK_WITH_SIGN ) | ( k << ( FLOAT32_PRECISION - 1 ) ) );
139144
return float64ToFloat32( frac * TWOM25 );
140145
}
141146

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,14 @@
3636
"libraries": [],
3737
"libpath": [],
3838
"dependencies": [
39+
"@stdlib/math/base/napi/binary",
3940
"@stdlib/number/float32/base/from-word",
4041
"@stdlib/number/float32/base/to-word",
4142
"@stdlib/math/base/special/copysignf",
42-
"@stdlib/constants/float32/pinf"
43+
"@stdlib/constants/float32/pinf",
44+
"@stdlib/constants/float32/exponent-mask",
45+
"@stdlib/constants/float32/precision",
46+
"@stdlib/constants/float32/abs-mask"
4347
]
4448
},
4549
{
@@ -58,7 +62,10 @@
5862
"@stdlib/number/float32/base/from-word",
5963
"@stdlib/number/float32/base/to-word",
6064
"@stdlib/math/base/special/copysignf",
61-
"@stdlib/constants/float32/pinf"
65+
"@stdlib/constants/float32/pinf",
66+
"@stdlib/constants/float32/exponent-mask",
67+
"@stdlib/constants/float32/precision",
68+
"@stdlib/constants/float32/abs-mask"
6269
]
6370
},
6471
{
@@ -75,7 +82,10 @@
7582
"@stdlib/number/float32/base/from-word",
7683
"@stdlib/number/float32/base/to-word",
7784
"@stdlib/math/base/special/copysignf",
78-
"@stdlib/constants/float32/pinf"
85+
"@stdlib/constants/float32/pinf",
86+
"@stdlib/constants/float32/exponent-mask",
87+
"@stdlib/constants/float32/precision",
88+
"@stdlib/constants/float32/abs-mask"
7989
]
8090
}
8191
]

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

Lines changed: 3 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -17,83 +17,7 @@
1717
*/
1818

1919
#include "stdlib/math/base/special/ldexpf.h"
20-
#include <node_api.h>
21-
#include <stdint.h>
22-
#include <assert.h>
20+
#include "stdlib/math/base/napi/binary.h"
2321

24-
/**
25-
* Receives JavaScript callback invocation data.
26-
*
27-
* @param env environment under which the function is invoked
28-
* @param info callback data
29-
* @return Node-API value
30-
*/
31-
static napi_value addon( napi_env env, napi_callback_info info ) {
32-
napi_status status;
33-
34-
// Get callback arguments:
35-
size_t argc = 2;
36-
napi_value argv[ 2 ];
37-
status = napi_get_cb_info( env, info, &argc, argv, NULL, NULL );
38-
assert( status == napi_ok );
39-
40-
// Check whether we were provided the correct number of arguments:
41-
if ( argc < 2 ) {
42-
status = napi_throw_error( env, NULL, "invalid invocation. Insufficient arguments." );
43-
assert( status == napi_ok );
44-
return NULL;
45-
}
46-
if ( argc > 2 ) {
47-
status = napi_throw_error( env, NULL, "invalid invocation. Too many arguments." );
48-
assert( status == napi_ok );
49-
return NULL;
50-
}
51-
52-
napi_valuetype vtype0;
53-
status = napi_typeof( env, argv[ 0 ], &vtype0 );
54-
assert( status == napi_ok );
55-
if ( vtype0 != napi_number ) {
56-
status = napi_throw_type_error( env, NULL, "invalid argument. First argument must be a number." );
57-
assert( status == napi_ok );
58-
return NULL;
59-
}
60-
61-
napi_valuetype vtype1;
62-
status = napi_typeof( env, argv[ 1 ], &vtype1 );
63-
assert( status == napi_ok );
64-
if ( vtype1 != napi_number ) {
65-
status = napi_throw_type_error( env, NULL, "invalid argument. Second argument must be a number." );
66-
assert( status == napi_ok );
67-
return NULL;
68-
}
69-
70-
double frac;
71-
status = napi_get_value_double( env, argv[ 0 ], &frac );
72-
assert( status == napi_ok );
73-
74-
int32_t exp;
75-
status = napi_get_value_int32( env, argv[ 1 ], &exp );
76-
assert( status == napi_ok );
77-
78-
napi_value v;
79-
status = napi_create_double( env, (double)stdlib_base_ldexpf( (float)frac, exp ), &v );
80-
assert( status == napi_ok );
81-
82-
return v;
83-
}
84-
85-
/**
86-
* Initializes a Node-API module.
87-
*
88-
* @param env environment under which the function is invoked
89-
* @param exports exports object
90-
* @return main export
91-
*/
92-
static napi_value init( napi_env env, napi_value exports ) {
93-
napi_value fcn;
94-
napi_status status = napi_create_function( env, "exports", NAPI_AUTO_LENGTH, addon, NULL, &fcn );
95-
assert( status == napi_ok );
96-
return fcn;
97-
}
98-
99-
NAPI_MODULE( NODE_GYP_MODULE_NAME, init )
22+
// cppcheck-suppress shadowFunction
23+
STDLIB_MATH_BASE_NAPI_MODULE_FI_F( stdlib_base_ldexpf )

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

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,15 @@
3535
#include "stdlib/number/float32/base/from_word.h"
3636
#include "stdlib/math/base/special/copysignf.h"
3737
#include "stdlib/constants/float32/pinf.h"
38+
#include "stdlib/constants/float32/exponent_mask.h"
39+
#include "stdlib/constants/float32/precision.h"
40+
#include "stdlib/constants/float32/abs_mask.h"
3841
#include <stdint.h>
3942

4043
static const float TWO25 = 33554432.0f; // 0x4c000000
4144
static const float TWOM25 = 2.9802322387695312e-8f; // 0x33000000
45+
static const int32_t FLOAT32_SIGNIFICAND_MASK_WITH_SIGN = 0x807fffff; // 1 00000000 11111111111111111111111
46+
static const int32_t ALL_ONES = 0xff; // 0xff = 255 => 11111111
4247

4348
/**
4449
* Multiplies a single-precision floating-point number by an integer power of two.
@@ -60,52 +65,52 @@ float stdlib_base_ldexpf( const float frac, const int32_t exp ) {
6065
stdlib_base_float32_to_word( frac, &uix );
6166
ix = (int32_t)uix;
6267

63-
// Extract exponent
64-
k = ( ix & 0x7f800000 ) >> 23;
68+
// Extract exponent:
69+
k = ( ix & STDLIB_CONSTANT_FLOAT32_EXPONENT_MASK ) >> ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 );
6570

66-
// 0 or subnormal frac
71+
// 0 or subnormal frac:
6772
fracc = frac;
6873
if ( k == 0 ) {
69-
if ( ( ix & 0x7fffffff ) == 0 ) {
70-
// +-0
74+
if ( ( ix & STDLIB_CONSTANT_FLOAT32_ABS_MASK ) == 0 ) {
75+
// +-0:
7176
return frac;
7277
}
7378
fracc = frac * TWO25;
7479
stdlib_base_float32_to_word( fracc, &uix );
7580
ix = (int32_t)uix;
76-
k = ( ( ix & 0x7f800000 ) >> 23 ) - 25;
81+
k = ( ( ix & STDLIB_CONSTANT_FLOAT32_EXPONENT_MASK ) >> ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 ) ) - 25;
7782
if ( exp < -50000 ) {
78-
// Underflow
83+
// Underflow:
7984
return 0.0;
8085
}
8186
}
8287

83-
// NaN or Inf
84-
if ( k == 0xff ) {
88+
// NaN or Inf:
89+
if ( k == ALL_ONES ) {
8590
return fracc + fracc;
8691
}
8792
k += exp;
88-
if ( k > 0xfe ) {
89-
// Overflow
93+
if ( k > ALL_ONES - 1 ) {
94+
// Overflow:
9095
return stdlib_base_copysignf( STDLIB_CONSTANT_FLOAT32_PINF, fracc );
9196
}
9297
if ( k > 0 ) {
93-
// Normal result
94-
stdlib_base_float32_from_word( (uint32_t)( ( ix & 0x807fffff ) | ( k << 23 ) ), &fracc );
98+
// Normal result:
99+
stdlib_base_float32_from_word( (uint32_t)( ( ix & FLOAT32_SIGNIFICAND_MASK_WITH_SIGN ) | ( k << ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 ) ) ), &fracc );
95100
return fracc;
96101
}
97102
if ( k <= -25 ) {
98103
if ( exp > 50000 ) {
99-
// In case of integer overflow in n + k
104+
// In case of integer overflow in n + k:
100105
return stdlib_base_copysignf( STDLIB_CONSTANT_FLOAT32_PINF, fracc );
101106
}
102107

103-
// Underflow
108+
// Underflow:
104109
return stdlib_base_copysignf( 0.0f, fracc );
105110
}
106111

107-
// Subnormal result
112+
// Subnormal result:
108113
k += 25;
109-
stdlib_base_float32_from_word( (uint32_t)( ( ix & 0x807fffff ) | ( k << 23 ) ), &fracc );
114+
stdlib_base_float32_from_word( (uint32_t)( ( ix & FLOAT32_SIGNIFICAND_MASK_WITH_SIGN ) | ( k << ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 ) ) ), &fracc );
110115
return fracc * TWOM25;
111116
}

lib/node_modules/@stdlib/math/base/special/ldexpf/test/test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,9 @@ tape( 'if provided a fraction and a very large negative exponent, the function r
225225
t.equal( v, 0.0, 'returns expected value' );
226226
t.end();
227227
});
228+
229+
tape( 'if provided a small fraction and a very large positive exponent, the function returns positive infinity due to integer overflow', function test( t ) {
230+
var v = ldexpf( 1.17549435e-38, 3e10 );
231+
t.equal( v, PINF, 'returns expected value' );
232+
t.end();
233+
});

lib/node_modules/@stdlib/math/base/special/ldexpf/test/test.native.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,9 @@ tape( 'if provided a fraction and a very large negative exponent, the function r
234234
t.equal( v, 0.0, 'returns expected value' );
235235
t.end();
236236
});
237+
238+
tape( 'if provided a small fraction and a very large positive exponent, the function returns positive infinity due to integer overflow', opts, function test( t ) {
239+
var v = ldexpf( 1.17549435e-38, 60000 );
240+
t.equal( v, PINF, 'returns expected value' );
241+
t.end();
242+
});

0 commit comments

Comments
 (0)