round() doesn't seem to be rounding properly

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?


Asked by: Abigail185 | Posted: 01-10-2021






Answer 1

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

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

Answered by: Lucas494 | Posted: 02-11-2021



Answer 2

Formatting works correctly even without having to round:

"%.1f" % n

Answered by: Sydney139 | Posted: 02-11-2021



Answer 3

If you use the Decimal module you can approximate without the use of the 'round' function. Here is what I've been using for rounding especially when writing monetary applications:

from decimal import Decimal, ROUND_UP

Decimal(str(16.2)).quantize(Decimal('.01'), rounding=ROUND_UP)

This will return a Decimal Number which is 16.20.

Answered by: Madaline950 | Posted: 02-11-2021



Answer 4

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.

Answered by: Cadie861 | Posted: 02-11-2021



Answer 5

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

Answered by: Adrian343 | Posted: 02-11-2021



Answer 6

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.

Answered by: Elise798 | Posted: 02-11-2021



Answer 7

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.

Answered by: Roman502 | Posted: 02-11-2021



Answer 8

Take a look at the Decimal module

Decimal β€œis based on a floating-point model which was designed with people in mind, and necessarily has a paramount guiding principle – computers must provide an arithmetic that works in the same way as the arithmetic that people learn at school.” – excerpt from the decimal arithmetic specification.

and

Decimal numbers can be represented exactly. In contrast, numbers like 1.1 and 2.2 do not have an exact representations in binary floating point. End users typically would not expect 1.1 + 2.2 to display as 3.3000000000000003 as it does with binary floating point.

Decimal provides the kind of operations that make it easy to write apps that require floating point operations and also need to present those results in a human readable format, e.g., accounting.

Answered by: Maddie454 | Posted: 02-11-2021



Answer 9

It's a big problem indeed. Try out this code:

print "%.2f" % (round((2*4.4+3*5.6+3*4.4)/8,2),)

It displays 4.85. Then you do:

print "Media = %.1f" % (round((2*4.4+3*5.6+3*4.4)/8,1),)

and it shows 4.8. Do you calculations by hand the exact answer is 4.85, but if you try:

print "Media = %.20f" % (round((2*4.4+3*5.6+3*4.4)/8,20),)

you can see the truth: the float point is stored as the nearest finite sum of fractions whose denominators are powers of two.

Answered by: Rafael650 | Posted: 02-11-2021



Answer 10

printf the sucker.

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

Answered by: Eric544 | Posted: 02-11-2021



Answer 11

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.

Answered by: Ada982 | Posted: 02-11-2021



Answer 12

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

mystring = "%.2f" % 5.5999

Answered by: Ada129 | Posted: 02-11-2021



Answer 13

I am doing:

int(round( x , 0))

In this case, we first round properly at the unit level, then we convert to integer to avoid printing a float.

so

>>> int(round(5.59,0))
6

I think this answer works better than formating the string, and it also makes more sens to me to use the round function.

Answered by: John182 | Posted: 02-11-2021



Answer 14

Works Perfect

format(5.59, '.1f') # to display
float(format(5.59, '.1f')) #to round

Answered by: Roman984 | Posted: 02-11-2021



Answer 15

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)

Answered by: Aston839 | Posted: 02-11-2021



Answer 16

Code:

x1 = 5.63
x2 = 5.65
print(float('%.2f' % round(x1,1)))  # gives you '5.6'
print(float('%.2f' % round(x2,1)))  # gives you '5.7'

Output:

5.6
5.7

Answered by: Sam255 | Posted: 02-11-2021



Answer 17

The problem is only when last digit is 5. Eg. 0.045 is internally stored as 0.044999999999999... You could simply increment last digit to 6 and round off. This will give you the desired results.

import re


