From 65d9ac49ed35792c76321059545a4599483f9384 Mon Sep 17 00:00:00 2001 From: Karan Anand Date: Wed, 2 Apr 2025 01:29:09 -0700 Subject: [PATCH] fix: update hypotf to follow the IEEE 754-2019 standard --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown status: passed - task: lint_package_json status: na - task: lint_repl_help status: passed - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: passed - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: passed - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../math/base/special/hypotf/README.md | 2 +- .../math/base/special/hypotf/docs/repl.txt | 3 ++- .../math/base/special/hypotf/lib/main.js | 12 ++++++----- .../math/base/special/hypotf/src/main.c | 8 ++++--- .../math/base/special/hypotf/test/test.js | 14 ++++++++++++- .../base/special/hypotf/test/test.native.js | 21 +++++++++++++++++-- 6 files changed, 47 insertions(+), 13 deletions(-) diff --git a/lib/node_modules/@stdlib/math/base/special/hypotf/README.md b/lib/node_modules/@stdlib/math/base/special/hypotf/README.md index facf49747c08..69300a4cb5a0 100644 --- a/lib/node_modules/@stdlib/math/base/special/hypotf/README.md +++ b/lib/node_modules/@stdlib/math/base/special/hypotf/README.md @@ -52,7 +52,7 @@ h = hypotf( -0.0, -0.0 ); // returns +0.0 ``` -If either argument is `NaN`, the function returns `NaN`. +If either argument is `NaN` and the other argument is not `+-Infinity`, the function returns `NaN`. ```javascript var h = hypotf( NaN, 12.0 ); diff --git a/lib/node_modules/@stdlib/math/base/special/hypotf/docs/repl.txt b/lib/node_modules/@stdlib/math/base/special/hypotf/docs/repl.txt index 031bf6ee829f..4d3429ff2fb6 100644 --- a/lib/node_modules/@stdlib/math/base/special/hypotf/docs/repl.txt +++ b/lib/node_modules/@stdlib/math/base/special/hypotf/docs/repl.txt @@ -2,7 +2,8 @@ {{alias}}( x, y ) Computes the hypotenuse avoiding overflow and underflow (single-precision). - If either argument is `NaN`, the function returns `NaN`. + If either argument is `NaN` and the other argument is not `+-Infinity`, + the function returns `NaN`. Parameters ---------- diff --git a/lib/node_modules/@stdlib/math/base/special/hypotf/lib/main.js b/lib/node_modules/@stdlib/math/base/special/hypotf/lib/main.js index 2fe9cb97dc46..23df6341422c 100644 --- a/lib/node_modules/@stdlib/math/base/special/hypotf/lib/main.js +++ b/lib/node_modules/@stdlib/math/base/special/hypotf/lib/main.js @@ -24,7 +24,7 @@ var float64ToFloat32 = require( '@stdlib/number/float64/base/to-float32' ); var isnanf = require( '@stdlib/math/base/assert/is-nanf' ); var isInfinitef = require( '@stdlib/math/base/assert/is-infinitef' ); var PINF = require( '@stdlib/constants/float32/pinf' ); -var sqrt = require( '@stdlib/math/base/special/sqrt' ); +var sqrtf = require( '@stdlib/math/base/special/sqrtf' ); // MAIN // @@ -50,12 +50,14 @@ var sqrt = require( '@stdlib/math/base/special/sqrt' ); */ function hypotf( x, y ) { var tmp; - if ( isnanf( x ) || isnanf( y ) ) { - return NaN; - } + + // If one of the arguments is `+-infinity`, return `+infinity` even if the other argument is `NaN` (IEEE 754-2019)... if ( isInfinitef( x ) || isInfinitef( y ) ) { return PINF; } + if ( isnanf( x ) || isnanf( y ) ) { + return NaN; + } x = float64ToFloat32( x ); y = float64ToFloat32( y ); if ( x < 0.0 ) { @@ -73,7 +75,7 @@ function hypotf( x, y ) { return 0.0; } y = float64ToFloat32( y / x ); - return float64ToFloat32( x * float64ToFloat32( sqrt( float64ToFloat32( 1.0 + float64ToFloat32(y*y) ) ) ) ); // eslint-disable-line max-len + return float64ToFloat32( x * sqrtf( float64ToFloat32( 1.0 + float64ToFloat32(y*y) ) ) ); // eslint-disable-line max-len } diff --git a/lib/node_modules/@stdlib/math/base/special/hypotf/src/main.c b/lib/node_modules/@stdlib/math/base/special/hypotf/src/main.c index c8b34f785e09..1c6d5d87e79f 100644 --- a/lib/node_modules/@stdlib/math/base/special/hypotf/src/main.c +++ b/lib/node_modules/@stdlib/math/base/special/hypotf/src/main.c @@ -37,12 +37,14 @@ float stdlib_base_hypotf( const float x, const float y ) { float tmp; float a; float b; - if ( stdlib_base_is_nanf( x ) || stdlib_base_is_nanf( y ) ) { - return 0.0f / 0.0f; // NaN - } + + // If one of the arguments is `+-infinity`, return `+infinity` even if the other argument is `NaN` (IEEE 754-2019)... if ( stdlib_base_is_infinitef( x ) || stdlib_base_is_infinitef( y ) ) { return STDLIB_CONSTANT_FLOAT32_PINF; } + if ( stdlib_base_is_nanf( x ) || stdlib_base_is_nanf( y ) ) { + return 0.0f / 0.0f; // NaN + } a = x; b = y; if ( a < 0.0f ) { diff --git a/lib/node_modules/@stdlib/math/base/special/hypotf/test/test.js b/lib/node_modules/@stdlib/math/base/special/hypotf/test/test.js index 73ba408de3bf..ebda0c38fa29 100644 --- a/lib/node_modules/@stdlib/math/base/special/hypotf/test/test.js +++ b/lib/node_modules/@stdlib/math/base/special/hypotf/test/test.js @@ -73,10 +73,22 @@ tape( 'the function returns `+infinity` if either argument is `+-infinity`', fun h = hypotf( NINF, NINF ); t.strictEqual( h, PINF, 'returns expected value' ); + h = hypotf( NaN, PINF ); + t.strictEqual( h, PINF, 'returns expected value' ); + + h = hypotf( PINF, NaN ); + t.strictEqual( h, PINF, 'returns expected value' ); + + h = hypotf( NINF, NaN ); + t.strictEqual( h, PINF, 'returns expected value' ); + + h = hypotf( NaN, NINF ); + t.strictEqual( h, PINF, 'returns expected value' ); + t.end(); }); -tape( 'the function returns `NaN` if either argument is `NaN`', function test( t ) { +tape( 'the function returns `NaN` if either argument is `NaN` but not `+-infinity`', function test( t ) { var h; h = hypotf( NaN, 3.14 ); diff --git a/lib/node_modules/@stdlib/math/base/special/hypotf/test/test.native.js b/lib/node_modules/@stdlib/math/base/special/hypotf/test/test.native.js index aa9efd5a15b6..ec55231c142a 100644 --- a/lib/node_modules/@stdlib/math/base/special/hypotf/test/test.native.js +++ b/lib/node_modules/@stdlib/math/base/special/hypotf/test/test.native.js @@ -82,10 +82,22 @@ tape( 'the function returns `+infinity` if either argument is `+-infinity`', opt h = hypotf( NINF, NINF ); t.strictEqual( h, PINF, 'returns expected value' ); + h = hypotf( NaN, PINF ); + t.strictEqual( h, PINF, 'returns expected value' ); + + h = hypotf( PINF, NaN ); + t.strictEqual( h, PINF, 'returns expected value' ); + + h = hypotf( NINF, NaN ); + t.strictEqual( h, PINF, 'returns expected value' ); + + h = hypotf( NaN, NINF ); + t.strictEqual( h, PINF, 'returns expected value' ); + t.end(); }); -tape( 'the function returns `NaN` if either argument is `NaN`', opts, function test( t ) { +tape( 'the function returns `NaN` if either argument is `NaN` but not `+-infinity`', opts, function test( t ) { var h; h = hypotf( NaN, 3.14 ); @@ -145,6 +157,8 @@ tape( 'the function computes the hypotenuse', opts, function test( t ) { }); tape( 'the function computes the hypotenuse (canonical inputs)', opts, function test( t ) { + var delta; + var tol; var h; h = hypotf( 3.0, 4.0 ); @@ -153,8 +167,11 @@ tape( 'the function computes the hypotenuse (canonical inputs)', opts, function h = hypotf( 6.0, 8.0 ); t.strictEqual( h, 10.0, 'returns expected value' ); + // NOTE: the tolerance here is larger than for the JavaScript implementation due to compiler optimizations which may be performed resulting in result divergence. For discussion, see https://github.com/stdlib-js/stdlib/pull/2298#discussion_r1624765205 h = hypotf( 5.0, 12.0 ); - t.strictEqual( h, 13.0, 'returns expected value' ); + delta = absf( h - 13.0 ); + tol = EPS * absf( 13.0 ); + t.strictEqual( delta <= tol, true, 'within tolerance. h: '+h+'. Expected: 13.0. Delta: '+delta+'. Tol: '+tol+'.' ); t.end(); });