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.

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
B. Richard
  • 771
  • 1
  • 5
  • 3
  • Floating point values do not represent decimals exactly. This is not a Python thing. – Daniel Roseman Jul 04 '11 at 09:27
  • possible duplicate of [Python rounding error with float numbers](http://stackoverflow.com/questions/5997027/python-rounding-error-with-float-numbers) – mac Jul 04 '11 at 11:12
  • 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**8``` – warownia1 Nov 14 '17 at 00:15

6 Answers6

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.

Alec
  • 8,529
  • 8
  • 37
  • 63
Pascal Bugnion
  • 4,878
  • 1
  • 24
  • 29
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.

Eric O. Lebigot
  • 91,433
  • 48
  • 218
  • 260
Jacob
  • 41,721
  • 6
  • 79
  • 81
  • 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. – Eric O. Lebigot Jul 05 '11 at 14:33
  • @EOL If you allow, I can edit it in or feel free to edit it yourself. – Jacob Jul 05 '11 at 14:34
  • Thanks. I edited your answer; feel free to adapt my prose to your taste. :) – Eric O. Lebigot Jul 05 '11 at 15:42
  • 1
    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. – kindall Jul 05 '11 at 15:53
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.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
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/ :),

Ant
  • 5,151
  • 2
  • 26
  • 43
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.

HackerBoss
  • 829
  • 7
  • 16
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))
Massifox
  • 4,369
  • 11
  • 31