简体   繁体   中英

Almost correct output, but not quite right. Math help in Python

I am trying to match an expected output of "13031.157014219536" exactly , and I have attempted 3 times to get the value with different methods, detailed below, and come extremely close to the value, but not close enough. What is happening in these code snippets that it causing the deviation? Is it rounding error in the calculation? Did I do something wrong?

Attempts:

    item_worth = 8000

    years = range(10)

    for year in years:
        item_worth += (item_worth*0.05)

    print(item_worth)

    value = item_worth * (1 + ((0.05)**10))

    print(value)

    cost = 8000

    for x in range(10):
        cost *= 1.05

    print(cost)

Expected Output:

    13031.157014219536

Actual Outputs:

    13031.157014219529
    13031.157014220802
    13031.157014219538

On most machine, floats are represented by fp64, or double floats.

You can check the precision of those for your number that way (not a method to be used for real computation. Just out of curiosity):

import struct
struct.pack('d', 13031.157014219536)
# bytes representing that number in fp64 b'\xf5\xbc\n\x19\x94s\xc9@'
# or, in a more humanely understandable way
struct.unpack('q', struct.pack('d', 13031.157014219536))[0]
# 4668389568658717941
# That number has no meaning, except that this integer is represented by the same bytes as your float.
# Now, let's see what float is "next in line"
struct.unpack('d', struct.pack('q', 4668389568658717941+1))[0]
# 13031.157014219538

Note that this code works on most machine, but is not reliable. First of all, it relies on the fact that significant bits are not just all 1. Otherwise, it would give a totally unrelated number. Secondly, it makes assumption that ints are LE. But well, it gave me what I wanted.

That is the information that the smallest number bigger than 13031.157014219536 is 13031.157014219538.

(Or, said more accurately for this kind of conversation: the smallest float bigger than 13031.157014219536 whose representation is not the same as the representation of 13031.157014219536 has the same representation as 13031.157014219538)

So, my point is you are flirting with the representation limit. You can't expect the sum of 10 numbers to be more accurate.

I could also have said that saying that the biggest power of 2 smaller than your number is 8192=2¹³. So, that 13 is the exponent of your float in its representation. And this you have 53 significant bits, the precision of such a number is 2**(13-53+1) = 1.8×10⁻¹² (which is indeed also the result of 13031.157014219538-13031.157014219536 ). Hence the reason why in decimal, 12 decimal places are printed. But not all combination of them can exist, and the last one is not insignificant, but not fully significant neither.

If your computation is the result of the sum of 10 such numbers, you could even have an error 10 times bigger than your last result the right to complain:D

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM