Skip to content

Commit 6f8898d

Browse files
authored
feat: add accessor arrays support to blas/ext/base/gnansumkbn2
PR-URL: #5034 Reviewed-by: Athan Reines <[email protected]>
1 parent 2e66bec commit 6f8898d

File tree

7 files changed

+370
-3
lines changed

7 files changed

+370
-3
lines changed

lib/node_modules/@stdlib/blas/ext/base/gnansumkbn2/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ var v = gnansumkbn2.ndarray( 5, x, 2, 1 );
109109
## Notes
110110

111111
- If `N <= 0`, both functions return `0.0`.
112+
- Both functions support array-like objects having getter and setter accessors for array element access (e.g., [`@stdlib/array/base/accessor`][@stdlib/array/base/accessor])
112113
- Depending on the environment, the typed versions ([`dnansumkbn2`][@stdlib/blas/ext/base/dnansumkbn2], [`snansumkbn2`][@stdlib/blas/ext/base/snansumkbn2], etc.) are likely to be significantly more performant.
113114

114115
</section>
@@ -185,6 +186,8 @@ console.log( v );
185186

186187
[mdn-typed-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
187188

189+
[@stdlib/array/base/accessor]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/array/base/accessor
190+
188191
[@klein:2005a]: https://doi.org/10.1007/s00607-005-0139-x
189192

190193
<!-- <related-links> -->

lib/node_modules/@stdlib/blas/ext/base/gnansumkbn2/docs/types/index.d.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@
2020

2121
/// <reference types="@stdlib/types"/>
2222

23-
import { NumericArray } from '@stdlib/types/array';
23+
import { NumericArray, Collection, AccessorArrayLike } from '@stdlib/types/array';
24+
25+
/**
26+
* Input array.
27+
*/
28+
type InputArray = NumericArray | Collection<number> | AccessorArrayLike<number>;
2429

2530
/**
2631
* Interface describing `gnansumkbn2`.
@@ -40,7 +45,7 @@ interface Routine {
4045
* var v = gnansumkbn2( x.length, x, 1 );
4146
* // returns 1.0
4247
*/
43-
( N: number, x: NumericArray, strideX: number ): number;
48+
( N: number, x: InputArray, strideX: number ): number;
4449

4550
/**
4651
* Computes the sum of strided array elements, ignoring `NaN` values and using a second-order iterative Kahan–Babuška algorithm and alternative indexing semantics.
@@ -57,7 +62,7 @@ interface Routine {
5762
* var v = gnansumkbn2.ndarray( x.length, x, 1, 0 );
5863
* // returns 1.0
5964
*/
60-
ndarray( N: number, x: NumericArray, strideX: number, offsetX: number ): number;
65+
ndarray( N: number, x: InputArray, strideX: number, offsetX: number ): number;
6166
}
6267

6368
/**

lib/node_modules/@stdlib/blas/ext/base/gnansumkbn2/docs/types/test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* limitations under the License.
1717
*/
1818

19+
import AccessorArray = require( '@stdlib/array/base/accessor' );
1920
import gnansumkbn2 = require( './index' );
2021

2122

@@ -26,6 +27,7 @@ import gnansumkbn2 = require( './index' );
2627
const x = new Float64Array( 10 );
2728

2829
gnansumkbn2( x.length, x, 1 ); // $ExpectType number
30+
gnansumkbn2( x.length, new AccessorArray( x ), 1 ); // $ExpectType number
2931
}
3032

3133
// The compiler throws an error if the function is provided a first argument which is not a number...
@@ -85,6 +87,7 @@ import gnansumkbn2 = require( './index' );
8587
const x = new Float64Array( 10 );
8688

8789
gnansumkbn2.ndarray( x.length, x, 1, 0 ); // $ExpectType number
90+
gnansumkbn2.ndarray( x.length, new AccessorArray( x ), 1, 0 ); // $ExpectType number
8891
}
8992

