Skip to content

Commit 56d02de

Browse files
committed
Add pkg to incrementally compute a moving product
1 parent f91f6ab commit 56d02de

File tree

8 files changed

+767
-0
lines changed

8 files changed

+767
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<!--
2+
3+
@license Apache-2.0
4+
5+
Copyright (c) 2018 The Stdlib Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
19+
-->
20+
21+
# incrmprod
22+
23+
> Compute a moving product incrementally.
24+
25+
<section class="usage">
26+
27+
## Usage
28+
29+
```javascript
30+
var incrmprod = require( '@stdlib/stats/incr/mprod' );
31+
```
32+
33+
#### incrmprod( window )
34+
35+
Returns an accumulator `function` which incrementally computes a moving product. The `window` parameter defines the number of values over which to compute the moving product.
36+
37+
```javascript
38+
var accumulator = incrmprod( 3 );
39+
```
40+
41+
#### accumulator( \[x] )
42+
43+
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.
44+
45+
```javascript
46+
var accumulator = incrmprod( 3 );
47+
48+
var p = accumulator();
49+
// returns null
50+
51+
// Fill the window...
52+
p = accumulator( 2.0 ); // [2.0]
53+
// returns 2.0
54+
55+
p = accumulator( 1.0 ); // [2.0, 1.0]
56+
// returns 2.0
57+
58+
p = accumulator( 3.0 ); // [2.0, 1.0, 3.0]
59+
// returns 6.0
60+
61+
// Window begins sliding...
62+
p = accumulator( -7.0 ); // [1.0, 3.0, -7.0]
63+
// returns -21.0
64+
65+
p = accumulator( -5.0 ); // [3.0, -7.0, -5.0]
66+
// returns 105.0
67+
68+
p = accumulator();
69+
// returns 105.0
70+
```
71+
72+
</section>
73+
74+
<!-- /.usage -->
75+
76+
<section class="notes">
77+
78+
## Notes
79+
80+
- Input values are **not** type checked. If provided `NaN` or a value which, when used in computations, results in `NaN`, the accumulated value is `NaN` for **at least** `W-1` future invocations. If non-numeric inputs are possible, you are advised to type check and handle accordingly **before** passing the value to the accumulator function.
81+
- The first `W-1` returned products will have less statistical support than subsequent products, as `W` values are needed to fill the window buffer. Until the window is full, the returned product equals the product of all provided values.
82+
- 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.
83+
84+
</section>
85+
86+
<!-- /.notes -->
87+
88+
<section class="examples">
89+
90+
## Examples
91+
92+
<!-- eslint no-undef: "error" -->
93+
94+
```javascript
95+
var randu = require( '@stdlib/random/base/randu' );
96+
var incrmprod = require( '@stdlib/stats/incr/mprod' );
97+
98+
var accumulator;
99+
var v;
100+
var i;
101+
102+
// Initialize an accumulator:
103+
accumulator = incrmprod( 5 );
104+
105+
// For each simulated datum, update the moving product...
106+
for ( i = 0; i < 100; i++ ) {
107+
v = ( randu()*10.0 ) - 5.0;
108+
accumulator( v );
109+
}
110+
console.log( accumulator() );
111+
```
112+
113+
</section>
114+
115+
<!-- /.examples -->
116+
117+
<section class="links">
118+
119+
</section>
120+
121+
<!-- /.links -->
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2018 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var bench = require( '@stdlib/bench' );
24+
var randu = require( '@stdlib/random/base/randu' );
25+
var pkg = require( './../package.json' ).name;
26+
var incrmprod = require( './../lib' );
27+
28+
29+
// MAIN //
30+
31+
bench( pkg, function benchmark( b ) {
32+
var f;
33+
var i;
34+
b.tic();
35+
for ( i = 0; i < b.iterations; i++ ) {
36+
f = incrmprod( (i%5)+1 );
37+
if ( typeof f !== 'function' ) {
38+
b.fail( 'should return a function' );
39+
}
40+
}
41+
b.toc();
42+
if ( typeof f !== 'function' ) {
43+
b.fail( 'should return a function' );
44+
}
45+
b.pass( 'benchmark finished' );
46+
b.end();
47+
});
48+
49+
bench( pkg+'::accumulator', function benchmark( b ) {
50+
var acc;
51+
var v;
52+
var i;
53+
54+
acc = incrmprod( 5 );
55+
56+
b.tic();
57+
for ( i = 0; i < b.iterations; i++ ) {
58+
v = acc( randu() );
59+
if ( v !== v ) {
60+
b.fail( 'should not return NaN' );
61+
}
62+
}
63+
b.toc();
64+
if ( v !== v ) {
65+
b.fail( 'should not return NaN' );
66+
}
67+
b.pass( 'benchmark finished' );
68+
b.end();
69+
});
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
2+
{{alias}}( window )
3+
Returns an accumulator function which incrementally computes a moving
4+
product.
5+
6+
The `window` parameter defines the number of values over which to compute
7+
the moving product.
8+
9+
If provided a value, the accumulator function returns an updated moving
10+
product. If not provided a value, the accumulator function returns the
11+
current moving product.
12+
13+
The first `W-1` returned products will have less statistical support than
14+
subsequent products, as `W` values are needed to fill the window buffer.
15+
Until the window is full, the returned product equals the product of all
16+
provided values.
17+
18+
For accumulations over large windows or accumulations of large numbers, care
19+
should be taken to prevent overflow. Note, however, that overflow/underflow
20+
may be transient, as the accumulator does not use a double-precision
21+
floating-point number to store an accumulated product. Instead, the
22+
accumulator splits an accumulated product into a normalized fraction and
23+
exponent and updates each component separately. Doing so guards against a
24+
loss in precision.
25+
26+
Parameters
27+
----------
28+
window: integer
29+
Window size.
30+
31+
Returns
32+
-------
33+
acc: Function
34+
Accumulator function.
35+
36+
Examples
37+
--------
38+
> var accumulator = {{alias}}( 3 );
39+
> var p = accumulator()
40+
null
41+
> p = accumulator( 2.0 )
42+
2.0
43+
> p = accumulator( -5.0 )
44+
-10.0
45+
> p = accumulator( 3.0 )
46+
-30.0
47+
> p = accumulator( 5.0 )
48+
-75.0
49+
> p = accumulator()
50+
-75.0
51+
52+
See Also
53+
--------
54+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2018 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
var randu = require( '@stdlib/random/base/randu' );
22+
var incrmprod = require( './../lib' );
23+
24+
var accumulator;
25+
var p;
26+
var v;
27+
var i;
28+
29+
// Initialize an accumulator:
30+
accumulator = incrmprod( 5 );
31+
32+
// For each simulated datum, update the moving product...
33+
console.log( '\nValue\tProduct\n' );
34+
for ( i = 0; i < 100; i++ ) {
35+
v = ( randu()*10.0 ) - 5.0;
36+
p = accumulator( v );
37+
console.log( '%d\t%d', v.toFixed( 3 ), p.toFixed( 3 ) );
38+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2018 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
/**
22+
* Compute a moving product incrementally.
23+
*
24+
* @module @stdlib/stats/incr/mprod
25+
*
26+
* @example
27+
* var incrmprod = require( '@stdlib/stats/incr/mprod' );
28+
*
29+
* var accumulator = incrmprod( 3 );
30+
*
31+
* var p = accumulator();
32+
* // returns null
33+
*
34+
* p = accumulator( 2.0 );
35+
* // returns 2.0
36+
*
37+
* p = accumulator( -5.0 );
38+
* // returns -10.0
39+
*
40+
* p = accumulator( 3.0 );
41+
* // returns -30.0
42+
*
43+
* p = accumulator( 5.0 );
44+
* // returns -75.0
45+
*
46+
* p = accumulator();
47+
* // returns -75.0
48+
*/
49+
50+
// MODULES //
51+
52+
var incrmprod = require( './main.js' );
53+
54+
55+
// EXPORTS //
56+
57+
module.exports = incrmprod;

0 commit comments

Comments
 (0)