Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add tests for negative values in math/base/special/fmod #2600

Merged
merged 8 commits into from
Jul 15, 2024
1 change: 1 addition & 0 deletions lib/node_modules/@stdlib/math/base/special/fmod/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ double stdlib_base_fmod( const double x, const double y );

```c
#include "stdlib/math/base/special/fmod.h"
#include <stdlib.h>
#include <stdio.h>

int main( void ) {
Expand Down
88 changes: 43 additions & 45 deletions lib/node_modules/@stdlib/math/base/special/fmod/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
*
* @param x dividend
* @param y divisor
* @returns remainder
* @return remainder
*
* @example
* double out = stdlib_base_fmod( 8.9, 3.0 );
Expand Down Expand Up @@ -86,14 +86,14 @@ double stdlib_base_fmod( const double x, const double y ) {
// Purge off exception values
if ( ( hy | ly ) == 0 || ( hx >= STDLIB_CONSTANT_FLOAT64_HIGH_WORD_EXPONENT_MASK ) || ( ( hy | ( ( ly | -ly ) >> 31 ) ) > STDLIB_CONSTANT_FLOAT64_HIGH_WORD_EXPONENT_MASK ) ) {
// y=0, x not finite, or y is NaN
return ( x * y ) / ( x * y );
return ( x * y ) / ( x * y );
}
if ( hx <= hy ) {
if ( ( hx < hy ) || ( lx < ly ) ){
if ( ( hx < hy ) || ( lx < ly ) ){
// |x|<|y| return x
return x;
}
if ( lx == ly ) {
if ( lx == ly ) {
// |x|=|y| return x*0
return ZERO[ (uint32_t)sx >> 31 ];
}
Expand All @@ -102,86 +102,84 @@ double stdlib_base_fmod( const double x, const double y ) {
// Determine ix = ilogb(x)
if ( hx < 0x00100000 ) {
// subnormal x
if ( hx == 0 ) {
if ( hx == 0 ) {
ix = -1043;
for ( i = lx; i > 0; i <<= 1 ) {
ix -=1;
}
} else {
} else {
ix = STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT;
for ( i = ( hx << 11 ); i > 0; i <<= 1 ) {
ix -=1;
}
}
}
} else {
ix = ( hx >> 20 ) - STDLIB_CONSTANT_FLOAT64_EXPONENT_BIAS;
}

// determine iy = ilogb(y)
// determine iy = ilogb(y)
if ( hy < 0x00100000 ) {
// subnormal y
if ( hy == 0 ) {
if ( hy == 0 ) {
iy = -1043;
for ( i = ly; i > 0; i <<= 1 ) {
iy -=1;
}
} else {
} else {
iy = STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT;
for ( i = ( hy << 11 ); i > 0; i <<= 1) {
iy -=1;
}
}
}
} else {
iy = ( hy >> 20 ) - STDLIB_CONSTANT_FLOAT64_EXPONENT_BIAS;
}

// set up {hx,lx}, {hy,ly} and align y to x
// set up {hx,lx}, {hy,ly} and align y to x
if ( ix >= STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT ) {
hx = 0x00100000 | ( STDLIB_CONSTANT_FLOAT64_HIGH_WORD_SIGNIFICAND_MASK & hx );
}
else {
} else {
// subnormal x, shift x to normal
n = STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT - ix;
if ( n <= 31 ) {
hx = ( (uint32_t)hx << n ) | ( lx >> ( 32 - n ) );
lx <<= n;
n = STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT - ix;
if ( n <= 31 ) {
hx = ( (uint32_t)hx << n ) | ( lx >> ( 32 - n ) );
lx <<= n;
} else {
hx = lx << ( n - 32 );
lx = 0;
}
}
}
if ( iy >= STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT ) {
hy = 0x00100000 | ( STDLIB_CONSTANT_FLOAT64_HIGH_WORD_SIGNIFICAND_MASK & hy );
}
else {
} else {
// subnormal y, shift y to normal
n = STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT - iy;
if ( n <= 31 ) {
hy = ( (uint32_t)hy << n ) | ( ly >> ( 32 - n ) );
ly <<= n;
} else {
n = STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT - iy;
if ( n <= 31 ) {
hy = ( (uint32_t)hy << n ) | ( ly >> ( 32 - n ) );
ly <<= n;
} else {
hy = ly << ( n - 32 );
ly = 0;
}
}
}
n = ix - iy;
while ( n-- ) {
hz = hx - hy;
hz = hx - hy;
lz = lx - ly;
if ( lx < ly ) {
hz -= 1;
}
if ( hz < 0 ) {
if ( hz < 0 ) {
hx = hx + hx + ( lx >> 31 );
lx += lx;
}
else {
if ( ( hz | lz ) == 0 )
// return sign(x)*0
return ZERO[ (uint32_t)sx >> 31 ];
hx = hz + hz + ( lz >> 31 );
} else {
if ( ( hz | lz ) == 0 ) {
// return sign(x)*0
return ZERO[ (uint32_t)sx >> 31 ];
}
hx = hz + hz + ( lz >> 31 );
lx = lz + lz;
}
}
}
hz = hx - hy;
lz = lx - ly;
Expand All @@ -193,34 +191,34 @@ double stdlib_base_fmod( const double x, const double y ) {
lx = lz;
}

// Convert back to floating value and restore the sign
// Convert back to floating value and restore the sign
if ( ( hx | lx ) == 0 ) {
// return sign(x)*0
return ZERO[ (uint32_t)sx >> 31 ];
}
while ( hx < 0x00100000 ) {
// normalize x
hx = hx + hx + ( lx >> 31 );
hx = hx + hx + ( lx >> 31 );
lx += lx;
iy -= 1;
iy -= 1;
}
if ( iy >= STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT ) {
// normalize output
hx = ( ( hx - 0x00100000 ) | ( ( iy + STDLIB_CONSTANT_FLOAT64_EXPONENT_BIAS ) << 20 ) );
hx = ( ( hx - 0x00100000 ) | ( ( iy + STDLIB_CONSTANT_FLOAT64_EXPONENT_BIAS ) << 20 ) );
stdlib_base_float64_from_words( (uint32_t)( hx | sx ), lx, &xc );
} else {
// subnormal output
n = STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT - iy;
if ( n <= 20 ) {
n = STDLIB_CONSTANT_FLOAT64_MIN_BASE2_EXPONENT - iy;
if ( n <= 20 ) {
lx = ( lx >> n ) | ( (uint32_t)hx << ( 32 - n ) );
hx >>= n;
} else if ( n <= 31 ) {
} else if ( n <= 31 ) {
lx = ( hx << ( 32 - n ) ) | ( lx >> n );
hx = sx;
} else {
} else {
lx = hx >> ( n - 32 );
hx = sx;
}
}
stdlib_base_float64_from_words( (uint32_t)( hx | sx ), lx, &xc );

// create necessary signal
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ julia> gen( x, y, \"data.json\" );
```
"""
function gen( x, y, name )
z = Array{Float64}( undef, length(x) );
z = Array{Float64}( undef, length( x ) );
for i in eachindex(x)
z[ i ] = mod(x[i], y[i])
z[ i ] = rem( x[ i ], y[ i ] )
end

# Store data to be written to file as a collection:
Expand Down Expand Up @@ -85,3 +85,18 @@ gen( x, y, "small_large.json" );
x = rand( 5001 ) .* 5e20;
y = rand( 5001 ) .* 10;
gen( x, y, "large_small.json" );

# x positive, y negative:
x = range( 1.0, stop = 709.78, length = 1000 );
y = range( -709.78, stop = -1.0, length = 1000 );
gen( x, y, "positive_negative.json" );

# x negative, y positive:
x = range( -709.78, stop = -1.0, length = 1000 );
y = range( 1.0, stop = 709.78, length = 1000 );
gen( x, y, "negative_positive.json" );

# x negative, y negative:
x = range( -709.78, stop = -1.0, length = 1000 );
y = range( -709.78, stop = -1.0, length = 1000 );
gen( x, y, "negative_negative.json" );

Large diffs are not rendered by default.

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions lib/node_modules/@stdlib/math/base/special/fmod/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ var subnormalResults = require( './fixtures/julia/subnormal_results.json' );
var smallSmall = require( './fixtures/julia/small_small.json' );
var smallLarge = require( './fixtures/julia/small_large.json' );
var largeSmall = require( './fixtures/julia/large_small.json' );
var negativePositive = require( './fixtures/julia/negative_positive.json' );
var positiveNegative = require( './fixtures/julia/positive_negative.json' );
var negativeNegative = require( './fixtures/julia/negative_negative.json' );


// TESTS //
Expand Down Expand Up @@ -109,6 +112,57 @@ tape( 'the function evaluates the modulus function (small `x`, small `y`)', func
t.end();
});

tape( 'the function evaluates the modulus function (positive `x`, negative `y`)', function test( t ) {
var expected;
var actual;
var x;
var y;
var i;

x = positiveNegative.x;
y = positiveNegative.y;
expected = positiveNegative.expected;
for ( i = 0; i < x.length; i++ ) {
actual = fmod( x[ i ], y[ i ] );
t.equal( actual, expected[ i ], 'fmod('+x[ i ]+','+y[ i ]+') returns '+expected[ i ] );
}
t.end();
});

tape( 'the function evaluates the modulus function (negative `x`, positive `y`)', function test( t ) {
var expected;
var actual;
var x;
var y;
var i;

x = negativePositive.x;
y = negativePositive.y;
expected = negativePositive.expected;
for ( i = 0; i < x.length; i++ ) {
actual = fmod( x[ i ], y[ i ] );
t.equal( actual, expected[ i ], 'fmod('+x[ i ]+','+y[ i ]+') returns '+expected[ i ] );
}
t.end();
});

tape( 'the function evaluates the modulus function (negative `x`, negative `y`)', function test( t ) {
var expected;
var actual;
var x;
var y;
var i;

x = negativeNegative.x;
y = negativeNegative.y;
expected = negativeNegative.expected;
for ( i = 0; i < x.length; i++ ) {
actual = fmod( x[ i ], y[ i ] );
t.equal( actual, expected[ i ], 'fmod('+x[ i ]+','+y[ i ]+') returns '+expected[ i ] );
}
t.end();
});

tape( 'the function returns `NaN` if provided `NaN` for `y`', function test( t ) {
var v;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ var subnormalResults = require( './fixtures/julia/subnormal_results.json' );
var smallSmall = require( './fixtures/julia/small_small.json' );
var smallLarge = require( './fixtures/julia/small_large.json' );
var largeSmall = require( './fixtures/julia/large_small.json' );
var negativePositive = require( './fixtures/julia/negative_positive.json' );
var positiveNegative = require( './fixtures/julia/positive_negative.json' );
var negativeNegative = require( './fixtures/julia/negative_negative.json' );


// TESTS //
Expand Down Expand Up @@ -118,6 +121,57 @@ tape( 'the function evaluates the modulus function (small `x`, small `y`)', opts
t.end();
});

tape( 'the function evaluates the modulus function (positive `x`, negative `y`)', opts, function test( t ) {
var expected;
var actual;
var x;
var y;
var i;

x = positiveNegative.x;
y = positiveNegative.y;
expected = positiveNegative.expected;
for ( i = 0; i < x.length; i++ ) {
actual = fmod( x[ i ], y[ i ] );
t.equal( actual, expected[ i ], 'fmod('+x[ i ]+','+y[ i ]+') returns '+expected[ i ] );
}
t.end();
});

tape( 'the function evaluates the modulus function (negative `x`, positive `y`)', opts, function test( t ) {
var expected;
var actual;
var x;
var y;
var i;

x = negativePositive.x;
y = negativePositive.y;
expected = negativePositive.expected;
for ( i = 0; i < x.length; i++ ) {
actual = fmod( x[ i ], y[ i ] );
t.equal( actual, expected[ i ], 'fmod('+x[ i ]+','+y[ i ]+') returns '+expected[ i ] );
}
t.end();
});

tape( 'the function evaluates the modulus function (negative `x`, negative `y`)', opts, function test( t ) {
var expected;
var actual;
var x;
var y;
var i;

x = negativeNegative.x;
y = negativeNegative.y;
expected = negativeNegative.expected;
for ( i = 0; i < x.length; i++ ) {
actual = fmod( x[ i ], y[ i ] );
t.equal( actual, expected[ i ], 'fmod('+x[ i ]+','+y[ i ]+') returns '+expected[ i ] );
}
t.end();
});

tape( 'the function returns `NaN` if provided `NaN` for `y`', opts, function test( t ) {
var v;

Expand Down
Loading