Skip to content

Commit 61b2c01

Browse files
committed
refactor and add protocol support to stats/base/stdevpn
1 parent 93dc87f commit 61b2c01

File tree

6 files changed

+139
-63
lines changed

6 files changed

+139
-63
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2025 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 isnan = require( '@stdlib/math/base/assert/is-nan' );
24+
var sqrt = require( '@stdlib/math/base/special/sqrt' );
25+
26+
// MAIN //
27+
/**
28+
* Computes the standard deviation of a strided array using a two-pass algorithm.
29+
*
30+
* @private
31+
* @param {PositiveInteger} N - number of indexed elements
32+
* @param {number} correction - degrees of freedom adjustment
33+
* @param {Object} x - input array object
34+
* @param {Collection} x.data - input array data
35+
* @param {Array<Function>} x.accessors - array element accessors
36+
* @param {integer} strideX - strideX length
37+
* @param {NonNegativeInteger} offsetX - starting index
38+
* @returns {number} standard deviation
39+
* @example
40+
* var toAccessorArray = require( '@stdlib/array/base/to-accessor-array' );
41+
* var arraylike2object = require( '@stdlib/array/base/arraylike2object' );
42+
*
43+
* var x = toAccessorArray( [ 2.0, 1.0, 2.0, -2.0, -2.0, 2.0, 3.0, 4.0 ] );
44+
*
45+
* var v = stdevpn( 4, 1, arraylike2object( x ), 2, 1 );
46+
* // returns 2.5
47+
*/
48+
function stdevpn( N, correction, x, strideX, offsetX) {
49+
var xbuf;
50+
var xget;
51+
var ix;
52+
var mean;
53+
var M2;
54+
var delta;
55+
var v;
56+
var i;
57+
58+
// Cache reference to array data:
59+
xbuf = x.data;
60+
61+
// Cache a reference to the element accessor:
62+
xget = x.accessors[ 0 ];
63+
64+
if ( N <= 0 || (N - correction) <= 0) {
65+
return NaN;
66+
}
67+
68+
mean = 0.0;
69+
M2 = 0.0;
70+
71+
ix = offsetX;
72+
for ( i = 0; i < N; i++ ) {
73+
v = xget( xbuf, ix );
74+
75+
delta = v - mean;
76+
mean += delta / (i + 1);
77+
M2 += delta * (v - mean);
78+
79+
ix += strideX;
80+
}
81+
82+
var variance = M2 / (N - correction);
83+
84+
return sqrt( variance );
85+
}
86+
// EXPORTS //
87+
88+
module.exports = stdevpn;

lib/node_modules/@stdlib/stats/base/stdevpn/lib/index.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,11 @@
3232
* // returns ~2.0817
3333
*
3434
* @example
35-
* var floor = require( '@stdlib/math/base/special/floor' );
3635
* var stdevpn = require( '@stdlib/stats/base/stdevpn' );
3736
*
3837
* var x = [ 2.0, 1.0, 2.0, -2.0, -2.0, 2.0, 3.0, 4.0 ];
39-
* var N = floor( x.length / 2 );
4038
*
41-
* var v = stdevpn.ndarray( N, 1, x, 2, 1 );
39+
* var v = stdevpn.ndarray( 8, 1, x, 2, 1 );
4240
* // returns 2.5
4341
*/
4442

lib/node_modules/@stdlib/stats/base/stdevpn/lib/ndarray.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222

2323
var variancepn = require( '@stdlib/stats/base/variancepn' ).ndarray;
2424
var sqrt = require( '@stdlib/math/base/special/sqrt' );
25-
25+
var arraylike2object = require( '@stdlib/array/base/arraylike2object' );
26+
var accessors = require( './accessors.js' );
2627

2728
// MAIN //
2829

