From 715168da8912d9ef8fa7c7ec1ca25e39795bef30 Mon Sep 17 00:00:00 2001 From: Shubham Date: Thu, 26 Feb 2026 21:59:13 +0530 Subject: [PATCH] feat: add implementation of `stats/incr/nanmprod` --- 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: passed - task: lint_repl_help status: passed - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: passed - task: lint_javascript_tests status: passed - task: lint_javascript_benchmarks status: passed - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - 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: passed - task: lint_typescript_tests status: passed - task: lint_license_headers status: passed --- --- .../@stdlib/stats/incr/nanmprod/README.md | 202 ++++++++++++++++++ .../incr/nanmprod/benchmark/benchmark.js | 70 ++++++ .../docs/img/equation_moving_product.svg | 30 +++ .../@stdlib/stats/incr/nanmprod/docs/repl.txt | 55 +++++ .../stats/incr/nanmprod/docs/types/index.d.ts | 73 +++++++ .../stats/incr/nanmprod/docs/types/test.ts | 66 ++++++ .../stats/incr/nanmprod/examples/index.js | 38 ++++ .../@stdlib/stats/incr/nanmprod/lib/index.js | 57 +++++ .../@stdlib/stats/incr/nanmprod/lib/main.js | 90 ++++++++ .../@stdlib/stats/incr/nanmprod/package.json | 69 ++++++ .../@stdlib/stats/incr/nanmprod/test/test.js | 111 ++++++++++ 11 files changed, 861 insertions(+) create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmprod/README.md create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmprod/benchmark/benchmark.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmprod/docs/img/equation_moving_product.svg create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmprod/docs/repl.txt create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmprod/docs/types/index.d.ts create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmprod/docs/types/test.ts create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmprod/examples/index.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmprod/lib/index.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmprod/lib/main.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmprod/package.json create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmprod/test/test.js diff --git a/lib/node_modules/@stdlib/stats/incr/nanmprod/README.md b/lib/node_modules/@stdlib/stats/incr/nanmprod/README.md new file mode 100644 index 000000000000..fc766f2f0f50 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmprod/README.md @@ -0,0 +1,202 @@ + + +# incrnanmprod + +> Compute a moving product incrementally, ignoring `NaN` values. + +
+ +For a window of size `W`, the moving product is defined as + + + +```math +\prod_{i=0}^{W-1} x_i +``` + + + + + +
+ + + +
+ +## Usage + +```javascript +var incrnanmprod = require( '@stdlib/stats/incr/nanmprod' ); +``` + +#### incrnanmprod( window ) + +Returns an accumulator `function` which incrementally computes a moving product, ignoring `NaN` values. The `window` parameter defines the number of values over which to compute the moving product. + +```javascript +var accumulator = incrnanmprod( 3 ); +``` + +#### 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 = incrnanmprod( 3 ); + +var p = accumulator(); +// returns null + +// Fill the window... +p = accumulator( 2.0 ); // [2.0] +// returns 2.0 + +p = accumulator( NaN ); // [2.0] (NaN ignored) +// returns 2.0 + +p = accumulator( 3.0 ); // [2.0, 3.0] +// returns 6.0 + +// Window begins sliding... +p = accumulator( 5.0 ); // [2.0, 3.0, 5.0] +// returns 30.0 + +p = accumulator( NaN ); // [2.0, 3.0, 5.0] (NaN ignored) +// returns 30.0 + +p = accumulator( 7.0 ); // [3.0, 5.0, 7.0] +// returns 105.0 + +p = accumulator(); +// returns 105.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 = incrnanmprod( 3 ); + +var p = accumulator( x ); +// returns 5.0e+300 + +// Transient overflow: +p = accumulator( y ); +// returns Infinity + +// Recover a finite result: +p = 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 = incrnanmprod( 3 ); + +var p = accumulator( x ); +// returns 4.0e-302 + +// Transient underflow: +p = accumulator( y ); +// returns 0.0 + +// Recover a non-zero result: +p = 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. +- `NaN` values are ignored and do not affect the computed moving product. +- As `W` values are needed to fill the window buffer, the first `W-1` returned values are calculated from smaller sample sizes. Until the window is full, each returned value is calculated from all provided values. +- For large accumulation windows 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 randu = require( '@stdlib/random/base/randu' ); +var incrnanmprod = require( '@stdlib/stats/incr/nanmprod' ); + +// Initialize an accumulator: +var accumulator = incrnanmprod( 5 ); + +// For each simulated datum, update the moving product... +var i; +for ( i = 0; i < 100; i++ ) { + accumulator( ( randu()*10.0 ) - 5.0 ); +} +console.log( accumulator() ); +``` + +
+ + + + + + + + + + + + diff --git a/lib/node_modules/@stdlib/stats/incr/nanmprod/benchmark/benchmark.js b/lib/node_modules/@stdlib/stats/incr/nanmprod/benchmark/benchmark.js new file mode 100644 index 000000000000..b1554f4c6425 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmprod/benchmark/benchmark.js @@ -0,0 +1,70 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 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 format = require( '@stdlib/string/format' ); +var pkg = require( './../package.json' ).name; +var incrnanmprod = require( './../lib' ); + + +// MAIN // + +bench( pkg, function benchmark( b ) { + var f; + var i; + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + f = incrnanmprod( (i%5)+1 ); + 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( format( '%s::accumulator', pkg ), function benchmark( b ) { + var acc; + var v; + var i; + + acc = incrnanmprod( 5 ); + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + v = acc( randu() ); + 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/nanmprod/docs/img/equation_moving_product.svg b/lib/node_modules/@stdlib/stats/incr/nanmprod/docs/img/equation_moving_product.svg new file mode 100644 index 000000000000..6805f02488ba --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmprod/docs/img/equation_moving_product.svg @@ -0,0 +1,30 @@ + +product Underscript i equals 0 Overscript upper W minus 1 Endscripts x Subscript i + + + \ No newline at end of file diff --git a/lib/node_modules/@stdlib/stats/incr/nanmprod/docs/repl.txt b/lib/node_modules/@stdlib/stats/incr/nanmprod/docs/repl.txt new file mode 100644 index 000000000000..e39291a99b47 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmprod/docs/repl.txt @@ -0,0 +1,55 @@ + +{{alias}}( W ) + Returns an accumulator function which incrementally computes a moving + product, ignoring `NaN` values. + + The `W` parameter defines the number of values over which to compute the + moving product. + + If provided a value, the accumulator function returns an updated moving + product. If not provided a value, the accumulator function returns the + current moving product. + + `NaN` values are ignored and do not affect the computed moving product. + + As `W` values are needed to fill the window buffer, the first `W-1` returned + values are calculated from smaller sample sizes. Until the window is full, + each returned value is calculated from all provided values. + + For accumulations over large windows 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. + + Parameters + ---------- + W: integer + Window size. + + Returns + ------- + acc: Function + Accumulator function. + + Examples + -------- + > var accumulator = {{alias}}( 3 ); + > var p = accumulator() + null + > p = accumulator( 2.0 ) + 2.0 + > p = accumulator( NaN ) + 2.0 + > p = accumulator( 3.0 ) + 6.0 + > p = accumulator( 5.0 ) + 30.0 + > p = accumulator() + 30.0 + + See Also + -------- + diff --git a/lib/node_modules/@stdlib/stats/incr/nanmprod/docs/types/index.d.ts b/lib/node_modules/@stdlib/stats/incr/nanmprod/docs/types/index.d.ts new file mode 100644 index 000000000000..bcc95c53ac71 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmprod/docs/types/index.d.ts @@ -0,0 +1,73 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2026 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. +* +* @param x - value +* @returns product +*/ +type accumulator = ( x?: number ) => number | null; + +/** +* Returns an accumulator function which incrementally computes a moving product, ignoring `NaN` values. +* +* ## Notes +* +* - The `W` parameter defines the number of values over which to compute the moving product. +* - As `W` values are needed to fill the window buffer, the first `W-1` returned values are calculated from smaller sample sizes. Until the window is full, each returned value is calculated from all provided values. +* +* @param W - window size +* @returns accumulator function +* +* @example +* var nanmprod = require( '@stdlib/stats/incr/nanmprod' ); +* +* var accumulator = incrnanmprod( 3 ); +* +* var p = accumulator(); +* // returns null +* +* p = accumulator( 2.0 ); +* // returns 2.0 +* +* p = accumulator( NaN ); +* // returns 2.0 +* +* p = accumulator( 3.0 ); +* // returns 6.0 +* +* p = accumulator( 5.0 ); +* // returns 30.0 +* +* p = accumulator( 5.0 ); +* // returns 75.0 +* +* p = accumulator(); +* // returns 75.0 +*/ +declare function incrnanmprod( W: number ): accumulator; + + +// EXPORTS // + +export = incrnanmprod; diff --git a/lib/node_modules/@stdlib/stats/incr/nanmprod/docs/types/test.ts b/lib/node_modules/@stdlib/stats/incr/nanmprod/docs/types/test.ts new file mode 100644 index 000000000000..f572fb82307b --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmprod/docs/types/test.ts @@ -0,0 +1,66 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2026 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 incrnanmprod = require( './index' ); + + +// TESTS // + +// The function returns an accumulator function... +{ + incrnanmprod( 3 ); // $ExpectType accumulator +} + +// The compiler throws an error if the function is provided an argument which is not a number... +{ + incrnanmprod( '5' ); // $ExpectError + incrnanmprod( true ); // $ExpectError + incrnanmprod( false ); // $ExpectError + incrnanmprod( null ); // $ExpectError + incrnanmprod( undefined ); // $ExpectError + incrnanmprod( [] ); // $ExpectError + incrnanmprod( {} ); // $ExpectError + incrnanmprod( ( x: number ): number => x ); // $ExpectError +} + +// The compiler throws an error if the function is provided an invalid number of arguments... +{ + incrnanmprod(); // $ExpectError + incrnanmprod( 2, 3 ); // $ExpectError +} + +// The function returns an accumulator function which returns an accumulated result... +{ + const acc = incrnanmprod( 3 ); + + 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 = incrnanmprod( 3 ); + + 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/nanmprod/examples/index.js b/lib/node_modules/@stdlib/stats/incr/nanmprod/examples/index.js new file mode 100644 index 000000000000..7a8f99414237 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmprod/examples/index.js @@ -0,0 +1,38 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 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 randu = require( '@stdlib/random/base/randu' ); +var incrnanmprod = require( './../lib' ); + +var accumulator; +var p; +var v; +var i; + +// Initialize an accumulator: +accumulator = incrnanmprod( 5 ); + +// For each simulated datum, update the moving product... +console.log( '\nValue\tProduct\n' ); +for ( i = 0; i < 100; i++ ) { + v = ( randu()*10.0 ) - 5.0; + p = accumulator( v ); + console.log( '%d\t%d', v.toFixed( 3 ), p.toFixed( 3 ) ); +} diff --git a/lib/node_modules/@stdlib/stats/incr/nanmprod/lib/index.js b/lib/node_modules/@stdlib/stats/incr/nanmprod/lib/index.js new file mode 100644 index 000000000000..35f5bfed3722 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmprod/lib/index.js @@ -0,0 +1,57 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 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 moving product incrementally, ignoring `NaN` values. +* +* @module @stdlib/stats/incr/nanmprod +* +* @example +* var incrnanmprod = require( '@stdlib/stats/incr/nanmprod' ); +* +* var accumulator = incrnanmprod( 3 ); +* +* var p = accumulator(); +* // returns null +* +* p = accumulator( 2.0 ); +* // returns 2.0 +* +* p = accumulator( NaN ); +* // returns 2.0 +* +* p = accumulator( 3.0 ); +* // returns 6.0 +* +* p = accumulator( 5.0 ); +* // returns 30.0 +* +* p = accumulator(); +* // returns 30.0 +*/ + +// MODULES // + +var main = require( './main.js' ); + + +// EXPORTS // + +module.exports = main; diff --git a/lib/node_modules/@stdlib/stats/incr/nanmprod/lib/main.js b/lib/node_modules/@stdlib/stats/incr/nanmprod/lib/main.js new file mode 100644 index 000000000000..40c2f3465ef9 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmprod/lib/main.js @@ -0,0 +1,90 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 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 incrmprod = require( '@stdlib/stats/incr/mprod' ); + + +// MAIN // + +/** +* Returns an accumulator function which incrementally computes a moving product, 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). +* +* @param {PositiveInteger} W - window size +* @returns {Function} accumulator function +* +* @example +* var nanmprod = require( '@stdlib/stats/incr/nanmprod' ); +* +* var accumulator = incrnanmprod( 3 ); +* +* var p = accumulator(); +* // returns null +* +* p = accumulator( 2.0 ); +* // returns 2.0 +* +* p = accumulator( NaN ); +* // returns 2.0 +* +* p = accumulator( 3.0 ); +* // returns 6.0 +* +* p = accumulator( 5.0 ); +* // returns 30.0 +* +* p = accumulator(); +* // returns 30.0 +*/ +function incrnanmprod( W ) { + var prod = incrmprod( W ); + return accumulator; + + /** + * If provided a value, the accumulator function returns an updated prod. If not provided a value, the accumulator function returns the current prod. + * + * @private + * @param {number} [x] - input value + * @returns {(number|null)} prod or null + */ + function accumulator( x ) { + if ( arguments.length === 0 || isnan( x ) ) { + return prod(); + } + return prod( x ); + } +} + + +// EXPORTS // + +module.exports = incrnanmprod; diff --git a/lib/node_modules/@stdlib/stats/incr/nanmprod/package.json b/lib/node_modules/@stdlib/stats/incr/nanmprod/package.json new file mode 100644 index 000000000000..7cd88893fa18 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmprod/package.json @@ -0,0 +1,69 @@ +{ + "name": "@stdlib/stats/incr/nanmprod", + "version": "0.0.0", + "description": "Compute a moving product incrementally, 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", + "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", + "product", + "prod", + "incremental", + "accumulator", + "moving prod", + "moving product", + "sliding window", + "sliding", + "window", + "moving" + ] +} diff --git a/lib/node_modules/@stdlib/stats/incr/nanmprod/test/test.js b/lib/node_modules/@stdlib/stats/incr/nanmprod/test/test.js new file mode 100644 index 000000000000..9a9a891d40e2 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmprod/test/test.js @@ -0,0 +1,111 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 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 incrnanmprod = require( './../lib' ); + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof incrnanmprod, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function returns an accumulator function', function test( t ) { + t.strictEqual( typeof incrnanmprod( 3 ), 'function', 'returns expected value' ); + t.end(); +}); + +tape( 'the initial accumulated value is `null`', function test( t ) { + var acc = incrnanmprod( 3 ); + t.strictEqual( acc(), null, 'returns expected value' ); + t.end(); +}); + +tape( 'the function throws an error if not provided a positive integer', function test( t ) { + var values; + var i; + + values = [ + '5', + -5.0, + 0.0, + 3.14, + true, + null, + void 0, + NaN, + [], + {}, + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + incrnanmprod( value ); + }; + } +}); + +tape( 'the accumulator function computes a moving product incrementally', function test( t ) { + var expected; + var actual; + var data; + var acc; + var N; + var i; + + data = [ 2.0, 3.0, NaN, 4.0, NaN, 4.0 ]; + N = data.length; + + acc = incrnanmprod( 3 ); + + actual = []; + for ( i = 0; i < N; i++ ) { + actual.push( acc( data[ i ] ) ); + } + expected = [ 2.0, 6.0, 6.0, 24.0, 24.0, 48.0 ]; + + t.deepEqual( actual, expected, 'returns expected incremental results' ); + 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, -5.0, 3.0, 5.0 ]; + acc = incrnanmprod( 3 ); + for ( i = 0; i < data.length; i++ ) { + acc( data[ i ] ); + } + t.strictEqual( acc(), -75.0, 'returns expected value' ); + t.end(); +});