I'm currently working on a Python project to convert Hexadecimal fractionals to Binary. So I faced into this problem that you can only store up to the limit of 17 numbers to the fractional part of a Float value. Here is an clear example of what I'm saying
total = 0
for n in range(1, 21):
total += 10 ** -n
print(f"{n} - {total}")
Output
1 - 0.1
2 - 0.11
3 - 0.111
4 - 0.1111
5 - 0.11111
6 - 0.111111
7 - 0.1111111
8 - 0.11111111
9 - 0.111111111
10 - 0.11111111109999999
11 - 0.11111111111
12 - 0.111111111111
13 - 0.1111111111111
14 - 0.11111111111111001
15 - 0.11111111111111101
16 - 0.1111111111111111
17 - 0.11111111111111112
18 - 0.11111111111111112
19 - 0.11111111111111112
20 - 0.11111111111111112
As you can see after 17 it doesn't add up. I know this is because of the limit of bytes that uses to store the float data. But I don't know how to solve it.
Next thing is the float point errors. As you can see in the 10th 14th and 15th rows the value doesn't show the correct result. For a previous calculation I used the Decimal
library to solve this but this time either it doesn't apply or I don't know how to.
Float numbers (i.e. floating point numbers) have limited precision and are usually implemented internally as either a Base 2 mantissa and a power of 2 as the exponent or as a Base 16 mantissa and a power of 16 as the exponent. What can be precisely described in one base with a finite number of "digits", might require an infinite number of digits in another base. For example, 1/3 in Base 10 is .33333333..., i.e. a never-ending sequence of repeating digits while in Base 3 is is just .1.
Use decimal.Decimal
numbers, which can represent any Base 10 number without rounding errors and they can have arbitrary precision.
from decimal import Decimal
total = Decimal(0)
addend = Decimal(".1") # Not Decimal(.1)
for n in range(1, 21):
total += addend
print(f"{n} - {total}")
addend /= 10
Prints:
1 - 0.1
2 - 0.11
3 - 0.111
4 - 0.1111
5 - 0.11111
6 - 0.111111
7 - 0.1111111
8 - 0.11111111
9 - 0.111111111
10 - 0.1111111111
11 - 0.11111111111
12 - 0.111111111111
13 - 0.1111111111111
14 - 0.11111111111111
15 - 0.111111111111111
16 - 0.1111111111111111
17 - 0.11111111111111111
18 - 0.111111111111111111
19 - 0.1111111111111111111
20 - 0.11111111111111111111