Skip to content

Commit f0ecdad

Browse files
authored
feat: add C ndarray API and refactor blas/ext/base/dnannsumkbn2
PR-URL: #2990 Reviewed-by: Philipp Burckhardt <pburckhardt@outlook.com>
1 parent 19c8688 commit f0ecdad

File tree

19 files changed

+369
-194
lines changed

19 files changed

+369
-194
lines changed

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

Lines changed: 127 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ The function has the following parameters:
5454

5555
- **N**: number of indexed elements.
5656
- **x**: input [`Float64Array`][@stdlib/array/float64].
57-
- **strideX**: index increment for `x`.
57+
- **strideX**: stride length for `x`.
5858
- **out**: output [`Float64Array`][@stdlib/array/float64] whose first element is the sum and whose second element is the number of non-NaN elements.
59-
- **strideOut**: index increment for `out`.
59+
- **strideOut**: stride length for `out`.
6060

6161
The `N` and stride parameters determine which elements are accessed at runtime. For example, to compute the sum of every other element in `x`,
6262

@@ -106,7 +106,7 @@ The function has the following additional parameters:
106106
- **offsetX**: starting index for `x`.
107107
- **offsetOut**: starting index for `out`.
108108

109-
While [`typed array`][mdn-typed-array] views mandate a view offset based on the underlying `buffer`, the `offset` parameter supports indexing semantics based on a starting index. For example, to calculate the sum of every other value in `x` starting from the second value
109+
While [`typed array`][mdn-typed-array] views mandate a view offset based on the underlying buffer, offset parameters support indexing semantics based on starting indices. For example, to calculate the sum of every other element starting from the second element:
110110

