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

Type stability of intermediates in conversions #81

Merged
merged 6 commits into from
Jun 21, 2024
Merged

Type stability of intermediates in conversions #81

merged 6 commits into from
Jun 21, 2024

Conversation

milankl
Copy link
Owner

@milankl milankl commented Jun 19, 2024

fixes #80

@milankl milankl added the bug Something isn't working label Jun 19, 2024
@giordano
Copy link
Contributor

Maybe add tests? 🙂

@milankl
Copy link
Owner Author

milankl commented Jun 19, 2024

@Tobboss I've added one signed and one unsigned operation to the float -> posit conversion which removes some type instabilities we had. The extracted exponent bits were UInt32 for Float32 and Int64 for Float64

julia> Posit32(64f0)          # = (2^4)^k * 2^e, k = 1, e = 2 
[ Info: (UInt32, 0x00000002)  # typeof(e), e
Posit32(0.125)

julia> Posit32(64e0)
[ Info: (Int64, 6, false, 1)
[ Info: (Int64, 2)
Posit32(64.0)

there's a difference between int/uint because the bitshift is only arithmetic (=sign preserving) for ints not for uints (always push in 0s). This should be resolved now. Adding some tests

@milankl
Copy link
Owner Author

milankl commented Jun 19, 2024

Maybe add tests? 🙂

Yes haha, bit embarrassing that this wasn't caught before ... 🙈

@milankl
Copy link
Owner Author

milankl commented Jun 19, 2024

Okay so I've added some tests that check for power 2 conversions float->posit->float in the following ranges
(kmin, kmax) for the range [2^k for k in kmin:kmax] and (2^kmin, 2^kmax) after that

[ Info: (Float64, Posit32, (-108, 108), (3.0814879110195774e-33, 3.2451855365842673e32))
[ Info: (Float32, Posit32, (-108, 108), (3.0814879110195774e-33, 3.2451855365842673e32))
[ Info: (Float64, Posit16, (-44, 44), (5.684341886080802e-14, 1.7592186044416e13))
[ Info: (Float32, Posit16, (-44, 44), (5.684341886080802e-14, 1.7592186044416e13))
[ Info: (Float64, Posit16_1, (-22, 22), (2.384185791015625e-7, 4.194304e6))
[ Info: (Float32, Posit16_1, (-22, 22), (2.384185791015625e-7, 4.194304e6))
[ Info: (Float64, Posit8, (-12, 12), (0.000244140625, 4096.0))
[ Info: (Float32, Posit8, (-12, 12), (0.000244140625, 4096.0))

but Float16 is still fishy, e.g.

julia> Posit32(Float16(1))
Posit32(5.421010862427522e-20)

julia> Posit16(Float16(1))
Posit16(1.0)

julia> Posit8(Float16(1))
Posit8(1.0)

@milankl
Copy link
Owner Author

milankl commented Jun 19, 2024

julia> bitstring(Posit32(Float16(1)))
"00000000000000000100000000000000"

julia> bitstring(Posit16(Float16(1)))
"0100000000000000"

something is not pushed in the right position

@milankl
Copy link
Owner Author

milankl commented Jun 19, 2024

Okay it's about the bitround function that in case of "upcasting" (so not actually rounding) should just append 0s to the right, but that's currently not happening

julia> SoftPosit.bitround(UInt8, 0x1234)   # downcasting/rounding, correct
0x12

julia> SoftPosit.bitround(UInt16, 0x1234)   # uint16->uint16, identity, correct
0x1234

julia> SoftPosit.bitround(UInt32, 0x1234)    # uint16->32 upcasting, not correct
0x00000000

the latter should return 0x12340000 as for both floats and posits adding zeros to the right doesn't change the value

@milankl
Copy link
Owner Author

milankl commented Jun 21, 2024

@Tobboss with the last commit hopefully all conversions are corrected now. Would you mind checking your initial tests again and feed back here? I say "hopefully" because it's quite tricky to test all conversions between all possible posits and floats. You see that the tests I've formulated usually pick one aspect / special case of the conversion, some ranges are tested via lookup tables, some via back and forth conversion, some conversions are exact, some have to be rounded (to nearest, tie to even).

I had some headaches with the float16 -> posit conversion as float16 subnormals require branching as their definition changes, such that the float16 subnormal mantissa impacts the posit regime and exponent bits. Kahan definitely owes me probably some weeks of my life because he thought that subnormals were a good idea. As I didn't want to go into the branching, I just defined float16->float32->posit, i.e. via conversion to float32 first. This is okay as float16 -> float32 is exact for all float16s, and conveniently converts all float16 subnormals to float32 normals. Float16 normals -> posit aren't a problem but well...

@milankl
Copy link
Owner Author

milankl commented Jun 21, 2024

if you think that #80 is resolved then I'll merge and tag a new patch release

@Tobboss
Copy link

Tobboss commented Jun 21, 2024

@Tobboss with the last commit hopefully all conversions are corrected now. Would you mind checking your initial tests again and feed back here?

Hey Milan, thanks for the quick fix. I updated to the new branch and ran my test bench again. It looks very promising but my test is far from exhaustive. The elephant in the room is definately fixed.

I did a quick test and compared if random Float32 values converted to posit are still alike for the whole range of Float32. It was not so easy to find a suitable comparison, because I just got started with Julia and Posit, so I ended up comparing the higher significants and the exponents. It looks fine. The deviations that reside are normal near the min and max boundaries of the float.

@milankl milankl merged commit 0839e0c into main Jun 21, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Float32 to Posit32 conversion yields unexpected results
3 participants