round() doesn't seem to be rounding properly

Viewed 258102

The documentation for the round() function states that you pass it a number, and the positions past the decimal to round. Thus it should do this:

n = 5.59
round(n, 1) # 5.6

But, in actuality, good old floating point weirdness creeps in and you get:

5.5999999999999996

For the purposes of UI, I need to display 5.6. I poked around the Internet and found some documentation that this is dependent on my implementation of Python. Unfortunately, this occurs on both my Windows dev machine and each Linux server I've tried. See here also.

Short of creating my own round library, is there any way around this?

20 Answers

I can't help the way it's stored, but at least formatting works correctly:

'%.1f' % round(n, 1) # Gives you '5.6'

Formatting works correctly even without having to round:

"%.1f" % n

round(5.59, 1) is working fine. The problem is that 5.6 cannot be represented exactly in binary floating point.

>>> 5.6
5.5999999999999996
>>> 

As Vinko says, you can use string formatting to do rounding for display.

Python has a module for decimal arithmetic if you need that.

You get '5.6' if you do str(round(n, 1)) instead of just round(n, 1).

You can switch the data type to an integer:

>>> n = 5.59
>>> int(n * 10) / 10.0
5.5
>>> int(n * 10 + 0.5)
56

And then display the number by inserting the locale's decimal separator.

However, Jimmy's answer is better.

Floating point math is vulnerable to slight, but annoying, precision inaccuracies. If you can work with integer or fixed point, you will be guaranteed precision.

printf the sucker.

print '%.1f' % 5.59  # returns 5.6

I would avoid relying on round() at all in this case. Consider

print(round(61.295, 2))
print(round(1.295, 2))

will output

61.3
1.29

which is not a desired output if you need solid rounding to the nearest integer. To bypass this behavior go with math.ceil() (or math.floor() if you want to round down):

from math import ceil
decimal_count = 2
print(ceil(61.295 * 10 ** decimal_count) / 10 ** decimal_count)
print(ceil(1.295 * 10 ** decimal_count) / 10 ** decimal_count)

outputs

61.3
1.3

Hope that helps.

You can use the string format operator %, similar to sprintf.

mystring = "%.2f" % 5.5999

Another potential option is:

def hard_round(number, decimal_places=0):
    """
    Function:
    - Rounds a float value to a specified number of decimal places
    - Fixes issues with floating point binary approximation rounding in python
    Requires:
    - `number`:
        - Type: int|float
        - What: The number to round
    Optional:
    - `decimal_places`:
        - Type: int 
        - What: The number of decimal places to round to
        - Default: 0
    Example:
    ```
    hard_round(5.6,1)
    ```
    """
    return int(number*(10**decimal_places)+0.5)/(10**decimal_places)

Here is an easy way to round a float number to any number of decimal places, and it still works in 2021!

float_number = 12.234325335563
rounded = round(float_number, 3) # 3 is the number of decimal places to be returned.You can pass any number in place of 3 depending on how many decimal places you want to return.
print(rounded)

And this will print;

12.234

What about:

round(n,1)+epsilon
Related