72

How can I round up a number to the second decimal place in Python?

For example:

0.022499999999999999

Should round up to 0.03

0.1111111111111000

Should round up to 0.12

If there is any value in the third decimal place, I want it to always round up leaving me 2 values behind the decimal point.

3

13 Answers 13

55

Python includes the round() function which lets you specify the number of digits you want. From the documentation:

round(x[, n])

Return the floating point value x rounded to n digits after the decimal point. If n is omitted, it defaults to zero. The result is a floating point number. Values are rounded to the closest multiple of 10 to the power minus n; if two multiples are equally close, rounding is done away from 0 (so. for example, round(0.5) is 1.0 and round(-0.5) is -1.0).

So you would want to use round(x, 2) to do normal rounding. To ensure that the number is always rounded up you would need to use the ceil(x) function. Similarly, to round down use floor(x).

Sign up to request clarification or add additional context in comments.

3 Comments

Good suggestion, but it doesn't round up as the OP seems to require.
"Round up" isn't the same as normal rounding. Look at the examples in the question.
@Mark Because adding in the exact code to do ceil would mean copying your answer, I'm leaving mine as (almost) is and upvoting yours.
38
from math import ceil

num = 0.1111111111000
num = ceil(num * 100) / 100.0

See:
math.ceil documentation
round documentation - You'll probably want to check this out anyway for future reference

5 Comments

You don't need round() here -- it won't change the result in any way.
Gives wrong results in following cases: math.ceil((1.11 * 100.0)) / 100.0 comes out to be 1.12 Because: 1.11 * 100.0 has value 111.00000000000001
@nimeshkiranverma see Is floating point math broken? Use the decimal module if you need exact decimal results.
Based on the observation made by @nimeshkiranverma, you do need round() to get the desired result: math.ceil(round(1.11 * 100.0)) / 100.0
@SeanBearden: If you put round in, the ceil is meaningless, and you're just rounding to nearest, not taking the ceiling of the value at all. With round added, 0.1111111111000 multiplied by 100, rounded, ceil-ed, then divided by 100 would get 0.11, when 0.12 is the intended result of ceil.
26
x = math.ceil(x * 100.0) / 100.0

5 Comments

I had to stare at this for a while before I realized this is even more pythonic than my solution.
Has anyone noticed in the last 13 years that this solution rounds up 1.11 to 1.12?
@Jeyekomon it's not an uncommon problem, see stackoverflow.com/q/588004/5987
@Jeyekomon more specifically the problem is that most decimal numbers can't be represented exactly in binary; for example 1.11 is really 1.1100000000000000976996261670137755572795867919921875. There's probably a 50/50 chance of any specific decimal number being above the threshold where ceil would push it up.
@Jeyekomon the problem is actually not as bad as I thought. For the 100 numbers from 1.00 to 1.99, only 4 have the problem: 1.09, 1.10, 1.11, 1.12.
24

Updated answer:
The problem with my original answer, as pointed out in the comments by @jpm, is the behavior at the boundaries. Python 3 makes this even more difficult since it uses "bankers" rounding instead of "old school" rounding. However, in looking into this issue I discovered an even better solution using the decimal library.

import decimal

def round_up(x, place=0):
    context = decimal.getcontext()
    # get the original setting so we can put it back when we're done
    original_rounding = context.rounding
    # change context to act like ceil()
    context.rounding = decimal.ROUND_CEILING

    rounded = round(decimal.Decimal(str(x)), place)
    context.rounding = original_rounding
    return float(rounded)

Or if you really just want a one-liner:

import decimal
decimal.getcontext().rounding = decimal.ROUND_CEILING

# here's the one-liner
float(round(decimal.Decimal(str(0.1111)), ndigits=2))
>> 0.12

# Note: this only affects the rounding of `Decimal`
round(0.1111, ndigits=2)
>> 0.11

Here are some examples:

round_up(0.022499999999999999, 2)
>> 0.03
round_up(0.1111111111111000, 2)
>> 0.12
round_up(0.1111111111111000, 3)
>> 0.112

