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

Incorrect encoding of binary subnormal floats #1049

Closed
robdockins opened this issue Jan 27, 2021 · 5 comments · Fixed by #1053
Closed

Incorrect encoding of binary subnormal floats #1049

robdockins opened this issue Jan 27, 2021 · 5 comments · Fixed by #1053
Labels
bug Something not working correctly

Comments

@robdockins
Copy link
Contributor

Consider

> :m Float
Loading module Cryptol
Loading module Float
Float> fpFromBits (zero#0x1) : Float32
0x8.0p-152

This, I believe, correctly represents the smallest positive 32-bit subnormal floating-point value. However, if we encode this back into bits, we get something else entirely.

Float> fpToBits (0x8.0p-152 : Float32)
0xf5000000
Float> fpToBits (fpFromBits (zero#0x1) : Float32)
0xf5000000
@robdockins robdockins added the bug Something not working correctly label Jan 27, 2021
@weaversa
Copy link
Collaborator

Since it’s only 32-bits, it’s entirely possible to do an exhaustive comparison against a trusted floating point implementation. Might be a worthwhile thing to do with all these operations...

@brianhuffman
Copy link
Contributor

brianhuffman commented Jan 27, 2021

So fpToBits should always be the inverse of fpFromBits, but it appears that isn't always the case. Here's an example testing all possible values for a 12-bit float type. If it was implemented correctly, the output would consist of all 1 bits:

Float> groupBy`{32} [ fpToBits (fpFromBits`{5,7} x) == x | x <- [0..0xfff] ]
[0x80000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0x80000000, 0x80000000, 0x80000000,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 0xffffffff, 0x80000000, 0x00000000]

@robdockins
Copy link
Contributor Author

robdockins commented Jan 27, 2021

I'm pretty sure I have a fix.

You have to be careful, though. The property you've stated isn't quite correct because NaNs are always round-tripped to a canonical quiet NaN.

@brianhuffman
Copy link
Contributor

Yeah, I just realized that all of the non-subnormal mismatches are for NaN values; I wasn't sure whether or not those were supposed to be all mapped to the same value.

I guess the real property you want to test is whether those two functions are inverses when you compose them the other way around.

@robdockins
Copy link
Contributor Author

I'm currently running the following before I check in a fix.

:exhaust (\x -> (y != y \/ x == fpToBits y  where y = fpFromBits x : Float32))

So far it's about 10% in, no failures yet.

robdockins added a commit that referenced this issue Jan 28, 2021
some subnormal values were being incorrectly encoded.

Fixes #1049
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something not working correctly
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants