Skip to content

Commit a7d2960

Browse files
committed
feat: add support for returning a normalized index
1 parent 4f15a40 commit a7d2960

10 files changed

Lines changed: 174 additions & 18 deletions

File tree

lib/node_modules/@stdlib/ndarray/base/ind/README.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,12 @@ idx = ind( 10, 9, 'throw' );
5757
// throws <RangeError>
5858
```
5959

60-
The function supports the following `modes`:
60+
The function supports the following modes:
6161

62-
- `throw`: specifies that the function should throw an error when an index is outside the interval `[0,max]`.
63-
- `wrap`: specifies that the function should wrap around an index using modulo arithmetic.
64-
- `clamp`: specifies that the function should set an index less than `0` to `0` (minimum index) and set an index greater than `max` to `max`.
62+
- **throw**: specifies that the function should throw an error when an index is outside the interval `[0, max]`.
63+
- **normalize**: specifies that the function should normalize negative indices and throw an error when an index is outside the interval `[-max-1, max]`.
64+
- **wrap**: specifies that the function should wrap around an index using modulo arithmetic.
65+
- **clamp**: specifies that the function should set an index less than `0` to `0` (minimum index) and set an index greater than `max` to `max`.
6566

6667
```javascript
6768
var idx = ind( 2, 9, 'wrap' );
@@ -81,6 +82,12 @@ idx = ind( 10, 9, 'clamp' );
8182