round_up(3.4)
>> 4.0

# @jpm - boundaries do what we want
round_up(0.1, 2)
>> 0.1
round_up(1.1, 2)
>> 1.1

# Note: this still rounds toward `inf`, not "away from zero"
round_up(2.049, 2)
>> 2.05
round_up(-2.0449, 2)
>> -2.04

We can use it to round to the left of the decimal as well:

round_up(11, -1)
>> 20

We don't multiply by 10, thereby avoiding the overflow mentioned in this answer.

round_up(1.01e308, -307)
>> 1.1e+308

Original Answer (Not recommended):
This depends on the behavior you want when considering positive and negative numbers, but if you want something that always rounds to a larger value (e.g. 2.0449 -> 2.05, -2.0449 -> -2.04) then you can do:

round(x + 0.005, 2)

or a little fancier:

def round_up(x, place):
    return round(x + 5 * 10**(-1 * (place + 1)), place)

This also seems to work as follows:

round(144, -1)
# 140
round_up(144, -1)
# 150
round_up(1e308, -307)
# 1.1e308

3 Comments

This is not guaranteed to work... An example: round(0.1 + 0.005, 2) == 0.11 whereas round(1.1 + 0.005, 2) == 1.10
@jpm: Good point. I looked into it and it turns out the boundaries are hard to deal with correctly using round, especially now that round uses "bankers" rounding instead of "old school rounding". I've updated my answer with a better solution.
This answer could be improved by specifying which rounding you mean with "oldschool": en.wikipedia.org/wiki/Rounding and removing the quotation marks around bankers rounding
15

Extrapolating from Edwin's answer:

from math import ceil, floor
def float_round(num, places = 0, direction = floor):
    return direction(num * (10**places)) / float(10**places)

To use:

>>> float_round(0.21111, 3, ceil)  # Round up
>>> 0.212
>>> float_round(0.21111, 3)        # Round down
>>> 0.211
>>> float_round(0.21111, 3, round) # Round naturally
>>> 0.211

1 Comment

Gives wrong results in following cases: math.ceil((1.11 * 100.0)) / 100.0 comes out to be 1.12 Because: 1.11 * 100.0 has value 111.00000000000001
7

The Python round function could be rounding the way you did not expect.

You can be more specific about the rounding method by using Decimal.quantize.

E.g.,

from decimal import Decimal, ROUND_HALF_UP
res = Decimal('0.25').quantize(Decimal('0.0'), rounding=ROUND_HALF_UP)
print(res)
# Prints 0.3

More reference:

How do I round to 2 decimals?

Comments

5

Note that the ceil(num * 100) / 100 trick will crash on some degenerate inputs, like 1e308. This may not come up often but I can tell you it just cost me a couple of days. To avoid this, "it would be nice if" ceil() and floor() took a decimal places argument, like round() does... Meanwhile, does anyone know a clean alternative that won't crash on inputs like this?

I had some hopes for the decimal package, but it seems to die too:

>>> from math import ceil
>>> from decimal import Decimal, ROUND_DOWN, ROUND_UP
>>> num = 0.1111111111000
>>> ceil(num * 100) / 100
0.12
>>> float(Decimal(num).quantize(Decimal('.01'), rounding=ROUND_UP))
0.12
>>> num = 1e308
>>> ceil(num * 100) / 100
Traceback (most recent call last):
  File "<string>", line 301, in runcode
  File "<interactive input>", line 1, in <module>
OverflowError: cannot convert float infinity to integer
>>> float(Decimal(num).quantize(Decimal('.01'), rounding=ROUND_UP))
Traceback (most recent call last):
  File "<string>", line 301, in runcode
  File "<interactive input>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

Of course one might say that crashing is the only sane behavior on such inputs, but I would argue that it's not the rounding but the multiplication that's causing the problem (that's why, e.g., 1e306 doesn't crash), and a cleaner implementation of the round-up-nth-place function would avoid the multiplication hack.