9093
// The compiler throws an error if the `ndarray` method is provided a first argument which is not a number...
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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 abs = require( '@stdlib/math/base/special/abs' );
25+
26+
27+
// MAIN //
28+
29+
/**
30+
* Computes the sum of strided array elements, ignoring `NaN` values and using a second-order iterative Kahan–Babuška algorithm.
31+
*
32+
* ## Method
33+
*
34+
* - This implementation uses a second-order iterative Kahan–Babuška algorithm, as described by Klein (2005).
35+
*
36+
* ## References
37+
*
38+
* - Klein, Andreas. 2005. "A Generalized Kahan-Babuška-Summation-Algorithm." _Computing_ 76 (3): 279–93. doi:[10.1007/s00607-005-0139-x](https://doi.org/10.1007/s00607-005-0139-x).
39+
*
40+
* @private
41+
* @param {PositiveInteger} N - number of indexed elements
42+
* @param {Object} x - input array object
43+
* @param {Collection} x.data - input array data
44+
* @param {Array<Function>} x.accessors - array element accessors
45+
* @param {integer} strideX - stride length for `x`
46+
* @param {NonNegativeInteger} offsetX - starting index for `x`
47+
* @returns {number} sum
48+
*
49+
* @example
50+
* var toAccessorArray = require( '@stdlib/array/base/to-accessor-array' );
51+
* var arraylike2object = require( '@stdlib/array/base/arraylike2object' );
52+
*
53+
* var x = toAccessorArray( [ 2.0, 1.0, 2.0, -2.0, -2.0, 2.0, 3.0, 4.0 ] );
54+
*
55+
* var v = gnansumkbn2( 4, arraylike2object( x ), 2, 1 );
56+
* // returns 5.0
57+
*/
58+
function gnansumkbn2( N, x, strideX, offsetX ) {
59+
var xbuf;
60+
var xget;
61+
var sum;
62+
var ccs;
63+
var cs;
64+
var cc;
65+
var ix;
66+
var v;
67+
var t;
68+
var c;
69+
var i;
70+
71+
// Cache reference to array data:
72+
xbuf = x.data;
73+
74+
// Cache reference to the element accessors:
75+
xget = x.accessors[ 0 ];
76+
77+
ix = offsetX;
78+
if ( strideX === 0 ) {
79+
if ( isnan( xget( xbuf, ix ) ) ) {
80+
return 0.0;
81+
}
82+
return N * xget( xbuf, ix );
83+
}
84+
sum = 0.0;
85+
ccs = 0.0; // second order correction term for lost low order bits
86+
cs = 0.0; // first order correction term for lost low order bits
87+
for ( i = 0; i < N; i++ ) {
88+
v = xget( xbuf, ix );
89+
if ( isnan( v ) === false ) {
90+
t = sum + v;
91+
if ( abs( sum ) >= abs( v ) ) {
92+
c = (sum-t) + v;
93+
} else {
94+
c = (v-t) + sum;
95+
}
96+
sum = t;
97+
t = cs + c;
98+
if ( abs( cs ) >= abs( c ) ) {
99+
cc = (cs-t) + c;
100+
} else {
101+
cc = (c-t) + cs;
102+
}
103+
cs = t;
104+
ccs += cc;
105+
}
106+
ix += strideX;
107+
}
108+
return sum + cs + ccs;
109+
}
110+
111+
112+
// EXPORTS //
113+
114+
module.exports = gnansumkbn2;

lib/node_modules/@stdlib/blas/ext/base/gnansumkbn2/lib/ndarray.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020

2121
// MODULES //
2222

23+
var arraylike2object = require( '@stdlib/array/base/arraylike2object' );
2324
var isnan = require( '@stdlib/math/base/assert/is-nan' );
2425
var abs = require( '@stdlib/math/base/special/abs' );
26+
var accessors = require( './accessors.js' );
2527

2628