111111
```javascript
112112
var Float64Array = require( '@stdlib/array/float64' );
@@ -164,8 +164,132 @@ console.log( out );
164164

165165
<!-- /.examples -->
166166

167+
<!-- C interface documentation. -->
168+
167169
* * *
168170

171+
<section class="c">
172+
173+
## C APIs
174+
175+
<!-- Section to include introductory text. Make sure to keep an empty line after the intro `section` element and another before the `/section` close. -->
176+
177+
<section class="intro">
178+
179+
</section>
180+
181+
<!-- /.intro -->
182+
183+
<!-- C usage documentation. -->
184+
185+
<section class="usage">
186+
187+
### Usage
188+
189+
```c
190+
#include "stdlib/blas/ext/base/dnannsumkbn2.h"
191+
```
192+
193+
#### stdlib_strided_dnannsumkbn2( N, \*X, strideX, \*n )
194+
195+
Computes the sum of double-precision floating-point strided array elements, ignoring `NaN` values and using a second-order iterative Kahan–Babuška algorithm.
196+
197+
```c
198+
const double x[] = { 1.0, 2.0, 0.0/0.0, 4.0 };
199+
CBLAS_INT n = 0;
200+
201+
double v = stdlib_strided_dnannsumkbn2( 4, x, 1, &n );
202+
// returns 7.0
203+
```
204+
205+
The function accepts the following arguments:
206+
207+
- **N**: `[in] CBLAS_INT` number of indexed elements.
208+
- **X**: `[in] double*` input array.
209+
- **strideX**: `[in] CBLAS_INT` stride length for `X`.
210+
- **n**: `[out] CBLAS_INT*` number of non-NaN elements.
211+
212+
```c
213+
double stdlib_strided_dnannsumkbn2( const CBLAS_INT N, const double *X, const CBLAS_INT strideX, CBLAS_INT *n );
214+
```
215+
216+
#### stdlib_strided_dnannsumkbn2_ndarray( N, \*X, strideX, offsetX, \*n )
217+
218+
Computes the sum of double-precision floating-point strided array elements, ignoring `NaN` values and using a second-order iterative Kahan–Babuška algorithm and alternative indexing semantics.
219+
220+
```c
221+
const double x[] = { 1.0, 2.0, 0.0/0.0, 4.0 };
222+
CBLAS_INT n = 0;
223+
224+
double v = stdlib_strided_dnannsumkbn2_ndarray( 4, x, 1, 0, &n );
225+
// returns 7.0
226+
```
227+
228+
The function accepts the following arguments:
229+
230+
- **N**: `[in] CBLAS_INT` number of indexed elements.
231+
- **X**: `[in] double*` input array.
232+
- **strideX**: `[in] CBLAS_INT` stride length for `X`.
233+
- **offsetX**: `[in] CBLAS_INT` starting index for `X`.
234+
- **n**: `[out] CBLAS_INT*` number of non-NaN elements.
235+
236+
```c
237+
double stdlib_strided_dnannsumkbn2_ndarray( const CBLAS_INT N, const double *X, const CBLAS_INT strideX, const CBLAS_INT offsetX, CBLAS_INT *n );
238+
```
239+
240+
</section>
241+
242+
<!-- /.usage -->
243+
244+
<!-- C API usage notes. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
245+
246+
<section class="notes">
247+
248+
</section>
249+
250+
<!-- /.notes -->
251+
252+
<!-- C API usage examples. -->
253+
254+
<section class="examples">
255+
256+
### Examples
257+
258+
```c
259+
#include "stdlib/blas/ext/base/dnannsumkbn2.h"
260+
#include "stdlib/blase/base/shared.h"
261+
#include <stdio.h>
262+
263+
int main( void ) {
264+
// Create a strided array:
265+
const double x[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 0.0/0.0, 0.0/0.0 };
266+
267+
// Specify the number of elements:
268+
const int N = 5;
269+
270+
// Specify the stride length:
271+
const int strideX = 2;
272+
273+
// Initialize a variable for storing the number of non-NaN elements:
274+
CBLAS_INT n = 0;
275+
276+
// Compute the sum:
277+
double v = stdlib_strided_dnannsumkbn2( N, x, strideX, &n );
278+
279+
// Print the result:
280+
printf( "sum: %lf\n", v );
281+
printf( "n: %"CBLAS_IFMT"\n", n );
282+
}
283+
```
284+
285+
</section>
286+
287+
<!-- /.examples -->
288+
289+
</section>
290+
291+
<!-- /.c -->
292+
169293
<section class="references">
170294
171295
## References

lib/node_modules/@stdlib/blas/ext/base/dnannsumkbn2/benchmark/benchmark.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ var dnannsumkbn2 = require( './../lib/dnannsumkbn2.js' );
3333

3434
// FUNCTIONS //
3535

36+
/**
37+
* Returns a random number.
38+
*
39+
* @private
40+
* @returns {number} random number
41+
*/
42+
function rand() {
43+
if ( bernoulli( 0.7 ) > 0 ) {
44+
return discreteUniform( -10.0, 10.0 );
45+
}
46+
return NaN;
47+
}
48+
3649
/**
3750
* Creates a benchmark function.
3851
*
@@ -44,14 +57,7 @@ function createBenchmark( len ) {
4457
var out;
4558
var x;
4659

47-
function clbk() {
48-
if ( bernoulli( 0.7 ) > 0 ) {
49-
return discreteUniform( -10, 10 );
50-
}
51-
return NaN;
52-
}
53-
54-
x = filledarrayBy( len, 'float64', clbk );
60+
x = filledarrayBy( len, 'float64', rand );
5561
out = new Float64Array( 2 );
5662
return benchmark;
5763

lib/node_modules/@stdlib/blas/ext/base/dnannsumkbn2/benchmark/benchmark.native.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@ var opts = {
4242

4343
// FUNCTIONS //
4444

45+
/**
46+
* Returns a random number.
47+
*
48+
* @private
49+
* @returns {number} random number
50+
*/
51+
function rand() {
52+
if ( bernoulli( 0.8 ) > 0 ) {
53+
return discreteUniform( -10.0, 10.0 );
54+
}
55+
return NaN;
56+
}
57+
4558
/**
4659
* Creates a benchmark function.
4760
*
@@ -53,14 +66,7 @@ function createBenchmark( len ) {
5366
var out;
5467
var x;
5568

56-
function clbk() {
57-
if ( bernoulli( 0.7 ) > 0 ) {
58-
return discreteUniform( -10, 10 );
59-
}
60-
return NaN;
61-
}
62-
63-
x = filledarrayBy( len, 'float64', clbk );
69+
x = filledarrayBy( len, 'float64', rand );
6470
out = new Float64Array( 2 );
6571
return benchmark;
6672

lib/node_modules/@stdlib/blas/ext/base/dnannsumkbn2/benchmark/benchmark.ndarray.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ var dnannsumkbn2 = require( './../lib/ndarray.js' );
3333

3434
// FUNCTIONS //
3535

36+
/**
37+
* Returns a random number.
38+
*
39+
* @private
40+
* @returns {number} random number
41+
*/
42+
function rand() {
43+
if ( bernoulli( 0.8 ) > 0 ) {
44+
return discreteUniform( -10.0, 10.0 );
45+
}
46+
return NaN;
47+
}
48+
3649
/**
3750
* Creates a benchmark function.
3851
*
@@ -44,14 +57,7 @@ function createBenchmark( len ) {
4457
var out;
4558
var x;
4659

47-
function clbk() {
48-
if ( bernoulli( 0.7 ) > 0 ) {
49-
return discreteUniform( -10, 10 );
50-
}
51-
return NaN;
52-
}
53-
54-
x = filledarrayBy( len, 'float64', clbk );
60+
x = filledarrayBy( len, 'float64', rand );
5561
out = new Float64Array( 2 );
5662
return benchmark;
5763

lib/node_modules/@stdlib/blas/ext/base/dnannsumkbn2/benchmark/benchmark.ndarray.native.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@ var opts = {
4242

4343
// FUNCTIONS //
4444

45+
/**
46+
* Returns a random number.
47+
*
48+
* @private
49+
* @returns {number} random number
50+
*/
51+
function rand() {
52+
if ( bernoulli( 0.8 ) > 0 ) {
53+
return discreteUniform( -10.0, 10.0 );
54+
}
55+
return NaN;
56+
}
57+
4558
/**
4659
* Creates a benchmark function.
4760
*
@@ -53,14 +66,7 @@ function createBenchmark( len ) {
5366
var out;
5467
var x;
5568

56-
function clbk() {
57-
if ( bernoulli( 0.7 ) > 0 ) {
58-
return discreteUniform( -10, 10 );
59-
}
60-
return NaN;
61-
}
62-
63-
x = filledarrayBy( len, 'float64', clbk );
69+
x = filledarrayBy( len, 'float64', rand );
6470
out = new Float64Array( 2 );
6571
return benchmark;
6672

lib/node_modules/@stdlib/blas/ext/base/dnannsumkbn2/benchmark/c/benchmark.length.c

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
#include "stdlib/blas/ext/base/dnannsumkbn2.h"
20+
#include "stdlib/blas/base/shared.h"
2021
#include <stdlib.h>
2122
#include <stdio.h>
2223
#include <math.h>
@@ -94,10 +95,10 @@ static double rand_double( void ) {
9495
* @param len array length
9596
* @return elapsed time in seconds
9697
*/
97-
static double benchmark( int iterations, int len ) {
98+
static double benchmark1( int iterations, int len ) {
9899
double elapsed;
99100
double x[ len ];
100-
int64_t n;
101+
CBLAS_INT n;
101102
double v;
102103
double t;
103104
int i;
@@ -126,6 +127,45 @@ static double benchmark( int iterations, int len ) {
126127
return elapsed;
127128
}
128129

130+
/**
131+
* Runs a benchmark.
132+
*
133+
* @param iterations number of iterations
134+
* @param len array length
135+
* @return elapsed time in seconds
136+
*/
137+
static double benchmark2( int iterations, int len ) {
138+
double elapsed;
139+
double x[ len ];
140+
CBLAS_INT n;
141+
double v;
142+
double t;
143+
int i;
144+
145+
for ( i = 0; i < len; i++ ) {
146+
if ( rand_double() < 0.2 ) {
147+
x[ i ] = 0.0 / 0.0; // NaN
148+
} else {
149+
x[ i ] = ( rand_double() * 20000.0 ) - 10000.0;
150+
}
151+
}
152+
v = 0.0;
153+
n = 0;
154+
t = tic();
155+
for ( i = 0; i < iterations; i++ ) {
156+
v = stdlib_strided_dnannsumkbn2_ndarray( len, x, 1, 0, &n );
157+
if ( v != v || n < 0 ) {
158+
printf( "should not return NaN\n" );
159+
break;
160+
}
161+
}
162+
elapsed = tic() - t;
163+
if ( v != v || n < 0 ) {
164+
printf( "should not return NaN\n" );
165+
}
166+
return elapsed;
167+
}
168+
129169
/**
130170
* Main execution sequence.
131171
*/
@@ -148,7 +188,18 @@ int main( void ) {
148188
for ( j = 0; j < REPEATS; j++ ) {
149189
count += 1;
150190
printf( "# c::%s:len=%d\n", NAME, len );
151-
elapsed = benchmark( iter, len );
191+
elapsed = benchmark1( iter, len );
192+
print_results( iter, elapsed );
193+
printf( "ok %d benchmark finished\n", count );
194+
}
195+
}
196+
for ( i = MIN; i <= MAX; i++ ) {
197+
len = pow( 10, i );
198+
iter = ITERATIONS / pow( 10, i-1 );
199+
for ( j = 0; j < REPEATS; j++ ) {
200+
count += 1;
201+
printf( "# c::%s:ndarray:len=%d\n", NAME, len );
202+
elapsed = benchmark2( iter, len );
152203
print_results( iter, elapsed );
153204
printf( "ok %d benchmark finished\n", count );
154205
}

0 commit comments

Comments
 (0)