def custom_round(num, precision=0):
    # Get the type of given number
    type_num = type(num)
    # If the given type is not a valid number type, raise TypeError
    if type_num not in [int, float, Decimal]:
        raise TypeError("type {} doesn't define __round__ method".format(type_num.__name__))
    # If passed number is int, there is no rounding off.
    if type_num == int:
        return num
    # Convert number to string.
    str_num = str(num).lower()
    # We will remove negative context from the number and add it back in the end
    negative_number = False
    if num < 0:
        negative_number = True
        str_num = str_num[1:]
    # If number is in format 1e-12 or 2e+13, we have to convert it to
    # to a string in standard decimal notation.
    if 'e-' in str_num:
        # For 1.23e-7, e_power = 7
        e_power = int(re.findall('e-[0-9]+', str_num)[0][2:])
        # For 1.23e-7, number = 123
        number = ''.join(str_num.split('e-')[0].split('.'))
        zeros = ''
        # Number of zeros = e_power - 1 = 6
        for i in range(e_power - 1):
            zeros = zeros + '0'
        # Scientific notation 1.23e-7 in regular decimal = 0.000000123
        str_num = '0.' + zeros + number
    if 'e+' in str_num:
        # For 1.23e+7, e_power = 7
        e_power = int(re.findall('e\+[0-9]+', str_num)[0][2:])
        # For 1.23e+7, number_characteristic = 1
        # characteristic is number left of decimal point.
        number_characteristic = str_num.split('e+')[0].split('.')[0]
        # For 1.23e+7, number_mantissa = 23
        # mantissa is number right of decimal point.
        number_mantissa = str_num.split('e+')[0].split('.')[1]
        # For 1.23e+7, number = 123
        number = number_characteristic + number_mantissa
        zeros = ''
        # Eg: for this condition = 1.23e+7
        if e_power >= len(number_mantissa):
            # Number of zeros = e_power - mantissa length = 5
            for i in range(e_power - len(number_mantissa)):
                zeros = zeros + '0'
            # Scientific notation 1.23e+7 in regular decimal = 12300000.0
            str_num = number + zeros + '.0'
        # Eg: for this condition = 1.23e+1
        if e_power < len(number_mantissa):
            # In this case, we only need to shift the decimal e_power digits to the right
            # So we just copy the digits from mantissa to characteristic and then remove
            # them from mantissa.
            for i in range(e_power):
                number_characteristic = number_characteristic + number_mantissa[i]
            number_mantissa = number_mantissa[i:]
            # Scientific notation 1.23e+1 in regular decimal = 12.3
            str_num = number_characteristic + '.' + number_mantissa
    # characteristic is number left of decimal point.
    characteristic_part = str_num.split('.')[0]
    # mantissa is number right of decimal point.
    mantissa_part = str_num.split('.')[1]
    # If number is supposed to be rounded to whole number,
    # check first decimal digit. If more than 5, return
    # characteristic + 1 else return characteristic
    if precision == 0:
        if mantissa_part and int(mantissa_part[0]) >= 5:
            return type_num(int(characteristic_part) + 1)
        return type_num(characteristic_part)
    # Get the precision of the given number.
    num_precision = len(mantissa_part)
    # Rounding off is done only if number precision is
    # greater than requested precision
    if num_precision <= precision:
        return num
    # Replace the last '5' with 6 so that rounding off returns desired results
    if str_num[-1] == '5':
        str_num = re.sub('5$', '6', str_num)
    result = round(type_num(str_num), precision)
    # If the number was negative, add negative context back
    if negative_number:
        result = result * -1
    return result

Answered by: Lana670 | Posted: 02-11-2021



Answer 18

Here's where I see round failing. What if you wanted to round these 2 numbers to one decimal place? 23.45 23.55 My education was that from rounding these you should get: 23.4 23.6 the "rule" being that you should round up if the preceding number was odd, not round up if the preceding number were even. The round function in python simply truncates the 5.

Answered by: Lenny271 | Posted: 02-11-2021



Answer 19

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

Answered by: Paul336 | Posted: 02-11-2021



Answer 20

What about:

round(n,1)+epsilon

Answered by: Roman650 | Posted: 02-11-2021



Similar questions

string - Rounding decimals with new Python format function

How do I round a decimal to a particular number of decimal places using the Python 3.0 format function?


Python rounding issue

I have come across a very strange issue in python. (Using python 2.4.x) In windows: &gt;&gt;&gt; a = 2292.5 &gt;&gt;&gt; print '%.0f' % a 2293 But in Solaris: &gt;&gt;&gt; a = 2292.5 &gt;&gt;&gt; print '%.0f' % a 2292 But this is the same in both windows and solaris: &gt;&gt;&gt; a = 1.5 &gt;&gt;&gt; print '%.0f' % a 2 ...


rounding - Python: How to round 123 to 100 instead of 100.0?

&gt;&gt;&gt; round(123,-2) 100.0 &gt;&gt;&gt; How to round it to 100 instead of 100.0?&nbsp;


rounding - python round problem

I am facing the problem while dividing my max_sum = 14 total_no=4 so when i do print "x :", (total_sum/total_no) , I get 3 and not 3.5 I tried many ways for printing but failed, can somebody let me know what way I get in 3.5 format? Thank you


python - Rounding the duration of two date values

I have two date values in Python which Im trying to get a rounded duration from. For example: 01-01-2000 to 12-31-2099 is really "100 years", not "99 years". I have an example, in Java, but Im not sure how to port this to Python speak: round(endDateEpochInMilliseconds -startDateEpochInMilliseconds /(365.25 * 24 * 3600 * 1000)) Im sure something similar is doab...


Rounding Rules in Python

I am trying to round to some different rules within python. For example; 10.666 = 10.6 10.667 = 10.7 ie down on 6, and up on 7. Is there a way that I can do this with Python?


python - PyODBC - cursor record value rounding

I am working on a Python script (Python version 2.5.1 on Windows XP) that involves connecting to a Microsoft Access (.mdb) database to read values from a table. I'm getting some unexpected results with one record whereby the field of interest precision is getting rounded. I know the Access table field of interest is a Double data type. But, the value that caused me to discover this in the table is 1107901035.43948...


Rounding Problem with Python

This question already has answers here:


python - Rounding in jinja2 brackets

I guess just generally I'm curious about what operations are allowable in jinja2 brackets, e.g. what I'm trying to do is perform an operation on embedded data like so: {{ round(255*(mileage['chevy'] - mileage['ford']))/1000 }} This throws the error on traceback: UndefinedError: 'round' is undefined Similarly when I try to use 'abs' in a bracket...


python - Rounding separate values in a list at the same time

I would like to write something which looks a bit like what I currently have in the following definition: def rounding( sp1, sp2, sp3, sp4 ): if () &lt;= 700.: round(object, -1) elif () &lt;= 1000.: round(object, (-1*5)) elif () &lt;= 10000.: round(object, -2) elif () &gt; 10000.: round(object, -3) else: print "Error" return [ sp1, sp2, sp3, ...






Still can't find your answer? Check out these communities...



PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python



top