8000 The floating-point information provided by `sys.float_info` is mostly incorrect. · Issue #93488 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

The floating-point information provided by sys.float_info is mostly incorrect. #93488

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

Closed
wiseaidev opened this issue Jun 4, 2022 · 9 comments
Assignees
Labels
type-bug An unexpected behavior, bug, or error

Comments

@wiseaidev
Copy link
wiseaidev commented Jun 4, 2022

Bug report

Running sys.float_info shows that the smallest number a float can store is min_10_exp=-307. However, by trial and error, it turns out that the true minimum value is 10.0 ** -323

>>> import sys
>>> sys.float_info
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)

>>> 10.0 ** -323
1e-323
>>> 10.0 ** -324
0.0

Therefore, min_10_exp=-307 should be corrected to min_10_exp=-323.

The same apply for min, it should be:

>>> f"{pow(10.0, -323):.16}"
'9.881312916824931e-324'

The max value is correct:

>>> 10.0 ** 308
1e+308
>>> 10.0 ** 309
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Numerical result out of range')

It turns out that a lot of information provided by this attribute(float_info) is not correct, the correct ones are:

>>> 2.0 ** 1023
8.98846567431158e+307

# this implies that max=8.98846567431158e+307 and max_exp=1023
# max_10_exp=308 is correct

>>> f"{pow(2.0, -1074):.16}"
'4.940656458412465e-324'

# this implies that min=4.940656458412465e-324 and min_exp=1074

Following the 64bits version of IEEE 754 standard, the sign is coded on 1 bit, the exponent on 11 bit, and 52-bit for the mantissa, 11 + 1 + 52 = 64 bits; the precision being 52 bits, thus 15 significant digits. This means that dig=15 is correct and mant_dig=52 instead of mant_dig=53.

|-63-|62-----------52|51------------------------0|      
|sign|---exponent----|---------mantissa----------|      
|1bit|----11bits-----|----------52bits-----------|       

Your environment

  • CPython versions tested on: Python 3.9.10
  • Operating system and architecture: Ubuntu 20.04.4 LTS 64 bits.
@wiseaidev wiseaidev added the type-bug An unexpected behavior, bug, or error label Jun 4, 2022
@wiseaidev wiseaidev changed the title An incorrect value for min_10_exp in sys.float_info The floating-point information provided by sys.float_info is mostly incorrect. Jun 4, 2022
@mdickinson
Copy link
Member
mdickinson commented Jun 4, 2022

Thanks for the report. Assuming that you're on a system that uses IEEE 754 binary64 floating-point (which is in practice a very safe assumption), the min and min_10_exp values are correct here. As both the docstrings and the online documentation indicate, they refer to the smallest representable positive normal floating-point value, and the smallest representable normal power of 10, respectively.

It turns out that a lot of information provided by this attribute(float_info) is not correct

Please could you elaborate? What other values do you consider incorrect?

@mdickinson mdickinson self-assigned this Jun 4, 2022
@wiseaidev
Copy link
Author

Updated the issue.

@ghost
Copy link
ghost commented Jun 4, 2022

Following the 64bits version of IEEE 754 standard, the sign is coded on 1 bit, the exponent on 11 bit, and 52-bit for the mantissa, 11 + 1 + 52 = 64 bits; the precision being 52 bits, thus 15 significant digits. This means that dig=15 is correct and mant_dig=52 instead of mant_dig=53.

The significand is 53 bits, 52 of which are actually stored in the significand field. There is a leading bit that is implicit. (See, for example, Section 3.4 of IEEE-754.)

@mdickinson
Copy link
Member

@oda-gitso Ah thanks; I missed that bit of the original report. Indeed mant_dig=53 is correct.

@mdickinson mdickinson closed this as not planned Won't fix, can't repro, duplicate, stale Jun 4, 2022
@wiseaidev
Copy link
Author

The significand is 53 bits, 52 of which are actually stored in the significand field. There is a leading bit that is implicit. (See, for example, Section 3.4 of IEEE-754.)

I wasn't aware that it takes into consideration the sign bit. But in any case, the other values that I have mentioned are completely wrong. You can reproduce the error by running the examples that I provided above.

@wiseaidev
Copy link
Author

Joined 29 days ago, @mdickinson, I see what you did there.

@mdickinson
Copy link
Member

the other values that I have mentioned are completely wrong

They're correct. Again, as documented, those constants refer to normal values. The result of 10.0 ** -323 is subnormal, not normal: it's not represented with full precision.

@eryksun
Copy link
Contributor
eryksun commented Jun 4, 2022

Any absolute value smaller than sys.float_info.min is a subnormal (i.e. denormalized) number, including 0.0. Subnormal doubles are evaluated with a fixed binary exponent of -1022 (not -1023). Here's the smallest subnormal that's greater than 0:

>>> f = float.fromhex('0x0.0000000000001p-1022')
>>> format(f, '.16e')
'4.9406564584124654e-324'

That's (2 ** -52) * (2 ** -1022) == 2 ** -1074.

Here's the smallest normal float value from hex format:

>>> f = float.fromhex('0x1.0000000000000p-1022')
>>> f == sys.float_info.min
True
>>> format(f, '.16e')
'2.2250738585072014e-308'

@wiseaidev
Copy link
Author
wiseaidev commented Jun 4, 2022

Now I get it. I didn't know about the subnormal numbers. Thanks for the explanation, @mdickinson & @eryksun.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants
0