Skip to content

Commit

Permalink
Auto-generated commit
Browse files Browse the repository at this point in the history
  • Loading branch information
stdlib-bot committed Nov 12, 2024
1 parent b3ab016 commit cb2d1a8
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 129 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<section class="release" id="unreleased">

## Unreleased (2024-11-11)
## Unreleased (2024-11-12)

<section class="packages">

Expand Down Expand Up @@ -237,6 +237,7 @@ A total of 4 people contributed to this release. Thank you to the following cont

<details>

- [`d88cd86`](https://github.com/stdlib-js/stdlib/commit/d88cd86622b7a4ebffcb4b57aa60d5b7292fee73) - **refactor:** use constants, `FI_F` for addon and style fixes in `math/base/special/ldexpf` [(#2868)](https://github.com/stdlib-js/stdlib/pull/2868) _(by Gunj Joshi)_
- [`d9a93be`](https://github.com/stdlib-js/stdlib/commit/d9a93be954f04720bb5b03512be42c9ce6201088) - **feat:** add `math/base/special/croundf` [(#3061)](https://github.com/stdlib-js/stdlib/pull/3061) _(by Gururaj Gurram, Philipp Burckhardt)_
- [`f8bcfd8`](https://github.com/stdlib-js/stdlib/commit/f8bcfd832483d46068c710b6854d5f97bcb778fd) - **feat:** add `math/base/special/gcdf` [(#2997)](https://github.com/stdlib-js/stdlib/pull/2997) _(by Aayush Khanna, Philipp Burckhardt)_
- [`6556a46`](https://github.com/stdlib-js/stdlib/commit/6556a46aa3a6dffdff6becd4fb98d32421b3e7f2) - **feat:** add `math/base/special/cfloorf` [(#3058)](https://github.com/stdlib-js/stdlib/pull/3058) _(by Aayush Khanna)_
Expand Down
9 changes: 4 additions & 5 deletions base/special/ldexpf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var ldexpf = require( '@stdlib/math/base/special/ldexpf' );

#### ldexpf( frac, exp )

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

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

## Notes

// TODO: update this once we have `frexpf`.

- This function is the inverse of [`frexp`][@stdlib/math/base/special/frexp].
- This function is the inverse of [`frexpf`][@stdlib/math/base/special/frexpf].

</section>

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

[ieee754]: https://en.wikipedia.org/wiki/IEEE_754-1985
[@stdlib/math/base/special/frexp]: https://github.com/stdlib-js/math/tree/main/base/special/frexp

[@stdlib/math/base/special/frexpf]: https://github.com/stdlib-js/math/tree/main/base/special/frexpf

<!-- <related-links> -->

Expand Down
2 changes: 1 addition & 1 deletion base/special/ldexpf/docs/repl.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

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

If `frac` equals positive or negative `zero`, `NaN`, or positive or negative
infinity, the function returns a value equal to `frac`.
Expand Down
10 changes: 5 additions & 5 deletions base/special/ldexpf/examples/c/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@

int main( void ) {
float y;
int i;
int i;

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

for ( i = 0; i < 5; i++ ) {
y = stdlib_base_ldexpf( frac[ i ], exp[ i ] );
printf( "ldexpf(%f, %d) = %f\n", frac[ i ], exp[ i ], y );
}
for ( i = 0; i < 5; i++ ) {
y = stdlib_base_ldexpf( frac[ i ], exp[ i ] );
printf( "ldexpf(%f, %d) = %f\n", frac[ i ], exp[ i ], y );
}
}
41 changes: 23 additions & 18 deletions base/special/ldexpf/lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,17 @@ var copysignf = require( './../../../../base/special/copysignf' );
var toWord = require( '@stdlib/number/float32/base/to-word' );
var fromWord = require( '@stdlib/number/float32/base/from-word' );
var float64ToFloat32 = require( '@stdlib/number/float64/base/to-float32' );
var FLOAT32_EXPONENT_MASK = require( '@stdlib/constants/float32/exponent-mask' );
var FLOAT32_PRECISION = require( '@stdlib/constants/float32/precision' );
var FLOAT32_ABS_MASK = require( '@stdlib/constants/float32/abs-mask' );


// VARIABLES //

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


// MAIN //
Expand Down Expand Up @@ -91,51 +96,51 @@ function ldexpf( frac, exp ) {
frac = float64ToFloat32( frac );
ix = toWord( frac );

// Extract exponent
k = ( ix & 0x7f800000 ) >> 23;
// Extract exponent:
k = ( ix & FLOAT32_EXPONENT_MASK ) >> ( FLOAT32_PRECISION - 1 );

// 0 or subnormal frac
// 0 or subnormal frac:
if ( k === 0 ) {
if ( ( ix & 0x7fffffff ) === 0 ) {
// +-0
if ( ( ix & FLOAT32_ABS_MASK ) === 0 ) {
// +-0:
return frac;
}
frac = float64ToFloat32( frac * TWO25 );
ix = toWord( frac );
k = ( ( ix & 0x7f800000 ) >> 23 ) - 25;
k = ( ( ix & FLOAT32_EXPONENT_MASK ) >> ( FLOAT32_PRECISION - 1 ) ) - 25;
if ( exp < -50000 ) {
// Underflow
// Underflow:
return 0.0;
}
}

// NaN or Inf
if ( k === 0xff ) {
// NaN or Inf:
if ( k === ALL_ONES ) {
return float64ToFloat32( frac + frac );
}
k += exp;
if ( k > 0xfe ) {
// Overflow
k = ( k + exp ) | 0;
if ( k > ALL_ONES - 1 ) {
// Overflow:
return copysignf( PINF, frac );
}
if ( k > 0 ) {
// Normal result
frac = fromWord( ( ix & 0x807fffff ) | ( k << 23 ) );
// Normal result:
frac = fromWord( ( ix & FLOAT32_SIGNIFICAND_MASK_WITH_SIGN ) | ( k << ( FLOAT32_PRECISION - 1 ) ) );
return frac;
}
if ( k <= -25 ) {
if ( exp > 50000 ) {
// In case of integer overflow in n + k
// In case of integer overflow in n + k:
return copysignf( PINF, frac );
}

// Underflow
// Underflow:
return copysignf( 0.0, frac );
}

// Subnormal result
// Subnormal result:
k += 25;
frac = fromWord( ( ix & 0x807fffff ) | ( k << 23 ) );
frac = fromWord( ( ix & FLOAT32_SIGNIFICAND_MASK_WITH_SIGN ) | ( k << ( FLOAT32_PRECISION - 1 ) ) );
return float64ToFloat32( frac * TWOM25 );
}

Expand Down
16 changes: 13 additions & 3 deletions base/special/ldexpf/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,14 @@
"libraries": [],
"libpath": [],
"dependencies": [
"@stdlib/math/base/napi/binary",
"@stdlib/number/float32/base/from-word",
"@stdlib/number/float32/base/to-word",
"@stdlib/math/base/special/copysignf",
"@stdlib/constants/float32/pinf"
"@stdlib/constants/float32/pinf",
"@stdlib/constants/float32/exponent-mask",
"@stdlib/constants/float32/precision",
"@stdlib/constants/float32/abs-mask"
]
},
{
Expand All @@ -58,7 +62,10 @@
"@stdlib/number/float32/base/from-word",
"@stdlib/number/float32/base/to-word",
"@stdlib/math/base/special/copysignf",
"@stdlib/constants/float32/pinf"
"@stdlib/constants/float32/pinf",
"@stdlib/constants/float32/exponent-mask",
"@stdlib/constants/float32/precision",
"@stdlib/constants/float32/abs-mask"
]
},
{
Expand All @@ -75,7 +82,10 @@
"@stdlib/number/float32/base/from-word",
"@stdlib/number/float32/base/to-word",
"@stdlib/math/base/special/copysignf",
"@stdlib/constants/float32/pinf"
"@stdlib/constants/float32/pinf",
"@stdlib/constants/float32/exponent-mask",
"@stdlib/constants/float32/precision",
"@stdlib/constants/float32/abs-mask"
]
}
]
Expand Down
82 changes: 3 additions & 79 deletions base/special/ldexpf/src/addon.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,83 +17,7 @@
*/

#include "stdlib/math/base/special/ldexpf.h"
#include <node_api.h>
#include <stdint.h>
#include <assert.h>
#include "stdlib/math/base/napi/binary.h"

/**
* Receives JavaScript callback invocation data.
*
* @param env environment under which the function is invoked
* @param info callback data
* @return Node-API value
*/
static napi_value addon( napi_env env, napi_callback_info info ) {
napi_status status;

// Get callback arguments:
size_t argc = 2;
napi_value argv[ 2 ];
status = napi_get_cb_info( env, info, &argc, argv, NULL, NULL );
assert( status == napi_ok );

// Check whether we were provided the correct number of arguments:
if ( argc < 2 ) {
status = napi_throw_error( env, NULL, "invalid invocation. Insufficient arguments." );
assert( status == napi_ok );
return NULL;
}
if ( argc > 2 ) {
status = napi_throw_error( env, NULL, "invalid invocation. Too many arguments." );
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;
}

double frac;
status = napi_get_value_double( env, argv[ 0 ], &frac );
assert( status == napi_ok );

int32_t exp;
status = napi_get_value_int32( env, argv[ 1 ], &exp );
assert( status == napi_ok );

napi_value v;
status = napi_create_double( env, (double)stdlib_base_ldexpf( (float)frac, exp ), &v );
assert( status == napi_ok );

return v;
}

/**
* Initializes a Node-API module.
*
* @param env environment under which the function is invoked
* @param exports exports object
* @return main export
*/
static napi_value init( napi_env env, napi_value exports ) {
napi_value fcn;
napi_status status = napi_create_function( env, "exports", NAPI_AUTO_LENGTH, addon, NULL, &fcn );
assert( status == napi_ok );
return fcn;
}

NAPI_MODULE( NODE_GYP_MODULE_NAME, init )
// cppcheck-suppress shadowFunction
STDLIB_MATH_BASE_NAPI_MODULE_FI_F( stdlib_base_ldexpf )
39 changes: 22 additions & 17 deletions base/special/ldexpf/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,15 @@
#include "stdlib/number/float32/base/from_word.h"
#include "stdlib/math/base/special/copysignf.h"
#include "stdlib/constants/float32/pinf.h"
#include "stdlib/constants/float32/exponent_mask.h"
#include "stdlib/constants/float32/precision.h"
#include "stdlib/constants/float32/abs_mask.h"
#include <stdint.h>

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

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

// Extract exponent
k = ( ix & 0x7f800000 ) >> 23;
// Extract exponent:
k = ( ix & STDLIB_CONSTANT_FLOAT32_EXPONENT_MASK ) >> ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 );

// 0 or subnormal frac
// 0 or subnormal frac:
fracc = frac;
if ( k == 0 ) {
if ( ( ix & 0x7fffffff ) == 0 ) {
// +-0
if ( ( ix & STDLIB_CONSTANT_FLOAT32_ABS_MASK ) == 0 ) {
// +-0:
return frac;
}
fracc = frac * TWO25;
stdlib_base_float32_to_word( fracc, &uix );
ix = (int32_t)uix;
k = ( ( ix & 0x7f800000 ) >> 23 ) - 25;
k = ( ( ix & STDLIB_CONSTANT_FLOAT32_EXPONENT_MASK ) >> ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 ) ) - 25;
if ( exp < -50000 ) {
// Underflow
// Underflow:
return 0.0;
}
}

// NaN or Inf
if ( k == 0xff ) {
// NaN or Inf:
if ( k == ALL_ONES ) {
return fracc + fracc;
}
k += exp;
if ( k > 0xfe ) {
// Overflow
if ( k > ALL_ONES - 1 ) {
// Overflow:
return stdlib_base_copysignf( STDLIB_CONSTANT_FLOAT32_PINF, fracc );
}
if ( k > 0 ) {
// Normal result
stdlib_base_float32_from_word( (uint32_t)( ( ix & 0x807fffff ) | ( k << 23 ) ), &fracc );
// Normal result:
stdlib_base_float32_from_word( (uint32_t)( ( ix & FLOAT32_SIGNIFICAND_MASK_WITH_SIGN ) | ( k << ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 ) ) ), &fracc );
return fracc;
}
if ( k <= -25 ) {
if ( exp > 50000 ) {
// In case of integer overflow in n + k
// In case of integer overflow in n + k:
return stdlib_base_copysignf( STDLIB_CONSTANT_FLOAT32_PINF, fracc );
}

// Underflow
// Underflow:
return stdlib_base_copysignf( 0.0f, fracc );
}

// Subnormal result
// Subnormal result:
k += 25;
stdlib_base_float32_from_word( (uint32_t)( ( ix & 0x807fffff ) | ( k << 23 ) ), &fracc );
stdlib_base_float32_from_word( (uint32_t)( ( ix & FLOAT32_SIGNIFICAND_MASK_WITH_SIGN ) | ( k << ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 ) ) ), &fracc );
return fracc * TWOM25;
}
6 changes: 6 additions & 0 deletions base/special/ldexpf/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,9 @@ tape( 'if provided a fraction and a very large negative exponent, the function r
t.equal( v, 0.0, 'returns expected value' );
t.end();
});

tape( 'if provided a small fraction and a very large positive exponent, the function returns positive infinity due to integer overflow', function test( t ) {
var v = ldexpf( 1.17549435e-38, 3e10 );
t.equal( v, PINF, 'returns expected value' );
t.end();
});
6 changes: 6 additions & 0 deletions base/special/ldexpf/test/test.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,9 @@ tape( 'if provided a fraction and a very large negative exponent, the function r
t.equal( v, 0.0, 'returns expected value' );
t.end();
});

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 ) {
var v = ldexpf( 1.17549435e-38, 60000 );
t.equal( v, PINF, 'returns expected value' );
t.end();
});

0 comments on commit cb2d1a8

Please sign in to comment.