diff --git a/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/lib/accessors.js b/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/lib/accessors.js index b57d85fa41f6..86ec0881d749 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/lib/accessors.js +++ b/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/lib/accessors.js @@ -20,7 +20,9 @@ // MODULES // +var isnan = require( '@stdlib/math/base/assert/is-nan' ); var floor = require( '@stdlib/math/base/special/floor' ); +var gindexOfGreaterThanEqual = require( '@stdlib/blas/ext/base/gindex-of-greater-than-equal' ).ndarray; // MAIN // @@ -50,11 +52,13 @@ var floor = require( '@stdlib/math/base/special/floor' ); function gindexOfGreaterThanEqualSorted( N, searchElement, x, strideX, offsetX ) { var xbuf; var get; + var idx; var mid; var lo; var hi; var v1; var v2; + var v; // Cache reference to array data: xbuf = x.data; @@ -65,6 +69,10 @@ function gindexOfGreaterThanEqualSorted( N, searchElement, x, strideX, offsetX ) v1 = get( xbuf, offsetX ); v2 = get( xbuf, offsetX + ( ( N - 1 ) * strideX ) ); + // If either the first or last indexed element is NaN, we cannot determine the sort order, so fall back to a linear search... + if ( isnan( v1 ) || isnan( v2 ) ) { + return gindexOfGreaterThanEqual( N, searchElement, xbuf, strideX, offsetX ); + } // Descending order: elements which are greater than or equal to the search element form a prefix, so only the first indexed element needs to be checked... if ( v1 >= v2 ) { if ( searchElement <= v1 ) { @@ -77,7 +85,14 @@ function gindexOfGreaterThanEqualSorted( N, searchElement, x, strideX, offsetX ) hi = N; while ( lo < hi ) { mid = lo + floor( ( hi - lo ) / 2 ); - if ( searchElement <= get( xbuf, offsetX + ( mid * strideX ) ) ) { + v = get( xbuf, offsetX + ( mid * strideX ) ); + + // If we encounter a NaN, fall back to a linear search over the remaining candidate elements... + if ( isnan( v ) ) { + idx = gindexOfGreaterThanEqual( N-lo, searchElement, xbuf, strideX, offsetX + ( lo * strideX ) ); + return ( idx < 0 ) ? idx : idx + lo; + } + if ( searchElement <= v ) { hi = mid; } else { lo = mid + 1; diff --git a/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/lib/ndarray.js b/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/lib/ndarray.js index 6e7f6784d3d3..395e71d00ebe 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/lib/ndarray.js +++ b/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/lib/ndarray.js @@ -20,8 +20,10 @@ // MODULES // +var isnan = require( '@stdlib/math/base/assert/is-nan' ); var floor = require( '@stdlib/math/base/special/floor' ); var arraylike2object = require( '@stdlib/array/base/arraylike2object' ); +var gindexOfGreaterThanEqual = require( '@stdlib/blas/ext/base/gindex-of-greater-than-equal' ).ndarray; var accessors = require( './accessors.js' ); @@ -48,12 +50,14 @@ var accessors = require( './accessors.js' ); * // returns 1 */ function gindexOfGreaterThanEqualSorted( N, searchElement, x, strideX, offsetX ) { + var idx; var mid; var lo; var hi; var v1; var v2; var o; + var v; if ( N <= 0 ) { return -1; @@ -65,6 +69,10 @@ function gindexOfGreaterThanEqualSorted( N, searchElement, x, strideX, offsetX ) v1 = x[ offsetX ]; v2 = x[ offsetX + ( ( N - 1 ) * strideX ) ]; + // If either the first or last indexed element is NaN, we cannot determine the sort order, so fall back to a linear search... + if ( isnan( v1 ) || isnan( v2 ) ) { + return gindexOfGreaterThanEqual( N, searchElement, x, strideX, offsetX ); + } // Descending order: elements which are greater than or equal to the search element form a prefix, so only the first indexed element needs to be checked... if ( v1 >= v2 ) { if ( searchElement <= v1 ) { @@ -77,7 +85,14 @@ function gindexOfGreaterThanEqualSorted( N, searchElement, x, strideX, offsetX ) hi = N; while ( lo < hi ) { mid = lo + floor( ( hi - lo ) / 2 ); - if ( searchElement <= x[ offsetX + ( mid * strideX ) ] ) { + v = x[ offsetX + ( mid * strideX ) ]; + + // If we encounter a NaN, fall back to a linear search over the remaining candidate elements... + if ( isnan( v ) ) { + idx = gindexOfGreaterThanEqual( N-lo, searchElement, x, strideX, offsetX + ( lo * strideX ) ); + return ( idx < 0 ) ? idx : idx + lo; + } + if ( searchElement <= v ) { hi = mid; } else { lo = mid + 1; diff --git a/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/test/test.main.js b/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/test/test.main.js index 44b0bb595a12..34b8596a7ed8 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/test/test.main.js +++ b/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/test/test.main.js @@ -468,3 +468,57 @@ tape( 'the function supports view offsets (descending order)', function test( t t.end(); }); + +tape( 'the function supports input arrays containing `NaN` values', function test( t ) { + var actual; + var x; + + x = [ 1.0, NaN, 3.0, 4.0 ]; + + actual = gindexOfGreaterThanEqualSorted( x.length, 3.0, x, 1 ); + t.strictEqual( actual, 2, 'returns expected value' ); + + x = [ NaN, 1.0, 2.0, 3.0 ]; + + actual = gindexOfGreaterThanEqualSorted( x.length, 2.0, x, 1 ); + t.strictEqual( actual, 2, 'returns expected value' ); + + x = [ 1.0, 2.0, 3.0, NaN ]; + + actual = gindexOfGreaterThanEqualSorted( x.length, 2.0, x, 1 ); + t.strictEqual( actual, 1, 'returns expected value' ); + + x = [ 3.0, NaN, 2.0, 1.0 ]; + + actual = gindexOfGreaterThanEqualSorted( x.length, 3.0, x, 1 ); + t.strictEqual( actual, 0, 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports input arrays containing `NaN` values (accessors)', function test( t ) { + var actual; + var x; + + x = toAccessorArray( [ 1.0, NaN, 3.0, 4.0 ] ); + + actual = gindexOfGreaterThanEqualSorted( x.length, 3.0, x, 1 ); + t.strictEqual( actual, 2, 'returns expected value' ); + + x = toAccessorArray( [ NaN, 1.0, 2.0, 3.0 ] ); + + actual = gindexOfGreaterThanEqualSorted( x.length, 2.0, x, 1 ); + t.strictEqual( actual, 2, 'returns expected value' ); + + x = toAccessorArray( [ 1.0, 2.0, 3.0, NaN ] ); + + actual = gindexOfGreaterThanEqualSorted( x.length, 2.0, x, 1 ); + t.strictEqual( actual, 1, 'returns expected value' ); + + x = toAccessorArray( [ 3.0, NaN, 2.0, 1.0 ] ); + + actual = gindexOfGreaterThanEqualSorted( x.length, 3.0, x, 1 ); + t.strictEqual( actual, 0, 'returns expected value' ); + + t.end(); +}); diff --git a/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/test/test.ndarray.js b/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/test/test.ndarray.js index 174c386f2df8..2940b687f739 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/test/test.ndarray.js +++ b/lib/node_modules/@stdlib/blas/ext/base/gindex-of-greater-than-equal-sorted/test/test.ndarray.js @@ -517,3 +517,57 @@ tape( 'the function supports an `x` offset (descending order) (accessors)', func t.end(); }); + +tape( 'the function supports input arrays containing `NaN` values', function test( t ) { + var actual; + var x; + + x = [ 1.0, NaN, 3.0, 4.0 ]; + + actual = gindexOfGreaterThanEqualSorted( x.length, 3.0, x, 1, 0 ); + t.strictEqual( actual, 2, 'returns expected value' ); + + x = [ NaN, 1.0, 2.0, 3.0 ]; + + actual = gindexOfGreaterThanEqualSorted( x.length, 2.0, x, 1, 0 ); + t.strictEqual( actual, 2, 'returns expected value' ); + + x = [ 1.0, 2.0, 3.0, NaN ]; + + actual = gindexOfGreaterThanEqualSorted( x.length, 2.0, x, 1, 0 ); + t.strictEqual( actual, 1, 'returns expected value' ); + + x = [ 3.0, NaN, 2.0, 1.0 ]; + + actual = gindexOfGreaterThanEqualSorted( x.length, 3.0, x, 1, 0 ); + t.strictEqual( actual, 0, 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports input arrays containing `NaN` values (accessors)', function test( t ) { + var actual; + var x; + + x = toAccessorArray( [ 1.0, NaN, 3.0, 4.0 ] ); + + actual = gindexOfGreaterThanEqualSorted( x.length, 3.0, x, 1, 0 ); + t.strictEqual( actual, 2, 'returns expected value' ); + + x = toAccessorArray( [ NaN, 1.0, 2.0, 3.0 ] ); + + actual = gindexOfGreaterThanEqualSorted( x.length, 2.0, x, 1, 0 ); + t.strictEqual( actual, 2, 'returns expected value' ); + + x = toAccessorArray( [ 1.0, 2.0, 3.0, NaN ] ); + + actual = gindexOfGreaterThanEqualSorted( x.length, 2.0, x, 1, 0 ); + t.strictEqual( actual, 1, 'returns expected value' ); + + x = toAccessorArray( [ 3.0, NaN, 2.0, 1.0 ] ); + + actual = gindexOfGreaterThanEqualSorted( x.length, 3.0, x, 1, 0 ); + t.strictEqual( actual, 0, 'returns expected value' ); + + t.end(); +});