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

float-int conversion problem #666

Closed
notro opened this issue Mar 11, 2018 · 3 comments
Closed

float-int conversion problem #666

notro opened this issue Mar 11, 2018 · 3 comments

Comments

@notro
Copy link
Collaborator

notro commented Mar 11, 2018

Strange things happen above (1 << 22):

Adafruit CircuitPython 3.0.0-alpha.2-dirty on 2018-03-10; Adafruit Feather M0 Express with samd21g18

>>> hex(int(float(0x300001)))
'0x300001'
>>> hex(int(float(0x3fffff)))
'0x3fffff'

>>> hex(int(float(0x400001)))
'0x400000'
>>> 0x400001
4194305
>>> int(4194305.0)
4194304

>>> hex(int(float(0x4fffff)))
'0x4ffffe'

>>> hex(int(float(0x4000001)))
'0x4000000'
>>> hex(int(float(0x4ffffff)))
'0x5000000'

>>> hex(int(float(0x3fffff00)))
'0x3fffff00'
>>> hex(int(float(0x3fffff01)))
'0x3fffff00'
>>> hex(int(float(0x3fffffdf)))
'0x3fffff00'

More strangeness:

>>> print("%.6f" % 14.0)
14.000000
>>> print("%.7f" % 14.0)
13.9999998

>>> print("%.5f" % 14.1234)
14.12340
>>> print("%.6f" % 14.1234)
14.123398

paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== for i in range(32):
===     for prec in range(1,9):
===         print('{:.{}f} '.format(float(i), prec), end='')
===     print()
===
===
0.0 0.00 0.000 0.0000 0.00000 0.000000 0.0000000 0.00000000
1.0 1.00 1.000 1.0000 1.00000 1.000000 1.0000000 1.00000000
2.0 2.00 2.000 2.0000 2.00000 2.000000 2.0000000 2.00000000
3.0 3.00 3.000 3.0000 3.00000 3.000000 3.0000000 3.00000000
4.0 4.00 4.000 4.0000 4.00000 4.000000 4.0000000 4.00000000
5.0 5.00 5.000 5.0000 5.00000 5.000000 5.0000000 5.00000000
6.0 6.00 6.000 6.0000 6.00000 6.000000 6.0000000 6.00000000
7.0 7.00 7.000 7.0000 7.00000 7.000000 7.0000000 7.00000000
8.0 8.00 8.000 8.0000 8.00000 8.000000 8.0000000 8.00000000
9.0 9.00 9.000 9.0000 9.00000 9.000000 9.0000000 9.00000000
10.0 10.00 10.000 10.0000 10.00000 10.000000 10.0000000 10.00000000
11.0 11.00 11.000 11.0000 11.00000 11.000000 11.0000002 11.00000024
12.0 12.00 12.000 12.0000 12.00000 12.000000 12.0000005 12.00000048
13.0 13.00 13.000 13.0000 13.00000 13.000001 13.0000007 13.00000072
14.0 14.00 14.000 14.0000 14.00000 14.000000 13.9999998 13.99999981
15.0 15.00 15.000 15.0000 15.00000 15.000000 15.0000000 15.00000000
16.0 16.00 16.000 16.0000 16.00000 16.000000 16.0000000 16.00000000
17.0 17.00 17.000 17.0000 17.00000 17.000000 17.0000005 17.00000048
18.0 18.00 18.000 18.0000 18.00000 18.000001 18.0000010 18.00000095
19.0 19.00 19.000 19.0000 19.00000 19.000000 19.0000000 19.00000000
20.0 20.00 20.000 20.0000 20.00000 20.000000 20.0000000 20.00000000
21.0 21.00 21.000 21.0000 21.00000 21.000001 21.0000014 21.00000143
22.0 22.00 22.000 22.0000 22.00000 22.000000 22.0000005 22.00000048
23.0 23.00 23.000 23.0000 23.00000 23.000000 22.9999995 22.99999952
24.0 24.00 24.000 24.0000 24.00000 24.000001 24.0000010 24.00000095
25.0 25.00 25.000 25.0000 25.00000 25.000000 25.0000000 25.00000000
26.0 26.00 26.000 26.0000 26.00000 26.000001 26.0000014 26.00000143
27.0 27.00 27.000 27.0000 27.00000 27.000000 27.0000005 27.00000048
28.0 28.00 28.000 28.0000 28.00000 28.000000 27.9999995 27.99999952
29.0 29.00 29.000 29.0000 29.00000 29.000001 29.0000010 29.00000095
30.0 30.00 30.000 30.0000 30.00000 30.000000 30.0000000 30.00000000
31.0 31.00 31.000 31.0000 31.00000 31.000001 31.0000014 31.00000143
@jerryneedell
Copy link
Collaborator

jerryneedell commented Mar 11, 2018

I’m not sure I understand the “strangeness”. floats can only represent about 7 significant digits. https://en.m.wikipedia.org/wiki/Single-precision_floating-point_format

@dhalbert
Copy link
Collaborator

dhalbert commented Mar 11, 2018

CircuitPython and MicroPython use a modified single-precision floating point representation. It's a conventional 32-bit IEEE float with the bottom two bits set to zero (parts of encoding pointers, ints, and floats in a single-word format). There are 8 bits of exponent and 22 bits of mantissa. Further explication in #230 (comment).

@notro
Copy link
Collaborator Author

notro commented Mar 11, 2018

I think it strange that the implementation doesn't understand it's own limitations when it comes to printing numbers. I expect it to work like cpython or say so when it can't. At least it's suprising behaviour for someone not steeped in the implementation.

And loosing whole number precision is very suprising, for me at least, but then again I have never looked at how float is implemented.

>>> int(4194304.0) == 4194304
True
>>> int(4194305.0) == 4194305
False
>>> int(4194304.0 + 1 - 1)
4194303

I'm looking at implementing time.localtime() (and time/mktime) which in cpython can take a float. But with these limitations, it doesn't seem possible:

>>> time.localtime(4194304.0)
(2000, 2, 18, 13, 5, 4, 4, 49, -1)
>>> time.localtime(4194305.0)
(2000, 2, 18, 13, 5, 4, 4, 49, -1)

>>> time.localtime(4194304)
(2000, 2, 18, 13, 5, 4, 4, 49, -1)
>>> time.localtime(4194305)
(2000, 2, 18, 13, 5, 5, 4, 49, -1)
>>>

>>> time.localtime(0)
(2000, 1, 1, 0, 0, 0, 5, 1, -1)
>>> time.localtime(sys.maxsize)
(2034, 1, 9, 13, 37, 3, 0, 9, -1)

@notro notro closed this as completed Mar 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants