Skip to content

Commit bf4258f

Browse files
committed
fix: update implementation to preserve signed zeros
--- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: passed - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: passed - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed ---
1 parent 149aa3c commit bf4258f

File tree

4 files changed

+81
-16
lines changed

4 files changed

+81
-16
lines changed

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

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ var abs = require( '@stdlib/math/base/special/abs' );
5454
function dnansumkbn2( N, x, strideX, offsetX ) {
5555
var sum;
5656
var ccs;
57+
var flg;
5758
var ix;
5859
var cs;
5960
var cc;
@@ -62,20 +63,50 @@ function dnansumkbn2( N, x, strideX, offsetX ) {
6263
var c;
6364
var i;
6465

65-
sum = 0.0;
6666
if ( N <= 0 ) {
67-
return sum;
67+
return 0.0;
6868
}
6969
ix = offsetX;
7070
if ( strideX === 0 ) {
7171
if ( isnan( x[ ix ] ) ) {
72-
return sum;
72+
return 0.0;
7373
}
7474
return x[ ix ] * N;
7575
}
76+
// Find the first non-NaN element...
77+
for ( i = 0; i < N; i++ ) {
78+
v = x[ ix ];
79+
if ( isnan( v ) === false ) {
80+
break;
81+
}
82+
ix += strideX;
83+
}
84+
if ( i === N ) {
85+
return NaN;
86+
}
87+
sum = v;
88+
ix += strideX;
89+
i += 1;
90+
91+
// In order to preserve the sign of zero which can be lost during compensated summation below, find the first non-zero element...
92+
if ( sum === 0.0 ) {
93+
for ( ; i < N; i++ ) {
94+
v = x[ ix ];
95+
if ( isnan( v ) === false ) {
96+
if ( v !== 0.0 ) {
97+
flg = true;
98+
break;
99+
}
100+
sum += v;
101+
}
102+
ix += strideX;
103+
}
104+
} else {
105+
flg = true;
106+
}
76107
ccs = 0.0; // second order correction term for lost low order bits
77108
cs = 0.0; // first order correction term for lost low order bits
78-
for ( i = 0; i < N; i++ ) {
109+
for ( ; i < N; i++ ) {
79110
v = x[ ix ];
80111
if ( isnan( v ) === false ) {
81112
t = sum + v;
@@ -96,7 +127,7 @@ function dnansumkbn2( N, x, strideX, offsetX ) {
96127
}
97128
ix += strideX;
98129
}
99-
return sum + cs + ccs;
130+
return ( flg ) ? sum+cs+ccs : sum;
100131
}
101132

102133

lib/node_modules/@stdlib/blas/ext/base/dnansumkbn2/src/main.c

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,30 +61,62 @@ double API_SUFFIX(stdlib_strided_dnansumkbn2)( const CBLAS_INT N, const double *
6161
* @return output value
6262
*/
6363
double API_SUFFIX(stdlib_strided_dnansumkbn2_ndarray)( const CBLAS_INT N, const double *X, const CBLAS_INT strideX, const CBLAS_INT offsetX ) {
64-
double sum;
65-
double ccs;
6664
CBLAS_INT ix;
6765
CBLAS_INT i;
66+
double sum;
67+
double ccs;
6868
double cs;
6969
double cc;
7070
double v;
7171
double t;
7272
double c;
73+
int flg;
7374

74-
sum = 0.0;
7575
if ( N <= 0 ) {
76-
return sum;
76+
return 0.0;
7777
}
7878
ix = offsetX;
7979
if ( strideX == 0 ) {
8080
if ( stdlib_base_is_nan( X[ ix ] ) ) {
81-
return sum;
81+
return 0.0;
8282
}
8383
return X[ ix ] * N;
8484
}
85+
// Find the first non-NaN element...
86+
for ( i = 0; i < N; i++ ) {
87+
v = X[ ix ];
88+
if ( !stdlib_base_is_nan( v ) ) {
89+
break;
90+
}
91+
ix += strideX;
92+
}
93+
if ( i == N ) {
94+
return 0.0;
95+
}
96+
sum = v;
97+
ix += strideX;
98+
flg = 0;
99+
i += 1;
100+
101+
// In order to preserve the sign of zero which can be lost during compensated summation below, find the first non-zero element...
102+
if ( sum == 0.0 ) {
103+
for ( ; i < N; i++ ) {
104+
v = X[ ix ];
105+
if ( !stdlib_base_is_nan( v ) ) {
106+
if ( v != 0.0 ) {
107+
flg = 1;
108+
break;
109+
}
110+
sum += v;
111+
}
112+
ix += strideX;
113+
}
114+
} else {
115+
flg = 1;
116+
}
85117
ccs = 0.0; // second order correction term for lost lower order bits
86118
cs = 0.0; // first order correction term for lost low order bits
87-
for ( i = 0; i < N; i++ ) {
119+
for ( ; i < N; i++ ) {
88120
v = X[ ix ];
89121
if ( !stdlib_base_is_nan( v ) ) {
90122
t = sum + v;
@@ -105,5 +137,5 @@ double API_SUFFIX(stdlib_strided_dnansumkbn2_ndarray)( const CBLAS_INT N, const
105137
}
106138
ix += strideX;
107139
}
108-
return sum + cs + ccs;
140+
return ( flg == 1 ) ? sum+cs+ccs : sum;
109141
}

lib/node_modules/@stdlib/blas/ext/base/dnansumkbn2/test/test.ndarray.js

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

2323
var tape = require( 'tape' );
2424
var isPositiveZero = require( '@stdlib/math/base/assert/is-positive-zero' );
25+
var isNegativeZero = require( '@stdlib/math/base/assert/is-negative-zero' );
2526
var Float64Array = require( '@stdlib/array/float64' );
2627
var dnansumkbn2 = require( './../lib/ndarray.js' );
2728

@@ -78,14 +79,14 @@ tape( 'the function calculates the sum of strided array elements (ignoring NaN v
7879
t.end();
7980
});
8081

81-
tape( 'the function does not preserve the sign of zero', function test( t ) {
82+
tape( 'the function preserves the sign of zero', function test( t ) {
8283
var x;
8384
var v;
8485

8586
x = new Float64Array( [ -0.0, -0.0, -0.0 ] );
8687

8788
v = dnansumkbn2( x.length, x, 1, 0 );
88-
t.strictEqual( isPositiveZero( v ), true, 'returns expected value' );
89+
t.strictEqual( isNegativeZero( v ), true, 'returns expected value' );
8990

9091
x = new Float64Array( [ 0.0, -0.0, -0.0 ] );
9192

lib/node_modules/@stdlib/blas/ext/base/dnansumkbn2/test/test.ndarray.native.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
var resolve = require( 'path' ).resolve;
2424
var tape = require( 'tape' );
2525
var isPositiveZero = require( '@stdlib/math/base/assert/is-positive-zero' );
26+
var isNegativeZero = require( '@stdlib/math/base/assert/is-negative-zero' );
2627
var Float64Array = require( '@stdlib/array/float64' );
2728
var tryRequire = require( '@stdlib/utils/try-require' );
2829

@@ -87,14 +88,14 @@ tape( 'the function calculates the sum of strided array elements (ignoring NaN v
8788
t.end();
8889
});
8990

90-
tape( 'the function does not preserve the sign of zero', opts, function test( t ) {
91+
tape( 'the function preserves the sign of zero', opts, function test( t ) {
9192
var x;
9293
var v;
9394

9495
x = new Float64Array( [ -0.0, -0.0, -0.0 ] );
9596

9697
v = dnansumkbn2( x.length, x, 1, 0 );
97-
t.strictEqual( isPositiveZero( v ), true, 'returns expected value' );
98+
t.strictEqual( isNegativeZero( v ), true, 'returns expected value' );
9899

99100
x = new Float64Array( [ 0.0, -0.0, -0.0 ] );
100101

0 commit comments

Comments
 (0)