Skip to content

Commit ad21e7c

Browse files
authored
feat: add C implementation for stats/base/ndarray/dvariancetk
PR-URL: #14794 Reviewed-by: Athan Reines <kgryte@gmail.com> Ref: #14034
1 parent acbf27e commit ad21e7c

20 files changed

Lines changed: 1986 additions & 180 deletions

File tree

lib/node_modules/@stdlib/stats/base/ndarray/dvariancetk/README.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,176 @@ console.log( v );
168168

169169
<!-- /.examples -->
170170

171+
<!-- C interface documentation. -->
172+
173+
* * *
174+
175+
<section class="c">
176+
177+
## C APIs
178+
179+
<!-- Section to include introductory text. Make sure to keep an empty line after the intro `section` element and another before the `/section` close. -->
180+
181+
<section class="intro">
182+
183+
</section>
184+
185+
<!-- /.intro -->
186+
187+
<!-- C usage documentation. -->
188+
189+
<section class="usage">
190+
191+
### Usage
192+
193+
```c
194+
#include "stdlib/stats/base/ndarray/dvariancetk.h"
195+
```
196+
197+
#### stdlib_stats_dvariancetk( arrays )
198+
199+
Computes the variance of a one-dimensional double-precision floating-point ndarray using a one-pass textbook algorithm.
200+
201+
```c
202+
#include "stdlib/ndarray/ctor.h"
203+
#include "stdlib/ndarray/dtypes.h"
204+
#include "stdlib/ndarray/index_modes.h"
205+
#include "stdlib/ndarray/orders.h"
206+
#include "stdlib/ndarray/base/bytes_per_element.h"
207+
#include <stdint.h>
208+
209+
// Create an ndarray:
210+
const double data[] = { 1.0, -2.0, 2.0 };
211+
int64_t shape[] = { 3 };
212+
int64_t strides[] = { STDLIB_NDARRAY_FLOAT64_BYTES_PER_ELEMENT };
213+
int8_t submodes[] = { STDLIB_NDARRAY_INDEX_ERROR };
214+
215+
struct ndarray *x = stdlib_ndarray_allocate( STDLIB_NDARRAY_FLOAT64, (uint8_t *)data, 1, shape, strides, 0, STDLIB_NDARRAY_ROW_MAJOR, STDLIB_NDARRAY_INDEX_ERROR, 1, submodes );
216+
217+
// Create an ndarray for specifying the degrees of freedom adjustment:
218+
const double cdata[] = { 1.0 };
219+
int64_t cstrides[] = { 0 };
220+
struct ndarray *corr = stdlib_ndarray_allocate( STDLIB_NDARRAY_FLOAT64, (uint8_t *)cdata, 0, NULL, cstrides, 0, STDLIB_NDARRAY_ROW_MAJOR, STDLIB_NDARRAY_INDEX_ERROR, 1, submodes );
221+
222+
// Compute the result:
223+
const struct ndarray *arrays[] = { x, corr };
224+
double v = stdlib_stats_dvariancetk( arrays );
225+
// returns ~4.3333
226+
227+
// Free allocated memory:
228+
stdlib_ndarray_free( x );
229+
stdlib_ndarray_free( corr );
230+
```
231+
232+
The function accepts the following arguments:
233+
234+
- **arrays**: `[in] struct ndarray**` list containing the following ndarrays:
235+
236+
- `[in] struct ndarray*` a one-dimensional input ndarray.
237+
- `[in] struct ndarray*` a zero-dimensional ndarray specifying the degrees of freedom adjustment. Providing a non-zero degrees of freedom adjustment has the effect of adjusting the divisor during the calculation of the [variance][variance] according to `N-c` where `N` is the number of elements in the input ndarray and `c` corresponds to the provided degrees of freedom adjustment. When computing the [variance][variance] of a population, setting this parameter to `0` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the corrected sample [variance][variance], setting this parameter to `1` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction).
238+
239+
```c
240+
double stdlib_stats_dvariancetk( const struct ndarray *arrays[] );
241+
```
242+
243+
</section>
244+
245+
<!-- /.usage -->
246+
247+
<!-- C API usage notes. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
248+
249+
<section class="notes">
250+
251+
</section>
252+
253+
<!-- /.notes -->
254+
255+
<!-- C API usage examples. -->
256+
257+
<section class="examples">
258+
259+
### Examples
260+
261+
```c
262+
#include "stdlib/stats/base/ndarray/dvariancetk.h"
263+
#include "stdlib/ndarray/ctor.h"
264+
#include "stdlib/ndarray/dtypes.h"
265+
#include "stdlib/ndarray/index_modes.h"
266+
#include "stdlib/ndarray/orders.h"
267+
#include "stdlib/ndarray/base/bytes_per_element.h"
268+
#include <stdint.h>
269+
#include <stdlib.h>
270+
#include <stdio.h>
271+
272+
int main( void ) {
273+
// Create a data buffer:
274+
const double data[] = { 1.0, -2.0, 3.0, -4.0, 5.0, -6.0, 7.0, -8.0 };
275+
276+
// Specify the number of array dimensions:
277+
const int64_t ndims = 1;
278+
279+
// Specify the array shape:
280+
int64_t shape[] = { 4 };
281+
282+
// Specify the array strides:
283+
int64_t strides[] = { 2*STDLIB_NDARRAY_FLOAT64_BYTES_PER_ELEMENT };
284+
285+
// Specify the byte offset:
286+
const int64_t offset = 0;
287+
288+
// Specify the array order:
289+
const enum STDLIB_NDARRAY_ORDER order = STDLIB_NDARRAY_ROW_MAJOR;
290+
291+
// Specify the index mode:
292+
const enum STDLIB_NDARRAY_INDEX_MODE imode = STDLIB_NDARRAY_INDEX_ERROR;
293+
294+
// Specify the subscript index modes:
295+
int8_t submodes[] = { STDLIB_NDARRAY_INDEX_ERROR };
296+
const int64_t nsubmodes = 1;
297+
298+
// Create an ndarray:
299+
struct ndarray *x = stdlib_ndarray_allocate( STDLIB_NDARRAY_FLOAT64, (uint8_t *)data, ndims, shape, strides, offset, order, imode, nsubmodes, submodes );
300+
if ( x == NULL ) {
301+
fprintf( stderr, "Error allocating memory.\n" );
302+
exit( 1 );
303+
}
304+
305+
// Create a data buffer for an ndarray specifying the degrees of freedom adjustment:
306+
const double cdata[] = { 1.0 };
307+
308+
// Specify the array strides:
309+
int64_t cstrides[] = { 0 };
310+
311+
// Create an ndarray for the degrees of freedom adjustment:
312+
struct ndarray *corr = stdlib_ndarray_allocate( STDLIB_NDARRAY_FLOAT64, (uint8_t *)cdata, 0, NULL, cstrides, 0, order, imode, nsubmodes, submodes );
313+
if ( corr == NULL ) {
314+
fprintf( stderr, "Error allocating memory.\n" );
315+
exit( 1 );
316+
}
317+
318+
// Define a list of ndarrays:
319+
const struct ndarray *arrays[] = { x, corr };
320+
321+
// Compute the result:
322+
double v = stdlib_stats_dvariancetk( arrays );
323+
324+
// Print the result:
325+
printf( "result: %lf\n", v );
326+
327+
// Free allocated memory:
328+
stdlib_ndarray_free( x );
329+
stdlib_ndarray_free( corr );
330+
}
331+
```
332+
333+
</section>
334+
335+
<!-- /.examples -->
336+
337+
</section>
338+
339+
<!-- /.c -->
340+
171341
* * *
172342
173343
<section class="references">

