22
22
23
23
var isPositiveInteger = require ( '@stdlib/assert/is-positive-integer' ) . isPrimitive ;
24
24
var isNumber = require ( '@stdlib/assert/is-number' ) . isPrimitive ;
25
+ var isnan = require ( '@stdlib/math/base/assert/is-nan' ) ;
25
26
var sqrt = require ( '@stdlib/math/base/special/sqrt' ) ;
26
27
27
28
@@ -104,6 +105,8 @@ function incrmstdev( W, mean ) {
104
105
* // returns ~5.29
105
106
*/
106
107
function accumulator1 ( x ) {
108
+ var k ;
109
+ var v ;
107
110
if ( arguments . length === 0 ) {
108
111
if ( N === 0 ) {
109
112
return null ;
@@ -119,9 +122,13 @@ function incrmstdev( W, mean ) {
119
122
// Update the index for managing the circular buffer:
120
123
i = ( i + 1 ) % W ;
121
124
122
- // Determine if we should update the initial window...
123
- if ( N < W ) {
124
- buf [ i ] = x ;
125
+ // Case: incoming value is NaN, the sliding second moment is automatically NaN...
126
+ if ( isnan ( x ) ) {
127
+ M2 = NaN ;
128
+ }
129
+ // Case: initial window...
130
+ else if ( N < W ) {
131
+ buf [ i ] = x ; // update buffer
125
132
N += 1 ;
126
133
delta = x - mu ;
127
134
mu += delta / N ;
@@ -131,18 +138,41 @@ function incrmstdev( W, mean ) {
131
138
}
132
139
return sqrt ( M2 / ( N - 1 ) ) ;
133
140
}
134
- // N = W = 1
141
+ // Case: N = W = 1
135
142
if ( N === 1 ) {
136
143
return 0.0 ;
137
144
}
138
- // Update the existing window...
139
- tmp = buf [ i ] ;
145
+ // Case: outgoing value is NaN, and, thus, we need to compute the accumulated values...
146
+ if ( isnan ( buf [ i ] ) ) {
147
+ N = 1 ;
148
+ mu = x ;
149
+ M2 = 0.0 ;
150
+ for ( k = 0 ; k < W ; k ++ ) {
151
+ if ( k !== i ) {
152
+ v = buf [ k ] ;
153
+ if ( isnan ( v ) ) {
154
+ M2 = NaN ;
155
+ break ; // second moment is automatically NaN, so no need to continue
156
+ }
157
+ N += 1 ;
158
+ delta = v - mu ;
159
+ mu += delta / N ;
160
+ M2 += delta * ( v - mu ) ;
161
+ }
162
+ }
163
+ }
164
+ // Case: neither the current second moment nor the incoming value are NaN, so we need to update the accumulated values...
165
+ else if ( isnan ( M2 ) === false ) {
166
+ tmp = buf [ i ] ;
167
+ delta = x - tmp ;
168
+ d1 = tmp - mu ;
169
+ mu += delta / W ;
170
+ d2 = x - mu ;
171
+ M2 += delta * ( d1 + d2 ) ;
172
+ }
173
+ // Case: the current second moment is NaN, so nothing to do until the buffer no longer contains NaN values...
174
+
140
175
buf [ i ] = x ;
141
- delta = x - tmp ;
142
- d1 = tmp - mu ;
143
- mu += delta / W ;
144
- d2 = x - mu ;
145
- M2 += delta * ( d1 + d2 ) ;
146
176
return sqrt ( M2 / n ) ;
147
177
}
148
178
@@ -154,6 +184,7 @@ function incrmstdev( W, mean ) {
154
184
* @returns {(number|null) } corrected sample standard deviation or null
155
185
*/
156
186
function accumulator2 ( x ) {
187
+ var k ;
157
188
if ( arguments . length === 0 ) {
158
189
if ( N === 0 ) {
159
190
return null ;
@@ -166,18 +197,40 @@ function incrmstdev( W, mean ) {
166
197
// Update the index for managing the circular buffer:
167
198
i = ( i + 1 ) % W ;
168
199
169
- // Determine if we should update the initial window...
170
- if ( N < W ) {
171
- buf [ i ] = x ;
200
+ // Case: incoming value is NaN, the sliding second moment is automatically NaN...
201
+ if ( isnan ( x ) ) {
202
+ M2 = NaN ;
203
+ }
204
+ // Case: initial window...
205
+ else if ( N < W ) {
206
+ buf [ i ] = x ; // update buffer
172
207
N += 1 ;
173
208
delta = x - mu ;
174
209
M2 += delta * delta ;
175
210
return sqrt ( M2 / N ) ;
176
211
}
177
- // Update the existing window...
178
- tmp = buf [ i ] ;
212
+ // Case: outgoing value is NaN, and, thus, we need to compute the accumulated values...
213
+ if ( isnan ( buf [ i ] ) ) {
214
+ M2 = 0.0 ;
215
+ for ( k = 0 ; k < W ; k ++ ) {
216
+ if ( k !== i ) {
217
+ if ( isnan ( buf [ k ] ) ) {
218
+ M2 = NaN ;
219
+ break ; // second moment is automatically NaN, so no need to continue
220
+ }
221
+ delta = buf [ k ] - mu ;
222
+ M2 += delta * delta ;
223
+ }
224
+ }
225
+ }
226
+ // Case: neither the current second moment nor the incoming value are NaN, so we need to update the accumulated values...
227
+ else if ( isnan ( M2 ) === false ) {
228
+ tmp = buf [ i ] ;
229
+ M2 += ( x - tmp ) * ( x - mu + tmp - mu ) ;
230
+ }
231
+ // Case: the current second moment is NaN, so nothing to do until the buffer no longer contains NaN values...
232
+
179
233
buf [ i ] = x ;
180
- M2 += ( x - tmp ) * ( x - mu + tmp - mu ) ;
181
234
return sqrt ( M2 / W ) ;
182
235
}
183
236
}
0 commit comments