[python] Round up to Second Decimal Place in Python

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.

This question is related to python rounding

The answer is


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

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

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, 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, eg, 1e306 doesn't crash), and a cleaner implementation of the round-up-nth-place fn would avoid the multiplication hack.


The python round function could be rounding the way not you expected.

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

eg.

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:

https://gist.github.com/jackiekazil/6201722


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).


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


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

def round_up(number, ndigits=None):
    # start by just rounding the number, as sometimes this rounds it up
    result = round(number, ndigits if ndigits else 0)
    if result < number:
        # whoops, the number was rounded down instead, so correct for that
        if ndigits:
            # use the type of number provided, e.g. float, decimal, fraction
            Numerical = type(number)
            # add the digit 1 in the correct decimal place
            result += Numerical(10) ** -ndigits
            # may need to be tweaked slightly if the addition was inexact
            result = round(result, ndigits)
        else:
            result += 1 # same as 10 ** -0 for precision of zero digits
    return result

assert round_up(0.022499999999999999, 2) == 0.03
assert round_up(0.1111111111111000, 2) == 0.12

assert round_up(1.11, 2) == 1.11
assert round_up(1e308, 2) == 1e308

The round funtion stated does not works for definate 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 , works for :

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

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


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

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

x = math.ceil(x * 100.0) / 100.0