@@ -32,21 +33,23 @@ var sqrt = require( '@stdlib/math/base/special/sqrt' );
3233
* @param {PositiveInteger} N - number of indexed elements
3334
* @param {number} correction - degrees of freedom adjustment
3435
* @param {NumericArray} x - input array
35-
* @param {integer} stride - stride length
36-
* @param {NonNegativeInteger} offset - starting index
36+
* @param {integer} strideX - stride length
37+
* @param {NonNegativeInteger} offsetX - starting index
3738
* @returns {number} standard deviation
3839
*
3940
* @example
40-
* var floor = require( '@stdlib/math/base/special/floor' );
41-
*
4241
* var x = [ 2.0, 1.0, 2.0, -2.0, -2.0, 2.0, 3.0, 4.0 ];
43-
* var N = floor( x.length / 2 );
44-
*
45-
* var v = stdevpn( N, 1, x, 2, 1 );
42+
* var v = stdevpn( 4, 1, x, 2, 1 );
4643
* // returns 2.5
4744
*/
48-
function stdevpn( N, correction, x, stride, offset ) {
49-
return sqrt( variancepn( N, correction, x, stride, offset ) );
45+
function stdevpn( N, correction, x, strideX, offsetX ) {
46+
var o;
47+
48+
o = arraylike2object( x );
49+
if ( o.accessorProtocol ) {
50+
return accessors( N, correction, o, strideX, offsetX );
51+
}
52+
return sqrt( variancepn( N, correction, x, strideX, offsetX ) );
5053
}
5154

5255

lib/node_modules/@stdlib/stats/base/stdevpn/lib/stdevpn.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@
2020

2121
// MODULES //
2222

23-
var variancepn = require( '@stdlib/stats/base/variancepn' );
24-
var sqrt = require( '@stdlib/math/base/special/sqrt' );
25-
23+
var stride2offset = require( '@stdlib/strided/base/stride2offset' );
24+
var ndarray = require( './ndarray.js' );
2625

2726
// MAIN //
2827

@@ -32,7 +31,7 @@ var sqrt = require( '@stdlib/math/base/special/sqrt' );
3231
* @param {PositiveInteger} N - number of indexed elements
3332
* @param {number} correction - degrees of freedom adjustment
3433
* @param {NumericArray} x - input array
35-
* @param {integer} stride - stride length
34+
* @param {integer} strideX - stride length
3635
* @returns {number} standard deviation
3736
*
3837
* @example
@@ -41,8 +40,8 @@ var sqrt = require( '@stdlib/math/base/special/sqrt' );
4140
* var v = stdevpn( x.length, 1, x, 1 );
4241
* // returns ~2.0817
4342
*/
44-
function stdevpn( N, correction, x, stride ) {
45-
return sqrt( variancepn( N, correction, x, stride ) );
43+
function stdevpn( N, correction, x, strideX ) {
44+
return ndarray( N, correction, x, strideX, stride2offset( N, strideX ) );
4645
}
4746

4847

lib/node_modules/@stdlib/stats/base/stdevpn/test/test.ndarray.js

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
// MODULES //
2222

2323
var tape = require( 'tape' );
24-
var floor = require( '@stdlib/math/base/special/floor' );
24+
var toAccessorArray = require( '@stdlib/array/base/to-accessor-array' );
2525
var sqrt = require( '@stdlib/math/base/special/sqrt' );
2626
var isnan = require( '@stdlib/math/base/assert/is-nan' );
2727
var stdevpn = require( './../lib/ndarray.js' );
@@ -45,15 +45,15 @@ tape( 'the function calculates the population standard deviation of a strided ar
4545
var v;
4646

4747
x = [ 1.0, -2.0, -4.0, 5.0, 0.0, 3.0 ];
48-
v = stdevpn( x.length, 0, x, 1, 0 );
48+
v = stdevpn( x.length, 0, toAccessorArray( x ), 1, 0 );
4949
t.strictEqual( v, sqrt( 53.5/x.length ), 'returns expected value' );
5050

5151
x = [ -4.0, -4.0 ];
52-
v = stdevpn( x.length, 0, x, 1, 0 );
52+
v = stdevpn( x.length, 0, toAccessorArray( x ), 1, 0 );
5353
t.strictEqual( v, 0.0, 'returns expected value' );
5454

5555
x = [ NaN, 4.0 ];
56-
v = stdevpn( x.length, 0, x, 1, 0 );
56+
v = stdevpn( x.length, 0, toAccessorArray( x ), 1, 0 );
5757
t.strictEqual( isnan( v ), true, 'returns expected value' );
5858

5959
t.end();
@@ -64,15 +64,15 @@ tape( 'the function calculates the sample standard deviation of a strided array'
6464
var v;
6565

6666
x = [ 1.0, -2.0, -4.0, 5.0, 0.0, 3.0 ];
67-
v = stdevpn( x.length, 1, x, 1, 0 );
67+
v = stdevpn( x.length, 1, toAccessorArray( x ), 1, 0 );
6868
t.strictEqual( v, sqrt( 53.5/(x.length-1) ), 'returns expected value' );
6969

7070
x = [ -4.0, -4.0 ];
71-
v = stdevpn( x.length, 1, x, 1, 0 );
71+
v = stdevpn( x.length, 1, toAccessorArray( x ), 1, 0 );
7272
t.strictEqual( v, 0.0, 'returns expected value' );
7373

7474
x = [ NaN, 4.0 ];
75-
v = stdevpn( x.length, 1, x, 1, 0 );
75+
v = stdevpn( x.length, 1, toAccessorArray( x ), 1, 0 );
7676
t.strictEqual( isnan( v ), true, 'returns expected value' );
7777

7878
t.end();
@@ -84,10 +84,10 @@ tape( 'if provided an `N` parameter less than or equal to `0`, the function retu
8484

8585
x = [ 1.0, -2.0, -4.0, 5.0, 3.0 ];
8686

87-
v = stdevpn( 0, 1, x, 1, 0 );
87+
v = stdevpn( 0, 1, toAccessorArray( x ), 1, 0 );
8888
t.strictEqual( isnan( v ), true, 'returns expected value' );
8989

90-
v = stdevpn( -1, 1, x, 1, 0 );
90+
v = stdevpn( -1, 1, toAccessorArray( x ), 1, 0 );
9191
t.strictEqual( isnan( v ), true, 'returns expected value' );
9292

9393
t.end();
@@ -99,7 +99,7 @@ tape( 'if provided an `N` parameter equal to `1`, the function returns a populat
9999

100100
x = [ 1.0, -2.0, -4.0, 5.0, 3.0 ];
101101

102-
v = stdevpn( 1, 0, x, 1, 0 );
102+
v = stdevpn( 1, 0, toAccessorArray( x ), 1, 0 );
103103
t.strictEqual( v, 0.0, 'returns expected value' );
104104

105105
t.end();
@@ -111,17 +111,16 @@ tape( 'if provided a `correction` parameter yielding `N-correction` less than or
111111

112112
x = [ 1.0, -2.0, -4.0, 5.0, 3.0 ];
113113

114-
v = stdevpn( x.length, x.length, x, 1, 0 );
114+
v = stdevpn( x.length, x.length, toAccessorArray( x ), 1, 0 );
115115
t.strictEqual( isnan( v ), true, 'returns expected value' );
116116

117-
v = stdevpn( x.length, x.length+1, x, 1, 0 );
117+
v = stdevpn( x.length, x.length+1, toAccessorArray( x ), 1, 0 );
118118
t.strictEqual( isnan( v ), true, 'returns expected value' );
119119

120120
t.end();
121121
});
122122

123123
tape( 'the function supports a `stride` parameter', function test( t ) {
124-
var N;
125124
var x;
126125
var v;
127126

@@ -136,15 +135,13 @@ tape( 'the function supports a `stride` parameter', function test( t ) {
136135
2.0
137136
];
138137

139-
N = floor( x.length / 2 );
140-
v = stdevpn( N, 1, x, 2, 0 );
138+
v = stdevpn( 4, 1, toAccessorArray( x ), 2, 0 );
141139

142140
t.strictEqual( v, 2.5, 'returns expected value' );
143141
t.end();
144142
});
145143

146144
tape( 'the function supports a negative `stride` parameter', function test( t ) {
147-
var N;
148145
var x;
149146
var v;
150147

@@ -159,8 +156,7 @@ tape( 'the function supports a negative `stride` parameter', function test( t )
159156
2.0
160157
];
161158

162-
N = floor( x.length / 2 );
163-
v = stdevpn( N, 1, x, -2, 6 );
159+
v = stdevpn( 4, 1, toAccessorArray( x ), -2, 6 );
164160

165161
t.strictEqual( v, 2.5, 'returns expected value' );
166162
t.end();
@@ -172,14 +168,13 @@ tape( 'if provided a `stride` parameter equal to `0`, the function returns `0`',
172168

173169
x = [ 1.0, -2.0, -4.0, 5.0, 3.0 ];
174170

175-
v = stdevpn( x.length, 1, x, 0, 0 );
171+
v = stdevpn( x.length, 1, toAccessorArray( x ), 0, 0 );
176172
t.strictEqual( v, 0.0, 'returns expected value' );
177173

178174
t.end();
179175
});
180176

181177
tape( 'the function supports an `offset` parameter', function test( t ) {
182-
var N;
183178
var x;
184179
var v;
185180

@@ -193,9 +188,8 @@ tape( 'the function supports an `offset` parameter', function test( t ) {
193188
3.0,
194189
4.0 // 3
195190
];
196-
N = floor( x.length / 2 );
197191

198-
v = stdevpn( N, 1, x, 2, 1 );
192+
v = stdevpn( 4, 1, toAccessorArray( x ), 2, 1 );
199193
t.strictEqual( v, 2.5, 'returns expected value' );
200194

201195
t.end();

0 commit comments

Comments
 (0)