Skip to content

Commit f507f85

Browse files
authored
feat: add blas/ext/base/ndarray/dnansumpw
PR-URL: #9174 Reviewed-by: Athan Reines <[email protected]>
1 parent fff219f commit f507f85

File tree

10 files changed

+784
-0
lines changed

10 files changed

+784
-0
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<!--
2+
3+
@license Apache-2.0
4+
5+
Copyright (c) 2025 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+
# dnansumpw
22+
23+
> Compute the sum of a one-dimensional double-precision floating-point ndarray, ignoring `NaN` values and using pairwise summation.
24+
25+
<section class="intro">
26+
27+
</section>
28+
29+
<!-- /.intro -->
30+
31+
<section class="usage">
32+
33+
## Usage
34+
35+
```javascript
36+
var dnansumpw = require( '@stdlib/blas/ext/base/ndarray/dnansumpw' );
37+
```
38+
39+
#### dnansumpw( arrays )
40+
41+
Computes the sum of a one-dimensional double-precision floating-point ndarray, ignoring `NaN` values and using pairwise summation.
42+
43+
```javascript
44+
var Float64Array = require( '@stdlib/array/float64' );
45+
var ndarray = require( '@stdlib/ndarray/base/ctor' );
46+
47+
var xbuf = new Float64Array( [ 1.0, -2.0, NaN, 2.0 ] );
48+
var x = new ndarray( 'float64', xbuf, [ 4 ], [ 1 ], 0, 'row-major' );
49+
50+
var v = dnansumpw( [ x ] );
51+
// returns 1.0
52+
```
53+
54+
The function has the following parameters:
55+
56+
- **arrays**: array-like object containing a one-dimensional input ndarray.
57+
58+
</section>
59+
60+
<!-- /.usage -->
61+
62+
<section class="notes">
63+
64+
## Notes
65+
66+
- If provided an empty one-dimensional ndarray, the function returns `0.0`.
67+
- In general, pairwise summation is more numerically stable than ordinary recursive summation (i.e., "simple" summation), with slightly worse performance. While not the most numerically stable summation technique (e.g., compensated summation techniques such as the Kahan–Babuška-Neumaier algorithm are generally more numerically stable), pairwise summation strikes a reasonable balance between numerical stability and performance. If either numerical stability or performance is more desirable for your use case, consider alternative summation techniques.
68+
69+
</section>
70+
71+
<!-- /.notes -->
72+
73+
<section class="examples">
74+
75+
## Examples
76+
77+
<!-- eslint no-undef: "error" -->
78+
79+
```javascript
80+
var bernoulli = require( '@stdlib/random/base/bernoulli' );
81+
var discreteUniform = require( '@stdlib/random/base/discrete-uniform' );
82+
var filledarrayBy = require( '@stdlib/array/filled-by' );
83+
var ndarray = require( '@stdlib/ndarray/base/ctor' );
84+
var ndarray2array = require( '@stdlib/ndarray/to-array' );
85+
var dnansumpw = require( '@stdlib/blas/ext/base/ndarray/dnansumpw' );
86+
87+
function clbk() {
88+
if ( bernoulli( 0.7 ) > 0 ) {
89+
return discreteUniform( 0, 100 );
90+
}
91+
return NaN;
92+
}
93+
94+
var xbuf = filledarrayBy( 10, 'float64', clbk );
95+
var x = new ndarray( 'float64', xbuf, [ xbuf.length ], [ 1 ], 0, 'row-major' );
96+
console.log( ndarray2array( x ) );
97+
98+
var v = dnansumpw( [ x ] );
99+
console.log( v );
100+
```
101+
102+
</section>
103+
104+
<!-- /.examples -->
105+
106+
<section class="references">
107+
108+
## References
109+
110+
- Higham, Nicholas J. 1993. "The Accuracy of Floating Point Summation." _SIAM Journal on Scientific Computing_ 14 (4): 783–99. doi:[10.1137/0914050][@higham:1993a].
111+
112+
</section>
113+
114+
<!-- /.references -->
115+
116+
<!-- Section for related `stdlib` packages. Do not manually edit this section, as it is automatically populated. -->
117+
118+
<section class="related">
119+
120+
</section>
121+
122+
<!-- /.related -->
123+
124+
<!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
125+
126+
<section class="links">
127+
128+
[@higham:1993a]: https://doi.org/10.1137/0914050
129+
130+
</section>
131+
132+
<!-- /.links -->
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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 bench = require( '@stdlib/bench' );
24+
var uniform = require( '@stdlib/random/base/uniform' );
25+
var bernoulli = require( '@stdlib/random/base/bernoulli' );
26+
var filledarrayBy = require( '@stdlib/array/filled-by' );
27+
var isnan = require( '@stdlib/math/base/assert/is-nan' );
28+
var pow = require( '@stdlib/math/base/special/pow' );
29+
var ndarray = require( '@stdlib/ndarray/base/ctor' );
30+
var pkg = require( './../package.json' ).name;
31+
var dnansumpw = require( './../lib' );
32+
33+
34+
// VARIABLES //
35+
36+
var options = {
37+
'dtype': 'float64'
38+
};
39+
40+
41+
// FUNCTIONS //
42+
43+
/**
44+
* Returns a random number or NaN.
45+
*
46+
* @private
47+
* @returns {number} random number or NaN
48+
*/
49+
function rand() {
50+
if ( bernoulli( 0.8 ) > 0 ) {
51+
return uniform( -10.0, 10.0 );
52+
}
53+
return NaN;
54+
}
55+
56+
/**
57+
* Creates a benchmark function.
58+
*
59+
* @private
60+
* @param {PositiveInteger} len - array length
61+
* @returns {Function} benchmark function
62+
*/
63+
function createBenchmark( len ) {
64+
var xbuf;
65+
var x;
66+
67+
xbuf = filledarrayBy( len, options.dtype, rand );
68+
x = new ndarray( options.dtype, xbuf, [ len ], [ 1 ], 0, 'row-major' );
69+
70+
return benchmark;
71+
72+
function benchmark( b ) {
73+
var v;
74+
var i;
75+
76+
b.tic();
77+
for ( i = 0; i < b.iterations; i++ ) {
78+
v = dnansumpw( [ x ] );
79+
if ( isnan( v ) ) {
80+
b.fail( 'should not return NaN' );
81+
}
82+
}
83+
b.toc();
84+
if ( isnan( v ) ) {
85+
b.fail( 'should not return NaN' );
86+
}
87+
b.pass( 'benchmark finished' );
88+
b.end();
89+
}
90+
}
91+
92+
93+
// MAIN //
94+
95+
/**
96+
* Main execution sequence.
97+
*
98+
* @private
99+
*/
100+
function main() {
101+
var len;
102+
var min;
103+
var max;
104+
var f;
105+
var i;
106+
107+
min = 1; // 10^min
108+
max = 6; // 10^max
109+
110+
for ( i = min; i <= max; i++ ) {
111+
len = pow( 10, i );
112+
f = createBenchmark( len );
113+
bench( pkg+':len='+len, f );
114+
}
115+
}
116+
117+
main();
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
{{alias}}( arrays )
3+
Computes the sum of a one-dimensional double-precision floating-point
4+
ndarray, ignoring `NaN` values and using pairwise summation.
5+
6+
If provided an empty ndarray, the function returns `0.0`.
7+
8+
Parameters
9+
----------
10+
arrays: ArrayLikeObject<ndarray>
11+
Array-like object containing a one-dimensional input ndarray.
12+
13+
Returns
14+
-------
15+
out: number
16+
Sum.
17+
18+
Examples
19+
--------
20+
> var xbuf = new {{alias:@stdlib/array/float64}}( [ 1.0, -2.0, NaN, 2.0 ] );
21+
> var dt = 'float64';
22+
> var sh = [ xbuf.length ];
23+
> var sx = [ 1 ];
24+
> var ox = 0;
25+
> var ord = 'row-major';
26+
> var x = new {{alias:@stdlib/ndarray/ctor}}( dt, xbuf, sh, sx, ox, ord );
27+
> {{alias}}( [ x ] )
28+
1.0
29+
30+
See Also
31+
--------
32+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
// TypeScript Version: 4.1
20+
21+
/// <reference types="@stdlib/types"/>
22+
23+
import { float64ndarray } from '@stdlib/types/ndarray';
24+
25+
/**
26+
* Computes the sum of a one-dimensional double-precision floating-point ndarray, ignoring `NaN` values and using pairwise summation.
27+
*
28+
* @param arrays - array-like object containing an input ndarray
29+
* @returns sum
30+
*
31+
* @example
32+
* var Float64Array = require( '@stdlib/array/float64' );
33+
* var ndarray = require( '@stdlib/ndarray/base/ctor' );
34+
*
35+
* var xbuf = new Float64Array( [ 1.0, -2.0, NaN, 2.0 ] );
36+
* var x = new ndarray( 'float64', xbuf, [ 4 ], [ 1 ], 0, 'row-major' );
37+
*
38+
* var v = dnansumpw( [ x ] );
39+
* // returns 1.0
40+
*/
41+
declare function dnansumpw( arrays: [ float64ndarray ] ): number;
42+
43+
44+
// EXPORTS //
45+
46+
export = dnansumpw;
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) 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+
/* eslint-disable space-in-parens */
20+
21+
import zeros = require( '@stdlib/ndarray/zeros' );
22+
import dnansumpw = require( '@stdlib/blas/ext/base/ndarray/dnansumpw' );
23+
24+
25+
// TESTS //
26+
27+
// The function returns a number...
28+
{
29+
const x = zeros( [ 10 ], {
30+
'dtype': 'float64'
31+
});
32+
33+
dnansumpw( [ x ] ); // $ExpectType number
34+
}
35+
36+
// The compiler throws an error if the function is provided a first argument which is not an array of ndarrays...
37+
{
38+
dnansumpw( '10' ); // $ExpectError
39+
dnansumpw( 10 ); // $ExpectError
40+
dnansumpw( true ); // $ExpectError
41+
dnansumpw( false ); // $ExpectError
42+
dnansumpw( null ); // $ExpectError
43+
dnansumpw( undefined ); // $ExpectError
44+
dnansumpw( [] ); // $ExpectError
45+
dnansumpw( {} ); // $ExpectError
46+
dnansumpw( ( x: number ): number => x ); // $ExpectError
47+
}
48+
49+
// The compiler throws an error if the function is provided an unsupported number of arguments...
50+
{
51+
const x = zeros( [ 10 ], {
52+
'dtype': 'float64'
53+
});
54+
55+
dnansumpw(); // $ExpectError
56+
dnansumpw( [ x ], {} ); // $ExpectError
57+
}

0 commit comments

Comments
 (0)