Python Forum

Full Version: float to int conversion
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
i have a floating point number that is a power (whole, perhaps negative, but not too extreme) of 2 and therefore can be represented in floating point exactly. an example of such a number is 2 to the -2 power which is 0.25. i might have other numbers, but the issue i am seeing is with those that are powers of 2. i also have a very large power of 10 such 10**32. typically i will have much larger but i picked 10**32 so the numbers i will show are not too long. if i have 0.125 and 10**32 and multiply them and convert back to int i am wanting to get 12500000000000000000000000000000 but the value i actually get is 12500000000000000670770275549184. the issue appears to be the int() conversion is working with a reduced number resolution that is unable to represent 1.25e-31 exactly (double in C on x86 can, even on 32 bit platforms), or is unable to represent a conversion temporary value exactly.

what i am looking for is a way to carry out the multiplication of a very large int to get a very large int by a float value that has an exact representation and get a "clean" result. one complication is that the original int number and expected result int number do not have exact representations in float (so doing it all in float isn't usable).
Fraction might solve your problem.
from fractions import Fraction
a = Fraction.from_float(0.125)
n = a * 10 ** 32
print(n)

It seem to work better as strings.
from fractions import Fraction
print(Fraction(0.1), Fraction(str(0.1)))
In addition to using rational arithmetic, the decimal module can also be used.

>>> from decimal import Decimal
>>> Decimal(0.125) * 10**32
Decimal('1.250000000000000000000000000E+31')
>>> int(_)
12500000000000000000000000000000
In recent versions of Python, binary floats are converted exactly to Decimal by allowing the precision of the result to be increased. 53 decimal digits is sufficient to represent a 53-bit binary value. Since your float value is an exact power of 2, this doesn't really matter but it can be useful.

The default precision of a result is 28 decimal digits. You can increase that if your expected result is larger.
i solved this by scaling the number, whatever it is, by a sufficient power of 2 to eliminate any fractional part and converted that to int. now this number is scaled by that power of 2. next, i do the multiply. eventually it will be unscaled. actually the 10**32 iyself is a scaling factor. so i am just doing one scaling (by a power of 2) then changing the scaling (to a power of 10) by multiplying the new scaling amount (10**32) and then dividing (int division ... // in Python3) by the old scaling amount (2**?).
You can use the expression
x & (1 + ~x)
to get the largest power of two that divides x, where x is a nonzero integer. For example
>>> x = 10 ** 32
>>> x
100000000000000000000000000000000
>>> x & (1 + ~x)
4294967296
>>> (x & (1 + ~x)).bit_length() - 1
32
I always found that string Fractions are more accurate the Decimals.
from decimal import Decimal
from fractions import Fraction

scale = 10 ** 32
value = 0.1
print(int(Decimal(value) * scale))
print(int(Fraction(value) * scale))
print(int(Fraction(str(value)) * scale))
Output:
10000000000000000555111512310000 10000000000000000555111512312578 10000000000000000000000000000000