1 Comment

The problem you're running into with this use of Decimal is that the result of the quantize expression needs 311 digits to express, and the current precision is too small. If you do a from decimal import getcontext; getcontext().prec = 400 beforehand, this will "work", for some value of "work". Or you could note that any float larger than 2**52 in absolute value must already be an integer, so the rounding will have no effect. And yes, I agree it would nice if "ceil" and "floor" took a decimal places argument.
3

Here is a more general one-liner that works for any digits:

import math
def ceil(number, digits) -> float: return math.ceil((10.0 ** digits) * number) / (10.0 ** digits)

Example usage:

>>> ceil(1.111111, 2)
1.12

Caveat: as stated by nimeshkiranverma:

>>> ceil(1.11, 2)
1.12  # Because: 1.11 * 100.0 has value 111.00000000000001

Comments

1

Here's a simple way to do it that I don't see in the other answers.

[Update] The examples below show how to round floating values up. If you want to round down, change the sign of the coefficient term and ratio. For instance, -(-n//10**-p) * 10**-p becomes (n//10**-p) * 10**-p.

To round up to the second decimal place:

>>> n = 0.022499999999999999
>>> 
>>> -(-n//.01) * .01
0.03
>>> 

Other value:

>>> n = 0.1111111111111000
>>> 
>>> -(-n//.01) * .01
0.12
>>> 

With floats there's the occasional value with some minute imprecision, which can be corrected for if you're displaying the values for instance:

>>> n = 10.1111111111111000
>>> 
>>> -(-n//0.01) * 0.01
10.120000000000001
>>> 
>>> f"{-(-n//0.01) * 0.01:.2f}"
'10.12'
>>> 

A simple roundup function with a parameter to specify precision:

>>> roundup = lambda n, p: -(-n//10**-p) * 10**-p
>>> 
>>> # Or if you want to ensure truncation using the f-string method:
>>> roundup = lambda n, p: float(f"{-(-n//10**-p) * 10**-p:.{p}f}")
>>> 
>>> roundup(0.111111111, 2)
0.12
>>> roundup(0.111111111, 3)
0.112

2 Comments

To round down to the tenths digit, you just remove the - before the formula, and change the - before n to a +. So it becomes (+n//10**-p) * 10**-p
@TheQuackiest, thanks for the tip. I added a note with the formula's rounding-down form at the top of the answer.
1

The ceil() function only rounds up to integers. This workaround can be adapted to round up to pennies. You can write a function to do that for you.

from math import ceil

payment = 3.1234
payment = 100 * payment
payment = ceil(payment)
payment = payment / 100
print(payment)
3.13

Comments

0

I wrote a simple function for round_up:

def round_up(number: float, ndigits: int):
    offset = 0.5
    if ndigits and ndigits > 0:
        offset = offset / (10 ** ndigits)
        return round(number + offset, ndigits)
   else:
       return round(number+offset)

Comments

-1

The round function stated does not work for definite integers, like:

a=8
round(a,3)
8.0
a=8.00
round(a,3)
8.0
a=8.000000000000000000000000
round(a,3)
8.0 \

But it works for:

> r=400/3.0 \
> r \
133.33333333333334 \
> round(r,3) \
133.333 \

Moreover, the decimals like 2.675 are rounded as 2.67, not 2.68.
Better use the other method provided above.

2 Comments

This is not an answer but a comment. Please add this as a comment to the related answer
-1

Use:

def round_decimals_up(number:float, decimals:int=2):
    """
    Returns a value rounded up to a specific number of decimal places.
    """
    if not isinstance(decimals, int):
        raise TypeError("decimal places must be an integer")
    elif decimals < 0:
        raise ValueError("decimal places has to be 0 or more")
    elif decimals == 0:
        return math.ceil(number)

    factor = 10 ** decimals
    return math.ceil(number * factor) / factor


round_decimals_up(0.022499999999999999)
# It returns: 0.03

round_decimals_up(0.1111111111111000)
# It returns: 0.12

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.