2729
// MAIN //
@@ -58,11 +60,16 @@ function gnansumkbn2( N, x, strideX, offsetX ) {
5860
var v;
5961
var t;
6062
var c;
63+
var o;
6164
var i;
6265

6366
if ( N <= 0 ) {
6467
return 0.0;
6568
}
69+
o = arraylike2object( x );
70+
if ( o.accessorProtocol ) {
71+
return accessors( N, o, strideX, offsetX );
72+
}
6673
ix = offsetX;
6774
if ( strideX === 0 ) {
6875
if ( isnan( x[ ix ] ) ) {

lib/node_modules/@stdlib/blas/ext/base/gnansumkbn2/test/test.main.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
var tape = require( 'tape' );
2424
var Float64Array = require( '@stdlib/array/float64' );
25+
var toAccessorArray = require( '@stdlib/array/base/to-accessor-array' );
2526
var gnansumkbn2 = require( './../lib' );
2627

2728

@@ -73,6 +74,41 @@ tape( 'the function calculates the sum of strided array elements (ignoring NaN v
7374
t.end();
7475
});
7576

77+
tape( 'the function calculates the sum of strided array elements (ignoring NaN values, accessors)', function test( t ) {
78+
var x;
79+
var v;
80+
81+
x = [ 1.0, -2.0, -4.0, 5.0, 0.0, NaN, 3.0, 0.0, -3.0, 3.0 ];
82+
v = gnansumkbn2( x.length, toAccessorArray( x ), 1 );
83+
t.strictEqual( v, 3.0, 'returns expected value' );
84+
85+
x = [ 1.0, -2.0, -4.0, NaN, 5.0, 0.0, 3.0 ];
86+
v = gnansumkbn2( x.length, toAccessorArray( x ), 1 );
87+
t.strictEqual( v, 3.0, 'returns expected value' );
88+
89+
x = [ -4.0, NaN, -4.0 ];
90+
v = gnansumkbn2( x.length, toAccessorArray( x ), 1 );
91+
t.strictEqual( v, -8.0, 'returns expected value' );
92+
93+
x = [ NaN, 4.0 ];
94+
v = gnansumkbn2( x.length, toAccessorArray( x ), 1 );
95+
t.strictEqual( v, 4.0, 'returns expected value' );
96+
97+
x = [ NaN, NaN ];
98+
v = gnansumkbn2( x.length, toAccessorArray( x ), 1 );
99+
t.strictEqual( v, 0.0, 'returns expected value' );
100+
101+
x = [ NaN ];
102+
v = gnansumkbn2( x.length, toAccessorArray( x ), 1 );
103+
t.strictEqual( v, 0.0, 'returns expected value' );
104+
105+
x = [ 1.0, 1.0e100, 1.0, -1.0e100 ];
106+
v = gnansumkbn2( x.length, toAccessorArray( x ), 1 );
107+
t.strictEqual( v, 2.0, 'returns expected value' );
108+
109+
t.end();
110+
});
111+
76112
tape( 'if provided an `N` parameter less than or equal to `0`, the function returns `0.0`', function test( t ) {
77113
var x;
78114
var v;
@@ -123,6 +159,29 @@ tape( 'the function supports a `stride` parameter', function test( t ) {
123159
t.end();
124160
});
125161

162+
tape( 'the function supports a `stride` parameter (accessors)', function test( t ) {
163+
var x;
164+
var v;
165+
166+
x = [
167+
1.0, // 0
168+
2.0,
169+
2.0, // 1
170+
-7.0,
171+
-2.0, // 2
172+
3.0,
173+
4.0, // 3
174+
2.0,
175+
NaN, // 4
176+
NaN
177+
];
178+
179+
v = gnansumkbn2( 5, toAccessorArray( x ), 2 );
180+
181+
t.strictEqual( v, 5.0, 'returns expected value' );
182+
t.end();
183+
});
184+
126185
tape( 'the function supports a negative `stride` parameter', function test( t ) {
127186
var x;
128187
var v;
@@ -146,6 +205,29 @@ tape( 'the function supports a negative `stride` parameter', function test( t )
146205
t.end();
147206
});
148207

208+
tape( 'the function supports a negative `stride` parameter (accessors)', function test( t ) {
209+
var x;
210+
var v;
211+
212+
x = [
213+
NaN, // 4
214+
NaN,
215+
1.0, // 3
216+
2.0,
217+
2.0, // 2
218+
-7.0,
219+
-2.0, // 1
220+
3.0,
221+
4.0, // 0
222+
2.0
223+
];
224+
225+
v = gnansumkbn2( 5, toAccessorArray( x ), -2 );
226+
227+
t.strictEqual( v, 5.0, 'returns expected value' );
228+
t.end();
229+
});
230+
149231
tape( 'if provided a `stride` parameter equal to `0`, the function returns the sum of the first element repeated N times', function test( t ) {
150232
var x;
151233
var v;
@@ -158,6 +240,18 @@ tape( 'if provided a `stride` parameter equal to `0`, the function returns the s
158240
t.end();
159241
});
160242

243+
tape( 'if provided a `stride` parameter equal to `0`, the function returns the sum of the first element repeated N times (accessors)', function test( t ) {
244+
var x;
245+
var v;
246+
247+
x = [ 1.0, -2.0, -4.0, 5.0, 3.0 ];
248+
249+
v = gnansumkbn2( x.length, toAccessorArray( x ), 0 );
250+
t.strictEqual( v, 5.0, 'returns expected value' );
251+
252+
t.end();
253+
});
254+
161255
tape( 'if provided a `stride` parameter equal to `0` and the first element is NaN, the function returns 0', function test( t ) {
162256
var x;
163257
var v;
@@ -170,6 +264,18 @@ tape( 'if provided a `stride` parameter equal to `0` and the first element is Na
170264
t.end();
171265
});
172266

267+
tape( 'if provided a `stride` parameter equal to `0` and the first element is NaN, the function returns 0 (accessors)', function test( t ) {
268+
var x;
269+
var v;
270+
271+
x = [ NaN, -2.0, -4.0, 5.0, 3.0 ];
272+
273+
v = gnansumkbn2( x.length, toAccessorArray( x ), 0 );
274+
t.strictEqual( v, 0.0, 'returns expected value' );
275+
276+
t.end();
277+
});
278+
173279
tape( 'the function supports view offsets', function test( t ) {
174280
var x0;
175281
var x1;

0 commit comments

Comments
 (0)