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

Bug in pack_float16() #157

Open
oyvindronningstad opened this issue Jan 10, 2023 · 2 comments
Open

Bug in pack_float16() #157

oyvindronningstad opened this issue Jan 10, 2023 · 2 comments
Labels

Comments

@oyvindronningstad
Copy link
Contributor

I did some cursory testing of your float16 functions (out of curiosity, since I recently wrote my own conversion functions float16 <-> float32).

It seems your pack_float16() doesn't give the same answer as mine for some values. For small numbers, it could maybe be attributed to different rounding rules, but for high numbers it does seem wrong, for example for the float32 number represented in raw hex as 0x47000000, i.e. 32768.0, which has an exact representation in float16: 0x7800, but is rounded to infinity by pack_float16().

I did read the document you referenced in half_float_tables.py, and it does not specify any rounding mode, so I don't know how it handles that. My code is written to do "Round to nearest, ties to even", which I tested against numpy.

I looked at the code and realized that pack_float16() being wrong is not critical, I just wanted to let you know.

If you're curious, my code and tests can be found here: NordicSemiconductor/zcbor#285

@dolfandringa
Copy link

dolfandringa commented Jun 2, 2023

Debugging here. Python's struct.(un)pack can handle the value correctly:

>> struct.unpack('e', bytearray([0x00, 0x78]))
(32768.0,)
>>> struct.pack('e', 32768.0).hex()
'0078'

It is definitely an issue with the c implementation. Encoding with the pure python encoder (cbor2.encoder.dumps) vs the c encoder (when supported) (dumps) and canonical=True on both (aka, the smallest possible size) results in different representations.

from cbor2 import dump, encoder
>>> dumps(32768.0, canonical=True).hex()
'fa47000000'
>>> encoder.dumps(32768.0, canonical=True).hex()
'f97800'
>>>

So it's probably somewhere here:

if (unpack_float16(u_half.i) == u_single.f) {

@dolfandringa
Copy link

dolfandringa commented Jun 2, 2023

Just commenting for future me (or anyone else interested in debugging):

I started the debugger to figure out where its going wrong, and I'll try to find time to continue that. But for anyone that is interested, this is basically how to get started with debugging: https://llllllllll.github.io/c-extension-tutorial/gdb.html
Using this snippet will bring you to the line mentioned above.

import _cbor2
_cbor2.dumps(32768.0, canonical=True)

Bringing it down to unpack_float16, which encodes 124 as infinite:

p pack_float16(32768.0)
$1 = 124
p unpack_float16(124)
$2 = inf

Check: https://evanw.github.io/float-toy/ (thanks @Sekenre ). Bit 11 is wrong in the unpack_float16

@agronholm agronholm added the bug label Sep 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants