-
Notifications
You must be signed in to change notification settings - Fork 103
fmod: Correct the normalization of subnormals #535
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
Conversation
@sjrd I added the test cases mentioned at #469 (comment), thank you for providing those. It doesn't seem like I am able to reproduce the failure without the
I also checked the test cases you added at scala-js/scala-js#5147, and there don't seem to be any problems. |
Cc @quaternic who has done a lot of experimentation with fmod |
Right, the translation to a generic implementation introduced an unintentional change that subnormals are "normalized" to a form that is |
One thing we did differently in the Scala port is that we mask off the sign bit early: Other than that, I followed the Rust implementation pretty closely. Perhaps the |
Interestingly a switch to
|
332729b
to
cd46e6b
Compare
From discussion at [1] our loop count calculation is incorrect, causing an issue with subnormal numbers. Add test cases for known failures. [1]: rust-lang#469 (comment)
Discussed at [1], there was an off-by-one mistake when converting from the loop routine to using `leading_zeros` for normalization. Currently, using `EXP_BITS` has the effect that `ix` after the branch has its MSB _one bit to the left_ of the implicit bit's position, whereas a shift by `EXP_BITS + 1` ensures that the MSB is exactly at the implicit bit's position, matching what is done for normals (where the implicit bit is set to be explicit). This doesn't seem to have any effect in our implementation since the failing test cases from [1] appear to still have correct results. Since the result of using `EXP_BITS + 1` is more consistent with what is done for normals, apply this here. [1]: rust-lang#469 (comment)
It's possible there is a difference if signed arithmetic is used rather than unsigned at some point since the net effect is to shift one bit further left than expected, which would be a sign flip any of the subtract+shift ops wind up placing that in the MSB. I don't think it's worth digging into too much though; I'll apply the change here since it's more correct, but this will go away soon with @quaternic's rewrite anyway #536. |
Discussed at 1, there was an off-by-one mistake when converting from
the loop routine to using
leading_zeros
for normalization.Currently, using
EXP_BITS
has the effect thatix
after the branchhas its MSB one bit to the left of the implicit bit's position,
whereas a shift by
EXP_BITS + 1
ensures that the MSB is exactly at theimplicit bit's position, matching what is done for normals (where the
implicit bit is set to be explicit). This doesn't seem to have any
effect in our implementation since the failing test cases from 1
appear to still have correct results.
Since the result of using
EXP_BITS + 1
is more consistent with what isdone for normals, apply this here.