Python float to int conversion [duplicate]
Asked Answered
R

6

77

Basically, I'm converting a float to an int, but I don't always have the expected value.

Here's the code I'm executing:

x = 2.51

print("--------- 251.0")
y = 251.0
print(y)
print(int(y))

print("--------- 2.51 * 100")
y = x * 100
print(y)
print(int(y))

print("--------- 2.51 * 1000 / 10")
y = x * 1000 / 10
print(y)
print(int(y))

print("--------- 2.51 * 100 * 10 / 10")
y = x * 100 * 10 / 10
print(y)
print(int(y))

x = 4.02
print("--------- 402.0")
y = 402.0
print(y)
print(int(y))

print("--------- 4.02 * 100")
y = x * 100
print(y)
print(int(y))

print("--------- 4.02 * 1000 / 10")
y = x * 1000 / 10
print(y)
print(int(y))

print("--------- 4.02 * 100 * 10 / 10")
y = x * 100 * 10 / 10
print(y)
print(int(y))

And here's the result (first value is the result of the operation, second value is int() of the same operation):

--------- 251.0
251.0
251
--------- 2.51 * 100
251.0
250
--------- 2.51 * 1000 / 10
251.0
251
--------- 2.51 * 100 * 10 / 10
251.0
250
--------- 402.0
402.0
402
--------- 4.02 * 100
402.0
401
--------- 4.02 * 1000 / 10
402.0
401
--------- 4.02 * 100 * 10 / 10
402.0
401

2.51 and 4.02 are the only values that lead to that strange behaviour on the 2.50 -> 5.00 range. Every other two digits value in that range converts to int without any problem when given the same operations.

So, what am I missing that leads to those results? I'm using Python 2.7.2 by the way.

Rolandrolanda answered 4/7, 2011 at 9:25 Comment(2)
Floating point values do not represent decimals exactly. This is not a Python thing.Perez
While others explained why this happen I'd like to show my workaround to get floor rounding with some tolerance to floating point error nfloor = lambda x: round(x * 10**8) // 10**8Desmarais
A
97
2.51 * 100 = 250.999999999997

The int() function simply truncates the number at the decimal point, giving 250. Use

int(round(2.51*100)) 

to get 251 as an integer. In general, floating point numbers cannot be represented exactly. One should therefore be careful of round-off errors. As mentioned, this is not a Python-specific problem. It's a recurring problem in all computer languages.

Andaman answered 4/7, 2011 at 9:35 Comment(0)
F
35

What Every Computer Scientist Should Know About Floating-Point Arithmetic

Floating-point numbers cannot represent all the numbers. In particular, 2.51 cannot be represented by a floating-point number, and is represented by a number very close to it:

>>> print "%.16f" % 2.51
2.5099999999999998
>>> 2.51*100
250.99999999999997
>>> 4.02*100
401.99999999999994

If you use int, which truncates the numbers, you get:

250
401

Have a look at the Decimal type.

Fivepenny answered 4/7, 2011 at 9:29 Comment(4)
"Floating-point numbers are not 100% accurate" would be most precisely described along the line of "Not all numbers can be represented by floating-point numbers" (a number literal is converted into a floating-point number which is very close, and sometimes identical to the number). In fact, all floating-point numbers represent accurately the value that they represent. The key point is that they do not represent all possible numbers.Supernova
@EOL If you allow, I can edit it in or feel free to edit it yourself.Fivepenny
Thanks. I edited your answer; feel free to adapt my prose to your taste. :)Supernova
The important thing to know about binary floating point numbers (you can get this from the linked article, but here's a TL;DR) is that digits after the binary point represent negative powers of two: one-half, one-fourth, one-eighth, etc. A binary floating-point number can thus represent exactly only fractions that are a sum of negative powers of two representable by the available bits. Certain fractions that are finite in decimal notation (e.g. 0.1) require an infinite number of bits in binary notation, and so cannot be completely represented in a float which has a finite number of bits.Ziguard
C
12

Languages that use binary floating point representations (Python is one) cannot represent all fractional values exactly. If the result of your calculation is 250.99999999999 (and it might be), then taking the integer part will result in 250.

A canonical article on this topic is What Every Computer Scientist Should Know About Floating-Point Arithmetic.

Cyrilla answered 4/7, 2011 at 9:29 Comment(0)
H
7
>>> x = 2.51
>>> x*100
250.99999999999997

the floating point numbers are inaccurate. in this case, it is 250.99999999999999, which is really close to 251, but int() truncates the decimal part, in this case 250.

you should take a look at the Decimal module or maybe if you have to do a lot of calculation at the mpmath library http://code.google.com/p/mpmath/ :),

Heintz answered 4/7, 2011 at 9:29 Comment(1)
int() does not round to the integer below, but truncates the decimal part. Example: int(-0.9) == 0.Supernova
U
1

int converts by truncation, as has been mentioned by others. This can result in the answer being one different than expected. One way around this is to check if the result is 'close enough' to an integer and adjust accordingly, otherwise the usual conversion. This is assuming you don't get too much roundoff and calculation error, which is a separate issue. For example:

def toint(f):
    trunc = int(f)
    diff = f - trunc

    # trunc is one too low
    if abs(f - trunc - 1) < 0.00001:
        return trunc + 1
    # trunc is one too high
    if abs(f - trunc + 1) < 0.00001:
        return trunc - 1
    # trunc is the right value
    return trunc

This function will adjust for off-by-one errors for near integers. The mpmath library does something similar for floating point numbers that are close to integers.

Upshaw answered 13/10, 2018 at 18:37 Comment(0)
L
0

To convert to int you should use the int() function:

def myFunction(x, y):
    return int(x / y)

However if x / y is something like 2.8, int() will remove the decimal and convert it to 2. For this you should use the round() function before using int() which looks like this:

def myFunction(x, y):
    return int(round(x / y))
Lundberg answered 3/9, 2022 at 10:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.