diff --git a/lib/node_modules/@stdlib/math/base/special/ldexp/lib/main.js b/lib/node_modules/@stdlib/math/base/special/ldexp/lib/main.js index 3c033a9f105f..85bbf11d0595 100644 --- a/lib/node_modules/@stdlib/math/base/special/ldexp/lib/main.js +++ b/lib/node_modules/@stdlib/math/base/special/ldexp/lib/main.js @@ -44,8 +44,8 @@ var fromWords = require( '@stdlib/number/float64/base/from-words' ); // VARIABLES // -// 1/(1<<52) = 1/(2**52) = 1/4503599627370496 -var TWO52_INV = 2.220446049250313e-16; +// 1/(1<<54) = 1/(2**54) = 1/18014398509481984 +var TWO54_INV = 5.551115123125783e-17; // Exponent all 0s: 1 00000000000 11111111111111111111 => 2148532223 var CLEAR_EXP_MASK = 0x800fffff>>>0; // asm type annotation @@ -113,8 +113,8 @@ function ldexp( frac, exp ) { // Extract the exponent from `frac` and add it to `exp`: exp += floatExp( frac ); - // Check for underflow/overflow... - if ( exp < MIN_SUBNORMAL_EXPONENT ) { + // Check for underflow/overflow (note: values on the interval `[2^-1075, 2^-1074)` may round to the smallest subnormal)... + if ( exp < MIN_SUBNORMAL_EXPONENT-1 ) { return copysign( 0.0, frac ); } if ( exp > MAX_EXPONENT ) { @@ -125,8 +125,8 @@ function ldexp( frac, exp ) { } // Check for a subnormal and scale accordingly to retain precision... if ( exp <= MAX_SUBNORMAL_EXPONENT ) { - exp += 52; - m = TWO52_INV; + exp += 54; + m = TWO54_INV; } else { m = 1.0; } diff --git a/lib/node_modules/@stdlib/math/base/special/ldexp/src/main.c b/lib/node_modules/@stdlib/math/base/special/ldexp/src/main.c index 6c209d16baad..482de7105f2e 100644 --- a/lib/node_modules/@stdlib/math/base/special/ldexp/src/main.c +++ b/lib/node_modules/@stdlib/math/base/special/ldexp/src/main.c @@ -32,8 +32,8 @@ #include "stdlib/constants/float64/exponent_bias.h" #include -// 1/(1<<52) = 1/(2**52) = 1/4503599627370496 -static const double TWO52_INV = 2.220446049250313e-16; +// 1/(1<<54) = 1/(2**54) = 1/18014398509481984 +static const double TWO54_INV = 5.551115123125783e-17; // Exponent all 0s: 1 00000000000 11111111111111111111 => 2148532223 static const uint32_t CLEAR_EXP_MASK = 2148532223; @@ -64,8 +64,8 @@ double stdlib_base_ldexp( const double frac, const int32_t exp ) { // Extract the exponent from `frac` and add it to `exp`: e += exp + stdlib_base_float64_exponent( y ); - // Check for underflow/overflow... - if ( e < STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT_SUBNORMAL ) { + // Check for underflow/overflow (note: values on the interval `[2^-1075, 2^-1074)` may round to the smallest subnormal)... + if ( e < STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT_SUBNORMAL-1 ) { return stdlib_base_copysign( 0.0, y ); } if ( e > STDLIB_CONSTANT_FLOAT64_MAX_BASE2_EXPONENT ) { @@ -76,8 +76,8 @@ double stdlib_base_ldexp( const double frac, const int32_t exp ) { } // Check for a subnormal and scale accordingly to retain precision... if ( e <= STDLIB_CONSTANT_FLOAT64_MAX_BASE2_EXPONENT_SUBNORMAL ) { - e += 52; - m = TWO52_INV; + e += 54; + m = TWO54_INV; } else { m = 1.0; } diff --git a/lib/node_modules/@stdlib/math/base/special/ldexp/test/test.js b/lib/node_modules/@stdlib/math/base/special/ldexp/test/test.js index 349f4a22bcd3..929072166e0c 100644 --- a/lib/node_modules/@stdlib/math/base/special/ldexp/test/test.js +++ b/lib/node_modules/@stdlib/math/base/special/ldexp/test/test.js @@ -113,6 +113,30 @@ tape( 'the function multiplies a number by an integer power of two (subnormals)' t.end(); }); +tape( 'the function rounds results on the interval `[2^-1075, 2^-1074)` to the nearest representable value', function test( t ) { + var v; + + v = ldexp( 0.75, -1074 ); + t.strictEqual( v, 5.0e-324, 'returns expected value' ); + + v = ldexp( -0.75, -1074 ); + t.strictEqual( v, -5.0e-324, 'returns expected value' ); + + v = ldexp( 3.0, -1076 ); + t.strictEqual( v, 5.0e-324, 'returns expected value' ); + + v = ldexp( 0.5000000000000001, -1074 ); + t.strictEqual( v, 5.0e-324, 'returns expected value' ); + + // Ties round to even: + v = ldexp( 0.5, -1074 ); + t.strictEqual( isPositiveZero( v ), true, 'returns expected value' ); + + v = ldexp( -0.5, -1074 ); + t.strictEqual( isNegativeZero( v ), true, 'returns expected value' ); + t.end(); +}); + tape( 'if provided a fraction equal to `+0`, the function returns `+0`', function test( t ) { var v = ldexp( 0.0, 10 ); t.strictEqual( isPositiveZero( v ), true, 'returns expected value' ); diff --git a/lib/node_modules/@stdlib/math/base/special/ldexp/test/test.native.js b/lib/node_modules/@stdlib/math/base/special/ldexp/test/test.native.js index bad8c91cc85d..a4e29769621b 100644 --- a/lib/node_modules/@stdlib/math/base/special/ldexp/test/test.native.js +++ b/lib/node_modules/@stdlib/math/base/special/ldexp/test/test.native.js @@ -122,6 +122,30 @@ tape( 'the function multiplies a number by an integer power of two (subnormals)' t.end(); }); +tape( 'the function rounds results on the interval `[2^-1075, 2^-1074)` to the nearest representable value', opts, function test( t ) { + var v; + + v = ldexp( 0.75, -1074 ); + t.strictEqual( v, 5.0e-324, 'returns expected value' ); + + v = ldexp( -0.75, -1074 ); + t.strictEqual( v, -5.0e-324, 'returns expected value' ); + + v = ldexp( 3.0, -1076 ); + t.strictEqual( v, 5.0e-324, 'returns expected value' ); + + v = ldexp( 0.5000000000000001, -1074 ); + t.strictEqual( v, 5.0e-324, 'returns expected value' ); + + // Ties round to even: + v = ldexp( 0.5, -1074 ); + t.strictEqual( isPositiveZero( v ), true, 'returns expected value' ); + + v = ldexp( -0.5, -1074 ); + t.strictEqual( isNegativeZero( v ), true, 'returns expected value' ); + t.end(); +}); + tape( 'if provided a fraction equal to `+0`, the function returns `+0`', opts, function test( t ) { var v = ldexp( 0.0, 10 ); t.strictEqual( isPositiveZero( v ), true, 'returns expected value' ); diff --git a/lib/node_modules/@stdlib/math/base/special/pow/test/test.js b/lib/node_modules/@stdlib/math/base/special/pow/test/test.js index 8e196a8addf1..af423e6f178a 100644 --- a/lib/node_modules/@stdlib/math/base/special/pow/test/test.js +++ b/lib/node_modules/@stdlib/math/base/special/pow/test/test.js @@ -389,7 +389,7 @@ tape( 'the function evaluates the exponential function (near underflow)', functi x = 1.9999999999999998; y = -1075; v = pow( x, y ); - t.strictEqual( v, 0.0, 'pow('+x+','+y+') returns 0' ); + t.strictEqual( v, 5.0e-324, 'pow('+x+','+y+') returns 5e-324' ); x = 1.9999999999999999; y = -1075; diff --git a/lib/node_modules/@stdlib/math/base/special/pow/test/test.native.js b/lib/node_modules/@stdlib/math/base/special/pow/test/test.native.js index 77da65e94d9b..a215d5de1adc 100644 --- a/lib/node_modules/@stdlib/math/base/special/pow/test/test.native.js +++ b/lib/node_modules/@stdlib/math/base/special/pow/test/test.native.js @@ -401,7 +401,7 @@ tape( 'the function evaluates the exponential function (near underflow)', opts, x = 1.9999999999999998; y = -1075; v = pow( x, y ); - t.strictEqual( v, 0.0, 'pow('+x+','+y+') returns 0' ); + t.strictEqual( v, 5.0e-324, 'pow('+x+','+y+') returns 5e-324' ); x = 1.9999999999999999; y = -1075;