diff --git a/lib/node_modules/@stdlib/stats/incr/nanprod/README.md b/lib/node_modules/@stdlib/stats/incr/nanprod/README.md
new file mode 100644
index 000000000000..4c36094fdc6c
--- /dev/null
+++ b/lib/node_modules/@stdlib/stats/incr/nanprod/README.md
@@ -0,0 +1,212 @@
+
+
+# incrnanprod
+
+> Compute a product incrementally, ignoring the `NaN` values.
+
+
+
+The product is defined as
+
+
+
+```math
+p = \prod_{i=0}^{n-1} x_i
+```
+
+
+
+
+
+
+
+
+
+
+
+## Usage
+
+```javascript
+var incrnanprod = require( '@stdlib/stats/incr/nanprod' );
+```
+
+#### incrnanprod()
+
+Returns an accumulator `function` which incrementally computes a product, ignoring `NaN` values.
+
+```javascript
+var accumulator = incrnanprod();
+```
+
+#### accumulator( \[x] )
+
+If provided an input value `x`, the accumulator function returns an updated product. If not provided an input value `x`, the accumulator function returns the current product.
+
+```javascript
+var accumulator = incrnanprod();
+
+var prod = accumulator( 2.0 );
+// returns 2.0
+
+prod = accumulator( NaN );
+// returns 2.0
+
+prod = accumulator( 1.0 );
+// returns 2.0
+
+prod = accumulator( 3.0 );
+// returns 6.0
+
+prod = accumulator();
+// returns 6.0
+```
+
+Under certain conditions, overflow may be transient.
+
+```javascript
+// Large values:
+var x = 5.0e+300;
+var y = 1.0e+300;
+
+// Tiny value:
+var z = 2.0e-302;
+
+// Initialize an accumulator:
+var accumulator = incrnanprod();
+
+var prod = accumulator( x );
+// returns 5.0e+300
+
+// Transient overflow:
+prod = accumulator( y );
+// returns Infinity
+
+// Recover a finite result:
+prod = accumulator( z );
+// returns 1.0e+299
+```
+
+Similarly, under certain conditions, underflow may be transient.
+
+```javascript
+// Tiny values:
+var x = 4.0e-302;
+var y = 9.0e-303;
+
+// Large value:
+var z = 2.0e+300;
+
+// Initialize an accumulator:
+var accumulator = incrnanprod();
+
+var prod = accumulator( x );
+// returns 4.0e-302
+
+// Transient underflow:
+prod = accumulator( y );
+// returns 0.0
+
+// Recover a non-zero result:
+prod = accumulator( z );
+// returns 7.2e-304
+```
+
+
+
+
+
+
+
+## Notes
+
+- Input values are **not** type checked. If non-numeric inputs are possible, you are advised to type check and handle accordingly **before** passing the value to the accumulator function.
+- For long running accumulations or accumulations of either large or small numbers, care should be taken to prevent overflow and underflow. Note, however, that overflow/underflow may be transient, as the accumulator does not use a double-precision floating-point number to store an accumulated product. Instead, the accumulator splits an accumulated product into a normalized **fraction** and **exponent** and updates each component separately. Doing so guards against a loss in precision.
+
+
+
+
+
+
+
+## Examples
+
+
+
+```javascript
+var uniform = require( '@stdlib/random/base/uniform' );
+var bernoulli = require( '@stdlib/random/base/bernoulli' );
+var incrnanprod = require( '@stdlib/stats/incr/nanprod' );
+
+var accumulator;
+var v;
+var i;
+
+// Initialize an accumulator:
+accumulator = incrnanprod();
+
+// For each simulated value, update the product...
+for ( i = 0; i < 100; i++ ) {
+ v = ( bernoulli( 0.8 ) < 1 ) ? NaN : uniform( 0.0, 100.0 );
+ accumulator( v );
+}
+console.log( accumulator() );
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[@stdlib/stats/incr/mprod]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/stats/incr/mprod
+
+[@stdlib/stats/incr/sum]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/stats/incr/sum
+
+[@stdlib/stats/incr/summary]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/stats/incr/summary
+
+
+
+
+
+
diff --git a/lib/node_modules/@stdlib/stats/incr/nanprod/benchmark/benchmark.js b/lib/node_modules/@stdlib/stats/incr/nanprod/benchmark/benchmark.js
new file mode 100644
index 000000000000..df59160b6d53
--- /dev/null
+++ b/lib/node_modules/@stdlib/stats/incr/nanprod/benchmark/benchmark.js
@@ -0,0 +1,69 @@
+/**
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+'use strict';
+
+// MODULES //
+
+var bench = require( '@stdlib/bench' );
+var randu = require( '@stdlib/random/base/randu' );
+var pkg = require( './../package.json' ).name;
+var incrnanprod = require( './../lib' );
+
+
+// MAIN //
+
+bench( pkg, function benchmark( b ) {
+ var f;
+ var i;
+ b.tic();
+ for ( i = 0; i < b.iterations; i++ ) {
+ f = incrnanprod();
+ if ( typeof f !== 'function' ) {
+ b.fail( 'should return a function' );
+ }
+ }
+ b.toc();
+ if ( typeof f !== 'function' ) {
+ b.fail( 'should return a function' );
+ }
+ b.pass( 'benchmark finished' );
+ b.end();
+});
+
+bench( pkg+'::accumulator', function benchmark( b ) {
+ var acc;
+ var v;
+ var i;
+
+ acc = incrnanprod();
+
+ b.tic();
+ for ( i = 0; i < b.iterations; i++ ) {
+ v = acc( randu()*10.0 );
+ if ( v !== v ) {
+ b.fail( 'should not return NaN' );
+ }
+ }
+ b.toc();
+ if ( v !== v ) {
+ b.fail( 'should not return NaN' );
+ }
+ b.pass( 'benchmark finished' );
+ b.end();
+});
diff --git a/lib/node_modules/@stdlib/stats/incr/nanprod/docs/repl.txt b/lib/node_modules/@stdlib/stats/incr/nanprod/docs/repl.txt
new file mode 100644
index 000000000000..4094ae4e0b7b
--- /dev/null
+++ b/lib/node_modules/@stdlib/stats/incr/nanprod/docs/repl.txt
@@ -0,0 +1,38 @@
+
+{{alias}}()
+ Returns an accumulator function which incrementally computes a
+ product, ignoring `NaN` values.
+
+ If provided a value, the accumulator function returns an updated product. If
+ not provided a value, the accumulator function returns the current product.
+
+ For long running accumulations or accumulations of large numbers, care
+ should be taken to prevent overflow. Note, however, that overflow/underflow
+ may be transient, as the accumulator does not use a double-precision
+ floating-point number to store an accumulated product. Instead, the
+ accumulator splits an accumulated product into a normalized fraction and
+ exponent and updates each component separately. Doing so guards against a
+ loss in precision.
+
+ Returns
+ -------
+ acc: Function
+ Accumulator function.
+
+ Examples
+ --------
+ > var accumulator = {{alias}}();
+ > var v = accumulator()
+ null
+ > v = accumulator( 2.0 )
+ 2.0
+ > v = accumulator( NaN )
+ 2.0
+ > v = accumulator( -5.0 )
+ -10.0
+ > v = accumulator()
+ -10.0
+
+ See Also
+ --------
+
diff --git a/lib/node_modules/@stdlib/stats/incr/nanprod/docs/types/index.d.ts b/lib/node_modules/@stdlib/stats/incr/nanprod/docs/types/index.d.ts
new file mode 100644
index 000000000000..485eb63497e8
--- /dev/null
+++ b/lib/node_modules/@stdlib/stats/incr/nanprod/docs/types/index.d.ts
@@ -0,0 +1,67 @@
+/*
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+// TypeScript Version: 4.1
+
+///
+
+/**
+* If provided a value, returns an updated product; otherwise, returns the current product.
+*
+* ## Notes
+*
+* - If provided `NaN` or a value which, when used in computations, results in `NaN`, the accumulated value is `NaN` for all future invocations.
+* - For long running accumulations or accumulations of large numbers, care should be taken to prevent overflow. Note, however, that overflow/underflow may be transient, as the accumulator does not use a double-precision floating-point number to store an accumulated product. Instead, the accumulator splits an accumulated product into a normalized fraction and exponent and updates each component separately. Doing so guards against a loss in precision.
+*
+* @param x - value
+* @returns product
+*/
+type accumulator = ( x?: number ) => number | null;
+
+/**
+* Returns an accumulator function which incrementally computes a product, ignoring `NaN` values.
+*
+* @returns accumulator function
+*
+* @example
+* var accumulator = incrnanprod();
+*
+* var v = accumulator();
+* // returns null
+*
+* v = accumulator( 2.0 );
+* // returns 2.0
+*
+* v = accumulator( NaN );
+* // returns 2.0
+*
+* v = accumulator( 3.0 );
+* // returns 6.0
+*
+* v = accumulator( 4.0 );
+* // returns 24.0
+*
+* v = accumulator();
+* // returns 24.0
+*/
+declare function incrnanprod(): accumulator;
+
+
+// EXPORTS //
+
+export = incrnanprod;
diff --git a/lib/node_modules/@stdlib/stats/incr/nanprod/docs/types/test.ts b/lib/node_modules/@stdlib/stats/incr/nanprod/docs/types/test.ts
new file mode 100644
index 000000000000..cdcf930f33f4
--- /dev/null
+++ b/lib/node_modules/@stdlib/stats/incr/nanprod/docs/types/test.ts
@@ -0,0 +1,61 @@
+/*
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import incrnanprod = require( './index' );
+
+
+// TESTS //
+
+// The function returns an accumulator function...
+{
+ incrnanprod(); // $ExpectType accumulator
+}
+
+// The compiler throws an error if the function is provided arguments...
+{
+ incrnanprod( '5' ); // $ExpectError
+ incrnanprod( 5 ); // $ExpectError
+ incrnanprod( true ); // $ExpectError
+ incrnanprod( false ); // $ExpectError
+ incrnanprod( null ); // $ExpectError
+ incrnanprod( undefined ); // $ExpectError
+ incrnanprod( [] ); // $ExpectError
+ incrnanprod( {} ); // $ExpectError
+ incrnanprod( ( x: number ): number => x ); // $ExpectError
+}
+
+// The function returns an accumulator function which returns an accumulated result...
+{
+ const acc = incrnanprod();
+
+ acc(); // $ExpectType number | null
+ acc( 3.14 ); // $ExpectType number | null
+}
+
+// The compiler throws an error if the returned accumulator function is provided invalid arguments...
+{
+ const acc = incrnanprod();
+
+ acc( '5' ); // $ExpectError
+ acc( true ); // $ExpectError
+ acc( false ); // $ExpectError
+ acc( null ); // $ExpectError
+ acc( [] ); // $ExpectError
+ acc( {} ); // $ExpectError
+ acc( ( x: number ): number => x ); // $ExpectError
+}
diff --git a/lib/node_modules/@stdlib/stats/incr/nanprod/examples/index.js b/lib/node_modules/@stdlib/stats/incr/nanprod/examples/index.js
new file mode 100644
index 000000000000..de8bb216b1e4
--- /dev/null
+++ b/lib/node_modules/@stdlib/stats/incr/nanprod/examples/index.js
@@ -0,0 +1,40 @@
+/**
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+'use strict';
+
+var uniform = require( '@stdlib/random/base/uniform' );
+var bernoulli = require( '@stdlib/random/base/bernoulli' );
+var incrnanprod = require( './../lib' );
+
+var accumulator;
+var prod;
+var v;
+var i;
+
+// Initialize an accumulator:
+accumulator = incrnanprod();
+
+// For each simulated value, update the product...
+console.log( '\nValue\tProduct\n' );
+for ( i = 0; i < 100; i++ ) {
+ v = ( bernoulli( 0.8 ) < 1 ) ? NaN : uniform( 0.0, 100.0 );
+ prod = accumulator( v );
+ console.log( '%d\t%d', v.toFixed( 4 ), ( prod === null ) ? NaN : prod.toFixed( 4 ) );
+}
+console.log( '\nFinal product: %d\n', accumulator() );
diff --git a/lib/node_modules/@stdlib/stats/incr/nanprod/lib/index.js b/lib/node_modules/@stdlib/stats/incr/nanprod/lib/index.js
new file mode 100644
index 000000000000..b4f77629b6b1
--- /dev/null
+++ b/lib/node_modules/@stdlib/stats/incr/nanprod/lib/index.js
@@ -0,0 +1,54 @@
+/**
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+'use strict';
+
+/**
+* Compute a product incrementally, while ignoring `NaN` values.
+*
+* @module @stdlib/stats/incr/nanprod
+*
+* @example
+* var incrnanprod = require( '@stdlib/stats/incr/nanprod' );
+*
+* var accumulator = incrnanprod();
+*
+* var prod = accumulator();
+* // returns null
+*
+* prod = accumulator( 2.0 );
+* // returns 2.0
+*
+* prod = accumulator( NaN );
+* // returns 2.0
+*
+* prod = accumulator( -5.0 );
+* // returns -10.0
+*
+* prod = accumulator();
+* // returns -10.0
+*/
+
+// MODULES //
+
+var main = require( './main.js' );
+
+
+// EXPORTS //
+
+module.exports = main;
diff --git a/lib/node_modules/@stdlib/stats/incr/nanprod/lib/main.js b/lib/node_modules/@stdlib/stats/incr/nanprod/lib/main.js
new file mode 100644
index 000000000000..2dadeb2d6e49
--- /dev/null
+++ b/lib/node_modules/@stdlib/stats/incr/nanprod/lib/main.js
@@ -0,0 +1,81 @@
+/**
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+'use strict';
+
+// MODULES //
+
+var isnan = require( '@stdlib/math/base/assert/is-nan' );
+var incrprod = require( '@stdlib/stats/incr/prod' );
+
+/**
+* Returns an accumulator function which incrementally computes a product, while ignoring `NaN` values.
+*
+* ## Method
+*
+* To avoid overflow/underflow, we store the fractional and exponent parts of intermediate results separately. By keeping a normalized fraction, we prevent underflow/overflow of the fraction. Underflow of the exponent is impossible, as IEEE 754 floating-point exponents are integer values. Overflow of the exponent is possible, but highly unlikely. In the worst case, an intermediate exponent is greater than the minimum safe integer, and adding the exponent of an incoming value does not change the intermediate result. While incorrect, such behavior does not lead to exponent overflow.
+*
+* While intermediate results are largely immune to overflow and not subject to underflow, this does not mean that returned results will never be zero or infinite. In fact, zero (underflow) and infinite (overflow) results may be transient (i.e., infinity followed by a finite number).
+*
+* ## References
+*
+* - Ueberhuber, Christoph W. 1997. _Numerical Computation 1: Methods, Software, and Analysis_. Springer-Verlag Berlin Heidelberg. doi:[10.1007/978-3-642-59118-1](https://doi.org/10.1007/978-3-642-59118-1).
+*
+* @returns {Function} accumulator function
+*
+* @example
+* var accumulator = incrnanprod();
+*
+* var prod = accumulator();
+* // returns null
+*
+* prod = accumulator( 2.0 );
+* // returns 2.0
+*
+* prod = accumulator( NaN );
+* // returns 2.0
+*
+* prod = accumulator( -5.0 );
+* // returns -10.0
+*
+* prod = accumulator();
+* // returns -10.0
+*/
+function incrnanprod() {
+ var prod = incrprod();
+ return accumulator;
+
+ /**
+ * If provided a value, the accumulator function returns an updated product. If not provided a value, the accumulator function returns the current product.
+ *
+ * @private
+ * @param {number} [x] - new value
+ * @returns {(number|null)} product or null
+ */
+ function accumulator( x ) {
+ if ( arguments.length === 0 || isnan( x ) ) {
+ return prod();
+ }
+ return prod( x );
+ }
+}
+
+
+// EXPORTS //
+
+module.exports = incrnanprod;
diff --git a/lib/node_modules/@stdlib/stats/incr/nanprod/package.json b/lib/node_modules/@stdlib/stats/incr/nanprod/package.json
new file mode 100644
index 000000000000..11a9b71e8a52
--- /dev/null
+++ b/lib/node_modules/@stdlib/stats/incr/nanprod/package.json
@@ -0,0 +1,65 @@
+{
+ "name": "@stdlib/stats/incr/nanprod",
+ "version": "0.0.0",
+ "description": "Compute a product incrementally while ignoring `NaN` values.",
+ "license": "Apache-2.0",
+ "author": {
+ "name": "The Stdlib Authors",
+ "url": "https://github.com/stdlib-js/stdlib/graphs/contributors"
+ },
+ "contributors": [
+ {
+ "name": "The Stdlib Authors",
+ "url": "https://github.com/stdlib-js/stdlib/graphs/contributors"
+ }
+ ],
+ "main": "./lib",
+ "directories": {
+ "benchmark": "./benchmark",
+ "doc": "./docs",
+ "example": "./examples",
+ "lib": "./lib",
+ "test": "./test"
+ },
+ "types": "./docs/types",
+ "scripts": {},
+ "homepage": "https://github.com/stdlib-js/stdlib.git",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/stdlib-js/stdlib.git"
+ },
+ "bugs": {
+ "url": "https://github.com/stdlib-js/stdlib/issues"
+ },
+ "dependencies": {},
+ "devDependencies": {},
+ "engines": {
+ "node": ">=0.10.0",
+ "npm": ">2.7.0"
+ },
+ "os": [
+ "aix",
+ "darwin",
+ "freebsd",
+ "linux",
+ "macos",
+ "openbsd",
+ "sunos",
+ "win32",
+ "windows"
+ ],
+ "keywords": [
+ "stdlib",
+ "stdmath",
+ "statistics",
+ "stats",
+ "mathematics",
+ "math",
+ "multiplication",
+ "mult",
+ "product",
+ "prod",
+ "incremental",
+ "accumulator"
+ ]
+}
diff --git a/lib/node_modules/@stdlib/stats/incr/nanprod/test/test.js b/lib/node_modules/@stdlib/stats/incr/nanprod/test/test.js
new file mode 100644
index 000000000000..4c463da6b145
--- /dev/null
+++ b/lib/node_modules/@stdlib/stats/incr/nanprod/test/test.js
@@ -0,0 +1,326 @@
+/**
+* @license Apache-2.0
+*
+* Copyright (c) 2025 The Stdlib Authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+'use strict';
+
+// MODULES //
+
+var tape = require( 'tape' );
+var PINF = require( '@stdlib/constants/float64/pinf' );
+var NINF = require( '@stdlib/constants/float64/ninf' );
+var EPSILON = require( '@stdlib/constants/float64/eps' );
+var normal = require( '@stdlib/random/base/normal' );
+var ldexp = require( '@stdlib/math/base/special/ldexp' );
+var abs = require( '@stdlib/math/base/special/abs' );
+var isnan = require( '@stdlib/assert/is-nan' );
+var isEven = require( '@stdlib/math/base/assert/is-even' );
+var isNegativeZero = require( '@stdlib/math/base/assert/is-negative-zero' );
+var isPositiveZero = require( '@stdlib/math/base/assert/is-positive-zero' );
+var incrnanprod = require( './../lib' );
+
+
+// TESTS //
+
+tape( 'main export is a function', function test( t ) {
+ t.ok( true, __filename );
+ t.strictEqual( typeof incrnanprod, 'function', 'main export is a function' );
+ t.end();
+});
+
+tape( 'the function returns an accumulator function', function test( t ) {
+ t.strictEqual( typeof incrnanprod(), 'function', 'returns a function' );
+ t.end();
+});
+
+tape( 'the initial accumulator value is `null`', function test( t ) {
+ var acc = incrnanprod();
+ t.strictEqual( acc(), null, 'returns null' );
+ t.end();
+});
+
+tape( 'the accumulator function incrementally computes a product', function test( t ) {
+ var expected;
+ var actual;
+ var data;
+ var prod;
+ var acc;
+ var N;
+ var d;
+ var i;
+
+ data = [ 2.0, NaN, 3.0, 2.0, NaN, 4.0, 3.0, 4.0 ];
+ N = data.length;
+
+ expected = [];
+ actual = [];
+
+ acc = incrnanprod();
+
+ prod = 1.0;
+ for ( i = 0; i < N; i++ ) {
+ d = data[ i ];
+ if ( !isnan( d ) ) {
+ prod *= d;
+ }
+ expected[ i ] = prod;
+ actual[ i ] = acc( d );
+ }
+ t.deepEqual( actual, expected, 'returns expected value' );
+ t.end();
+});
+
+tape( 'if not provided an input value, the accumulator function returns the current product', function test( t ) {
+ var data;
+ var acc;
+ var i;
+
+ data = [ 2.0, NaN, 3.0, 1.0 ];
+
+ acc = incrnanprod();
+ for ( i = 0; i < data.length; i++ ) {
+ acc( data[ i ] );
+ }
+ t.strictEqual( acc(), 6.0, 'returns expected value' );
+ t.end();
+});
+
+tape( 'the accumulator function incrementally computes a product (special series)', function test( t ) {
+ var acc;
+ var x;
+ var i;
+
+ acc = incrnanprod();
+ x = 2;
+
+ // A series of reciprocals having an even number of terms is equal to unity...
+ for ( i = 0; i < 150; i++ ) {
+ if ( isEven( i ) ) {
+ acc( x );
+ } else {
+ acc( 1.0/x );
+ }
+ if ( i % 10 === 0 ) {
+ acc( NaN );
+ }
+ }
+ t.strictEqual( acc(), 1.0, 'returns expected value' );
+ t.end();
+});
+
+tape( 'the accumulator function can return a result which overflows', function test( t ) {
+ var acc = incrnanprod();
+
+ acc( 5.0e300 );
+ acc( NaN );
+ acc( 1.0e300 );
+
+ t.strictEqual( acc(), PINF, 'returns infinity' );
+ t.end();
+});
+
+tape( 'overflow may be transient', function test( t ) {
+ var expected;
+ var delta;
+ var tol;
+ var acc;
+ var x;
+ var y;
+ var z;
+
+ expected = ldexp( 0.01, 1000 );
+
+ acc = incrnanprod();
+
+ x = ldexp( 0.5, 1000 ); // ~5.4e300
+ y = ldexp( 0.1, 1000 ); // ~1.1e300
+ z = ldexp( 0.2, -1000 ); // ~1.87e-302
+
+ acc( x );
+ acc( NaN );
+ acc( y );
+ acc( z );
+
+ delta = abs( expected - acc() );
+ tol = EPSILON * abs( expected );
+
+ t.strictEqual( delta <= tol, true, 'within tolerance. Expected: '+expected+'. Actual: '+acc()+'. Delta: '+delta+'. Tol: '+tol+'.' );
+ t.end();
+});
+
+tape( 'the accumulator function can return a result which underflows', function test( t ) {
+ var acc = incrnanprod();
+
+ acc( 4.0e-302 );
+ acc( NaN );
+ acc( 9.0e-303 );
+
+ t.strictEqual( acc(), 0.0, 'returns 0' );
+ t.end();
+});
+
+tape( 'underflow may be transient', function test( t ) {
+ var expected;
+ var delta;
+ var tol;
+ var acc;
+ var x;
+ var y;
+ var z;
+
+ expected = ldexp( 0.01, -1000 );
+
+ acc = incrnanprod();
+
+ x = ldexp( 0.5, -1000 ); // ~4.67e-302
+ y = ldexp( 0.1, -1000 ); // ~9.33e-303
+ z = ldexp( 0.2, 1000 ); // ~2.14e300
+
+ acc( x );
+ acc( NaN );
+ acc( y );
+
+ t.strictEqual( acc(), 0.0, 'returns 0 due to underflow' );
+
+ acc( z );
+
+ delta = abs( acc() - expected );
+ tol = EPSILON * abs( expected );
+
+ t.strictEqual( delta <= tol, true, 'within tolerance. Expected: '+expected+'. Actual: '+acc()+'. Delta: '+delta+'. Tol: '+tol+'.' );
+ t.end();
+});
+
+tape( 'if provided `+infinity`, the accumulator function always returns `NaN` if also provided a `0`', function test( t ) {
+ var acc;
+ var p;
+ var i;
+
+ acc = incrnanprod();
+ acc( 5.0 );
+
+ t.strictEqual( acc(), 5.0, 'returns expected value' );
+
+ acc( PINF );
+ t.strictEqual( acc(), PINF, 'returns +infinity' );
+
+ acc( NaN );
+ t.strictEqual( acc(), PINF, 'ignores NaN and retains +infinity' );
+
+ acc( 0.0 );
+ t.strictEqual( isnan( acc() ), true, 'returns NaN' );
+
+ for ( i = 0; i < 1000; i++ ) {
+ p = acc( i + 1 );
+ t.strictEqual( isnan( p ), true, 'returns NaN' );
+ }
+ t.end();
+});
+
+tape( 'if provided `-infinity`, the accumulator function always returns `NaN` if also provided a `0`', function test( t ) {
+ var acc;
+ var p;
+ var i;
+
+ acc = incrnanprod();
+ acc( 5.0 );
+
+ t.strictEqual( acc(), 5.0, 'returns expected value' );
+
+ acc( NINF );
+ t.strictEqual( acc(), NINF, 'returns -infinity' );
+
+ acc( NaN );
+ t.strictEqual( acc(), NINF, 'ignores NaN and retains -infinity' );
+
+ acc( 0.0 );
+ t.strictEqual( isnan( acc() ), true, 'returns NaN' );
+
+ for ( i = 0; i < 1000; i++ ) {
+ p = acc( i+1 );
+ t.strictEqual( isnan( p ), true, 'returns NaN' );
+ }
+ t.end();
+});
+
+tape( 'if provided `0`, the accumulator function always returns `0` (no +-infinity)', function test( t ) {
+ var acc;
+ var p;
+ var i;
+
+ acc = incrnanprod();
+ acc( 5.0 );
+
+ t.strictEqual( acc(), 5.0, 'returns expected value' );
+
+ acc( NaN );
+ t.strictEqual( acc(), 5.0, 'ignores NaN and retains product' );
+
+ acc( 0.0 );
+ t.strictEqual( acc(), 0.0, 'returns 0.0' );
+
+ for ( i = 0; i < 1000; i++ ) {
+ p = acc( i+1 );
+ t.strictEqual( p, 0.0, 'returns 0.0' );
+ }
+ t.end();
+});
+
+tape( 'the accumulator function returns a signed zero', function test( t ) {
+ var acc;
+ var p;
+ var i;
+
+ acc = incrnanprod();
+ acc( -0.0 );
+ for ( i = 0; i < 100; i++ ) {
+ acc( NaN );
+ p = acc( -0.0 );
+ if ( isEven( i ) ) {
+ t.strictEqual( isPositiveZero( p ), true, 'returns +0' );
+ } else {
+ t.strictEqual( isNegativeZero( p ), true, 'returns -0' );
+ }
+ }
+ t.end();
+});
+
+tape( 'if provided values of normal magnitude (i.e., far away from the extremes), the accumulator function returns results matching naive multiplication', function test( t ) {
+ var randn;
+ var prod;
+ var acc;
+ var r;
+ var i;
+
+ acc = incrnanprod();
+
+ randn = normal.factory( 50.0, 10.0, {
+ 'seed': 1234
+ });
+
+ prod = 1.0;
+ for ( i = 0; i < 1000; i++ ) {
+ r = randn();
+ if ( isnan( r ) ) {
+ continue;
+ }
+ acc( r );
+ prod *= r;
+ }
+ t.strictEqual( acc(), prod, 'equals native multiplication' );
+ t.end();
+});