-
-
Notifications
You must be signed in to change notification settings - Fork 473
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
refactor: use constant packages, FI_F
for addon and style fixes in math/base/special/ldexpf
#2868
base: develop
Are you sure you want to change the base?
Changes from all commits
4aa48f4
5805f17
ad9556b
4a04069
359290b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,10 +35,15 @@ | |
#include "stdlib/number/float32/base/from_word.h" | ||
#include "stdlib/math/base/special/copysignf.h" | ||
#include "stdlib/constants/float32/pinf.h" | ||
#include "stdlib/constants/float32/exponent_mask.h" | ||
#include "stdlib/constants/float32/precision.h" | ||
#include "stdlib/constants/float32/abs_mask.h" | ||
#include <stdint.h> | ||
|
||
static const float TWO25 = 33554432.0f; // 0x4c000000 | ||
static const float TWOM25 = 2.9802322387695312e-8f; // 0x33000000 | ||
static const int32_t FLOAT32_SIGNIFICAND_MASK_WITH_SIGN = 0x807fffff; // 1 00000000 11111111111111111111111 | ||
static const int32_t ALL_ONES = 0xff; // 0xff = 255 => 11111111 | ||
|
||
/** | ||
* Multiplies a single-precision floating-point number by an integer power of two. | ||
|
@@ -60,52 +65,52 @@ float stdlib_base_ldexpf( const float frac, const int32_t exp ) { | |
stdlib_base_float32_to_word( frac, &uix ); | ||
ix = (int32_t)uix; | ||
|
||
// Extract exponent | ||
k = ( ix & 0x7f800000 ) >> 23; | ||
// Extract exponent: | ||
k = ( ix & STDLIB_CONSTANT_FLOAT32_EXPONENT_MASK ) >> ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 ); | ||
|
||
// 0 or subnormal frac | ||
// 0 or subnormal frac: | ||
fracc = frac; | ||
if ( k == 0 ) { | ||
if ( ( ix & 0x7fffffff ) == 0 ) { | ||
// +-0 | ||
if ( ( ix & STDLIB_CONSTANT_FLOAT32_ABS_MASK ) == 0 ) { | ||
// +-0: | ||
return frac; | ||
} | ||
fracc = frac * TWO25; | ||
stdlib_base_float32_to_word( fracc, &uix ); | ||
ix = (int32_t)uix; | ||
k = ( ( ix & 0x7f800000 ) >> 23 ) - 25; | ||
k = ( ( ix & STDLIB_CONSTANT_FLOAT32_EXPONENT_MASK ) >> ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 ) ) - 25; | ||
if ( exp < -50000 ) { | ||
// Underflow | ||
// Underflow: | ||
return 0.0; | ||
} | ||
} | ||
|
||
// NaN or Inf | ||
if ( k == 0xff ) { | ||
// NaN or Inf: | ||
if ( k == ALL_ONES ) { | ||
return fracc + fracc; | ||
} | ||
k += exp; | ||
if ( k > 0xfe ) { | ||
// Overflow | ||
if ( k > ALL_ONES - 1 ) { | ||
// Overflow: | ||
return stdlib_base_copysignf( STDLIB_CONSTANT_FLOAT32_PINF, fracc ); | ||
} | ||
if ( k > 0 ) { | ||
// Normal result | ||
stdlib_base_float32_from_word( (uint32_t)( ( ix & 0x807fffff ) | ( k << 23 ) ), &fracc ); | ||
// Normal result: | ||
stdlib_base_float32_from_word( (uint32_t)( ( ix & FLOAT32_SIGNIFICAND_MASK_WITH_SIGN ) | ( k << ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 ) ) ), &fracc ); | ||
return fracc; | ||
} | ||
if ( k <= -25 ) { | ||
if ( exp > 50000 ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gunjjoshi Same comment as for the JS version. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay. I see why this was in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ...and add a respective test. |
||
// In case of integer overflow in n + k | ||
// In case of integer overflow in n + k: | ||
return stdlib_base_copysignf( STDLIB_CONSTANT_FLOAT32_PINF, fracc ); | ||
} | ||
|
||
// Underflow | ||
// Underflow: | ||
return stdlib_base_copysignf( 0.0f, fracc ); | ||
} | ||
|
||
// Subnormal result | ||
// Subnormal result: | ||
k += 25; | ||
stdlib_base_float32_from_word( (uint32_t)( ( ix & 0x807fffff ) | ( k << 23 ) ), &fracc ); | ||
stdlib_base_float32_from_word( (uint32_t)( ( ix & FLOAT32_SIGNIFICAND_MASK_WITH_SIGN ) | ( k << ( STDLIB_CONSTANT_FLOAT32_PRECISION - 1 ) ) ), &fracc ); | ||
return fracc * TWOM25; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gunjjoshi I am a bit confused. Why is this branch unreachable? If you can exercise L133, then you should also be able to exercise
exp > 50000
by providing aexp
value greater than50000
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kgryte This is because, suppose we take
exp
as60000
. Then, on L116,k
will become greater than or equal toexp
, i.e.,k>=60000
. Then, in the very next line, i.e., on L117, theif
condition will evaluate totrue
, as the condition checksk>0xfe
, where0xfe=254
. So, the execution will go inside that block, and the result would be returned from L119.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gunjjoshi Okay. We actually need to update L116 to emulate 32-bit integer arithmetic. It should be
k = (k + exp)|0;
. Then you can replicate the scenario whereexp
is very large andk
becomes negative.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After updating this to according to 32-bit integer arithmetic, we do not need to add the removed block again here, right? I have added the corresponding test to only
test.native.js
, as we're not having that block here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, you do need to re-add the block as now it is possible to overflow to a negative number.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For instance, for
exp = 3e9
,k = -1294967296
inJS
, but inC
,k = 1
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gunjjoshi Can you try recompiling the addon, but setting the
fwrapv
compiler flag? https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Signed-Overflow.htmlThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To compile with the flag set, you can use the same approach as we used when checking for fused operations previously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried:
But even with this, it doesn't work. What happens is, when I pass a large value such as
3e9
forexp
, and then try to print the value ofexp
from inside the function, it comes out to be1
. So, the value ofexp
is being taken as1
in these cases.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm...odd. I wonder if I get the same behavior on my machine. I'll try and check locally sometime in the next day or so.