lib/node_modules/@stdlib/stats/base/ndarray/dvariancetk/benchmark/benchmark.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ var pow = require( '@stdlib/math/base/special/pow' );
2727
var scalar2ndarray = require( '@stdlib/ndarray/from-scalar' );
2828
var format = require( '@stdlib/string/format' );
2929
var pkg = require( './../package.json' ).name;
30-
var dvariancetk = require( './../lib' );
30+
var dvariancetk = require( './../lib/main.js' );
3131

3232

3333
// VARIABLES //
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2026 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 resolve = require( 'path' ).resolve;
24+
var bench = require( '@stdlib/bench' );
25+
var uniform = require( '@stdlib/random/uniform' );
26+
var scalar2ndarray = require( '@stdlib/ndarray/from-scalar' );
27+
var isnan = require( '@stdlib/math/base/assert/is-nan' );
28+
var pow = require( '@stdlib/math/base/special/pow' );
29+
var format = require( '@stdlib/string/format' );
30+
var tryRequire = require( '@stdlib/utils/try-require' );
31+
var pkg = require( './../package.json' ).name;
32+
33+
34+
// VARIABLES //
35+
36+
var dvariancetk = tryRequire( resolve( __dirname, './../lib/native.js' ) );
37+
var opts = {
38+
'skip': ( dvariancetk instanceof Error )
39+
};
40+
var options = {
41+
'dtype': 'float64'
42+
};
43+
44+
45+
// FUNCTIONS //
46+
47+
/**
48+
* Creates a benchmark function.
49+
*
50+
* @private
51+
* @param {PositiveInteger} len - array length
52+
* @returns {Function} benchmark function
53+
*/
54+
function createBenchmark( len ) {
55+
var correction = scalar2ndarray( 1.0, options );
56+
var x = uniform( [ len ], -10.0, 10.0, options );
57+
return benchmark;
58+
59+
/**
60+
* Benchmark function.
61+
*
62+
* @private
63+
* @param {Benchmark} b - benchmark instance
64+
*/
65+
function benchmark( b ) {
66+
var v;
67+
var i;
68+
69+
b.tic();
70+
for ( i = 0; i < b.iterations; i++ ) {
71+
v = dvariancetk( [ x, correction ] );
72+
if ( isnan( v ) ) {
73+
b.fail( 'should not return NaN' );
74+
}
75+
}
76+
b.toc();
77+
if ( isnan( v ) ) {
78+
b.fail( 'should not return NaN' );
79+
}
80+
b.pass( 'benchmark finished' );
81+
b.end();
82+
}
83+
}
84+
85+
86+
// MAIN //
87+
88+
/**
89+
* Main execution sequence.
90+
*
91+
* @private
92+
*/
93+
function main() {
94+
var len;
95+
var min;
96+
var max;
97+
var f;
98+
var i;
99+
100+
min = 1; // 10^min
101+
max = 6; // 10^max
102+
103+
for ( i = min; i <= max; i++ ) {
104+
len = pow( 10, i );
105+
f = createBenchmark( len );
106+
bench( format( '%s::native:len=%d', pkg, len ), opts, f );
107+
}
108+
}
109+
110+
main();

0 commit comments

Comments
 (0)