8283
idx = ind( -1, 9, 'clamp' );
8384
// returns 0
85+
86+
idx = ind( 2, 9, 'normalize' );
87+
// returns 2
88+
89+
idx = ind( -4, 9, 'normalize' );
90+
// returns 6
8491
```
8592

8693
</section>

lib/node_modules/@stdlib/ndarray/base/ind/benchmark/benchmark.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,24 @@ bench( pkg+':mode=throw', function benchmark( b ) {
9292
b.pass( 'benchmark finished' );
9393
b.end();
9494
});
95+
96+
bench( pkg+':mode=normalize', function benchmark( b ) {
97+
var out;
98+
var idx;
99+
var i;
100+
101+
b.tic();
102+
for ( i = 0; i < b.iterations; i++ ) {
103+
idx = floor( randu()*20.0 ) - 10.0;
104+
out = ind( idx, 10, 'normalize' );
105+
if ( out !== out ) {
106+
b.fail( 'should not return NaN' );
107+
}
108+
}
109+
b.toc();
110+
if ( !isNonNegativeInteger( out ) ) {
111+
b.fail( 'should return a nonnegative integer' );
112+
}
113+
b.pass( 'benchmark finished' );
114+
b.end();
115+
});

lib/node_modules/@stdlib/ndarray/base/ind/benchmark/c/benchmark.c

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
/**
3636
* Prints the TAP version.
3737
*/
38-
void print_version() {
38+
void print_version( void ) {
3939
printf( "TAP version 13\n" );
4040
}
4141

@@ -73,7 +73,7 @@ void print_results( double elapsed ) {
7373
*
7474
* @return clock time
7575
*/
76-
double tic() {
76+
double tic( void ) {
7777
struct timeval now;
7878
gettimeofday( &now, NULL );
7979
return (double)now.tv_sec + (double)now.tv_usec/1.0e6;
@@ -84,7 +84,7 @@ double tic() {
8484
*
8585
* @return random double
8686
*/
87-
double rand_double() {
87+
double rand_double( void ) {
8888
int r = rand();
8989
return (double)r / ( (double)RAND_MAX + 1.0 );
9090
}
@@ -94,7 +94,7 @@ double rand_double() {
9494
*
9595
* @return elapsed time in seconds
9696
*/
97-
double benchmark1() {
97+
double benchmark1( void ) {
9898
double elapsed;
9999
int64_t idx;
100100
double t;
@@ -121,7 +121,7 @@ double benchmark1() {
121121
*
122122
* @return elapsed time in seconds
123123
*/
124-
double benchmark2() {
124+
double benchmark2( void ) {
125125
double elapsed;
126126
int64_t idx;
127127
double t;
@@ -148,7 +148,7 @@ double benchmark2() {
148148
*
149149
* @return elapsed time in seconds
150150
*/
151-
double benchmark3() {
151+
double benchmark3( void ) {
152152
double elapsed;
153153
int64_t idx;
154154
double t;
@@ -170,6 +170,33 @@ double benchmark3() {
170170
return elapsed;
171171
}
172172

173+
/**
174+
* Runs a benchmark.
175+
*
176+
* @return elapsed time in seconds
177+
*/
178+
double benchmark4( void ) {
179+
double elapsed;
180+
int64_t idx;
181+
double t;
182+
int i;
183+
184+
t = tic();
185+
for ( i = 0; i < ITERATIONS; i++ ) {
186+
idx = (int64_t)( (rand_double()*100.0) - 50.0 );
187+
idx = stdlib_ndarray_ind( idx, 10, STDLIB_NDARRAY_INDEX_NORMALIZE );
188+
if ( idx < -1 ) {
189+
printf( "unexpected result\n" );
190+
break;
191+
}
192+
}
193+
elapsed = tic() - t;
194+
if ( idx < -1 ) {
195+
printf( "unexpected result\n" );
196+
}
197+
return elapsed;
198+
}
199+
173200
/**
174201
* Main execution sequence.
175202
*/
@@ -205,5 +232,12 @@ int main( void ) {
205232
print_results( elapsed );
206233
printf( "ok %d benchmark finished\n", count );
207234
}
235+
for ( i = 0; i < REPEATS; i++ ) {
236+
count += 1;
237+
printf( "# c::native::%s:mode=normalize\n", NAME );
238+
elapsed = benchmark4();
239+
print_results( elapsed );
240+
printf( "ok %d benchmark finished\n", count );
241+
}
208242
print_summary( count, count );
209243
}

lib/node_modules/@stdlib/ndarray/base/ind/docs/repl.txt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111
Maximum index value.
1212

1313
mode: string
14-
Specifies how to handle an index outside the interval [0,max]. If equal
15-
to 'throw', the function throws an error. If equal to 'wrap', the
16-
function wraps around an index using modulo arithmetic. If equal to
17-
'clamp', the function sets an index to either `0` (minimum index) or the
18-
maximum index.
14+
Specifies how to handle an index outside the interval [0, max]. If equal
15+
to 'throw', the function throws an error. If equal to 'normalize', the
16+
function throws an error if provided an out-of-bounds normalized index.
17+
If equal to 'wrap', the function wraps around an index using modulo
18+
arithmetic. If equal to 'clamp', the function sets an index to either 0
19+
(minimum index) or the maximum index.
1920

2021
Returns
2122
-------
@@ -38,6 +39,10 @@
3839
0
3940
> idx = {{alias}}( 13, 10, 'clamp' )
4041
10
42+
> idx = {{alias}}( 2, 10, 'normalize' )
43+
2
44+
> idx = {{alias}}( -4, 10, 'normalize' )
45+
7
4146

4247
See Also
4348
--------

lib/node_modules/@stdlib/ndarray/base/ind/docs/types/index.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ import { Mode } from '@stdlib/types/ndarray';
6161
*
6262
* idx = ind( -1, 9, 'throw' );
6363
* // throws <RangeError>
64+
*
65+
* @example
66+
* var idx = ind( 2, 9, 'normalize' );
67+
* // returns 2
68+
*
69+
* idx = ind( -5, 9, 'normalize' );
70+
* // returns 5
71+
*
72+
* idx = ind( -20, 9, 'normalize' );
73+
* // throws <RangeError>
6474
*/
6575
declare function ind( idx: number, max: number, mode: Mode ): number;
6676

lib/node_modules/@stdlib/ndarray/base/ind/lib/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@
5858
*
5959
* idx = ind( -1, 10, 'throw' );
6060
* // throws <RangeError>
61+
*
62+
* @example
63+
* var ind = require( '@stdlib/ndarray/base/ind' );
64+
*
65+
* var idx = ind( 1, 10, 'normalize' );
66+
* // returns 1
67+
*
68+
* idx = ind( -4, 10, 'normalize' );
69+
* // returns 7
70+
*
71+
* idx = ind( -100, 10, 'normalize' );
72+
* // throws <RangeError>
6173
*/
6274

6375
// MODULES //

lib/node_modules/@stdlib/ndarray/base/ind/lib/main.js

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

2323
var clampIndex = require( '@stdlib/ndarray/base/clamp-index' );
2424
var wrapIndex = require( '@stdlib/ndarray/base/wrap-index' );
25+
var normalizeIndex = require( '@stdlib/ndarray/base/normalize-index' );
2526
var format = require( '@stdlib/string/format' );
2627

2728

@@ -65,18 +66,33 @@ var format = require( '@stdlib/string/format' );
6566
*
6667
* idx = ind( -1, 9, 'throw' );
6768
* // throws <RangeError>
69+
*
70+
* @example
71+
* var idx = ind( 1, 10, 'normalize' );
72+
* // returns 1
73+
*
74+
* idx = ind( -4, 10, 'normalize' );
75+
* // returns 7
76+
*
77+
* idx = ind( -100, 10, 'normalize' );
78+
* // throws <RangeError>
6879
*/
6980
function ind( idx, max, mode ) {
81+
var index;
7082
if ( mode === 'clamp' ) {
7183
return clampIndex( idx, max );
7284
}
7385
if ( mode === 'wrap' ) {
7486
return wrapIndex( idx, max );
7587
}
76-
if ( idx < 0 || idx > max ) {
77-
throw new RangeError( format( 'invalid argument. Index must be on the interval: [0, %d]. Value: `%d`.', max, idx ) );
88+
index = idx;
89+
if ( mode === 'normalize' ) {
90+
index = normalizeIndex( index, max );
91+
}
92+
if ( index < 0 || index > max ) {
93+
throw new RangeError( format( 'invalid argument. Index must resolve to a value on the interval: [0, %d]. Value: `%d`.', max, idx ) );
7894
}
79-
return idx;
95+
return index;
8096
}
8197

8298

lib/node_modules/@stdlib/ndarray/base/ind/manifest.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"libpath": [],
3535
"dependencies": [
3636
"@stdlib/ndarray/base/clamp-index",
37+
"@stdlib/ndarray/base/normalize-index",
3738
"@stdlib/ndarray/base/wrap-index",
3839
"@stdlib/ndarray/index-modes"
3940
]

lib/node_modules/@stdlib/ndarray/base/ind/src/main.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "stdlib/ndarray/index_modes.h"
2121
#include "stdlib/ndarray/base/wrap_index.h"
2222
#include "stdlib/ndarray/base/clamp_index.h"
23+
#include "stdlib/ndarray/base/normalize_index.h"
2324
#include <stdint.h>
2425

2526
/**
@@ -54,6 +55,13 @@
5455
*
5556
* int64_t idx = stdlib_ndarray_ind( 10, 8, STDLIB_NDARRAY_INDEX_ERROR );
5657
* // returns -1
58+
*
59+
* @example
60+
* #include "stdlib/ndarray/index_modes.h"
61+
* #include "stdlib/ndarray/base/ind.h"
62+
*
63+
* int64_t idx = stdlib_ndarray_ind( -4, 8, STDLIB_NDARRAY_INDEX_NORMALIZE );
64+
* // returns 5
5765
*/
5866
int64_t stdlib_ndarray_ind( const int64_t idx, const int64_t max, const enum STDLIB_NDARRAY_INDEX_MODE mode ) {
5967
if ( mode == STDLIB_NDARRAY_INDEX_CLAMP ) {
@@ -62,6 +70,9 @@ int64_t stdlib_ndarray_ind( const int64_t idx, const int64_t max, const enum STD
6270
if ( mode == STDLIB_NDARRAY_INDEX_WRAP ) {
6371
return stdlib_ndarray_wrap_index( idx, max );
6472
}
73+
if ( mode == STDLIB_NDARRAY_INDEX_NORMALIZE ) {
74+
return stdlib_ndarray_normalize_index( idx, max );
75+
}
6576
if ( idx < 0 || idx > max ) {
6677
return -1; // out-of-bounds
6778
}

lib/node_modules/@stdlib/ndarray/base/ind/test/test.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,42 @@ tape( 'when the `mode` is equal to `throw`, the function throws an error when a
9696
};
9797
}
9898
});
99+
100+
tape( 'when the `mode` is equal to `normalize`, the function resolves a nonnegative index when on the interval [-max-1,max]', function test( t ) {
101+
var expected;
102+
var max;
103+
var idx;
104+
var i;
105+
106+
max = 10;
107+
for ( i = -max-1; i < max+1; i++ ) {
108+
idx = ind( i, max, 'normalize' );
109+
if ( i < 0 ) {
110+
expected = i + max + 1;
111+
} else {
112+
expected = i;
113+
}
114+
t.strictEqual( idx, expected, 'returns expected value' );
115+
}
116+
t.end();
117+
});
118+
119+
tape( 'when the `mode` is equal to `normalize`, the function throws an error when a provided index is outside the interval [-max-1,max]', function test( t ) {
120+
var max;
121+
var i;
122+
123+
max = 10;
124+
for ( i = -100; i < -max-1; i++ ) {
125+
t.throws( badValue( i ), RangeError, 'throws an range error when provided '+i );
126+
}
127+
for ( i = max+1; i < 100; i++ ) {
128+
t.throws( badValue( i ), RangeError, 'throws an range error when provided '+i );
129+
}
130+
t.end();
131+
132+
function badValue( value ) {
133+
return function badValue() {
134+
ind( value, max, 'normalize' );
135+
};
136+
}
137+
});

0 commit comments

Comments
 (0)