2

I know that Python's float type is actually a double. Knowing that, I'm having a hard time understanding the results shown below. My expectations are based on the output of https://babbage.cs.qc.cuny.edu/IEEE-754/ and https://www.h-schmidt.net/FloatConverter/IEEE754.html. What is going on here?

>>> 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)
>>> 
>>> decimal_value = 1.23450005054473876953125  # This number is perfectly represented by a 32 bit float.  No rounding necessary.
>>> type(decimal_value)
<class 'float'>
>>> decimal_value
1.2345000505447388  # Why did Python truncate this?
>>>
>>> decimal_value = 1.2345000505447389915758549250313080847263  # This number is perfectly represented by a 64 bit double.  No rounding necessary.
>>> # The comment on the line above is a lie.  That number is not a perfect double.  The closest perfect double to that value is 1.2345000505447389915758549250313080847263336181640625
>>> type(decimal_value)
<class 'float'>
>>> decimal_value
1.234500050544739  # Why did Python truncate this, and why isn't this truncated double value the same as the trucanted float value above?
ubiquibacon
  • 10,451
  • 28
  • 109
  • 179
  • 2
    Because of the default precision that it uses when printing floats. Use a format string with longer precision. – Barmar May 15 '20 at 17:08
  • 1
    try `"{:.40f}".format(decimal_value)`. closing as duplicate as at least one answer solves your issue – Jean-François Fabre May 15 '20 at 17:10
  • both those numbers look **far** too long to be represented by even a double precision number, where did you get them from? notice that `dig=15` in the `float_info`, i.e. a double can represent approximately 15 decimal digits, not the 23 and 40 you are trying with – Sam Mason May 15 '20 at 17:22
  • The numbers are just values that show the problem I was having. I verified them using the IEEE-754 calculators linked to in my question. – ubiquibacon May 15 '20 at 17:27
  • 4
    @SamMason There are some longer numbers that are exactly representable. 1.23450005054473876953125 is one of them. The closest exactly representable number to 1.2345000505447389915758549250313080847263 is 1.2345000505447389915758549250313080847263336181640625. – Patricia Shanahan May 15 '20 at 17:30
  • try printing the hex representations of your numbers (i.e. `value.hex()`) they are one bit apart for me, which is all that can be done. python prints numbers using the shortest unambiguous decimal representation by default. hence it "truncates" the number – Sam Mason May 15 '20 at 17:30
  • @ubiquibacon It's lying, or at least rounding. If there is any digit after the decimal point the least significant digit must be 5. For integers A and B, A/(10**N) == B/(2**M) implies A is divisible by 5**N. – Patricia Shanahan May 15 '20 at 17:44
  • @PatriciaShanahan, I think I was reading or using the calculator incorrectly for the double number. I realized that after I made the comment (tried to delete, but you are too quick!). When use the calculator to generate the double from its corresponding hex value of `3FF3C08320000001` it works as expected. – ubiquibacon May 15 '20 at 17:49

0 Answers0