Round Numbers in Python: round(), Decimal.quantize()
This article explains how to round numbers (floating point numbers float
and integers int
) in Python.
For more information on rounding down and up decimals (floor and ceiling), refer to the following article.
For details on the round()
function in NumPy and pandas, refer to the following articles.
- NumPy: Round array elements (np.round, np.around, np.rint)
- pandas: Rounding, truncating, and ceiling for DataFrame and Series
Built-in round()
function
In Python, the built-in round()
function is available.
Specify the number to be rounded as the first argument and the number of decimal places to round to as the second argument, ndigits
.
Round decimals to a specific number of digits
For floating point numbers (float
), if the second argument is omitted, round()
rounds to and returns an integer (int
).
f = 123.456
print(round(f))
# 123
print(type(round(f)))
# <class 'int'>
When a second argument is specified, it returns a floating point number (float
).
Specifying a positive integer rounds to that number of decimal places, while specifying a negative integer rounds to that number of integer places. For example, -1
rounds to the tens place, -2
to the hundreds place. 0
rounds to an integer, but returns float
.
print(round(f, 1))
# 123.5
print(round(f, 2))
# 123.46
print(round(f, -1))
# 120.0
print(round(f, -2))
# 100.0
print(round(f, 0))
# 123.0
print(type(round(f, 0)))
# <class 'float'>
Round integers to a specific number of digits
For integers (int
), round()
returns the original number when the second argument is omitted, 0
, or any positive integer.
If a negative integer is specified, it rounds to the corresponding integer digit (-1
for tens, -2
for hundreds, etc.). In all cases, it returns an integer (int
).
i = 99518
print(round(i))
# 99518
print(round(i, 2))
# 99518
print(round(i, -1))
# 99520
print(round(i, -2))
# 99500
print(round(i, -3))
# 100000
round()
rounds half to even (bankers' rounding)
round()
uses bankers' rounding, which means it rounds half to even. For example, 0.5
and 2.5
are rounded to 0
and 2
, respectively.
For the built-in types supporting
round()
, values are rounded to the closest multiple of10
to the power minusndigits
; if two multiples are equally close, rounding is done toward the even choice (so, for example, bothround(0.5)
andround(-0.5)
are0
, andround(1.5)
is2
). Built-in Functions - round() — Python 3.12.1 documentation
print('0.5 =>', round(0.5))
print('1.5 =>', round(1.5))
print('2.5 =>', round(2.5))
print('3.5 =>', round(3.5))
print('4.5 =>', round(4.5))
# 0.5 => 0
# 1.5 => 2
# 2.5 => 2
# 3.5 => 4
# 4.5 => 4
print(' 5 =>', round(5, -1))
print('15 =>', round(15, -1))
print('25 =>', round(25, -1))
print('35 =>', round(35, -1))
print('45 =>', round(45, -1))
# 5 => 0
# 15 => 20
# 25 => 20
# 35 => 40
# 45 => 40
Rounding to even occurs only when the fraction is exactly 0.5
; for example, 2.5
is rounded to 2
, but 2.51
is rounded to 3
.
print('2.49 =>', round(2.49))
print('2.50 =>', round(2.5))
print('2.51 =>', round(2.51))
# 2.49 => 2
# 2.50 => 2
# 2.51 => 3
Rounding beyond the first decimal place may not always conform to the definition of rounding half to even.
print('0.05 =>', round(0.05, 1))
print('0.15 =>', round(0.15, 1))
print('0.25 =>', round(0.25, 1))
print('0.35 =>', round(0.35, 1))
print('0.45 =>', round(0.45, 1))
# 0.05 => 0.1
# 0.15 => 0.1
# 0.25 => 0.2
# 0.35 => 0.3
# 0.45 => 0.5
This inconsistency arises because, as mentioned in the documentation, floating point numbers cannot always represent decimals precisely.
Note: The behavior of
round()
for floats can be surprising: for example,round(2.675, 2)
gives2.67
instead of the expected2.68
. This is not a bug: it's a result of the fact that most decimal fractions can't be represented exactly as a float. Built-in Functions - round() — Python 3.12.1 documentation
For example, increasing the number of display digits shows that 0.15
is actually 0.14999...
. Since the fraction is less than 0.05
, it rounds to 0.1
.
print(f'{0.15:.20}')
# 0.14999999999999999445
To accurately handle decimals or use different rounding modes, consider using the decimal
module from the standard library, described next.
decimal.quantize()
The decimal
module of the standard library allows for accurate decimal floating point arithmetic.
The decimal
module, being part of the standard library, requires no additional installation but must be imported to be used. In the following sample code, it is imported as shown.
from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN
Create Decimal
objects
You can create Decimal
objects with Decimal()
.
Specifying a floating point number (float
) creates a Decimal
with the actual value.
print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125
print(type(Decimal(0.05)))
# <class 'decimal.Decimal'>
This indicates that the floating point number 0.05
contains an error, which is why values such as 0.05
are rounded to unexpected values by the built-in round()
function.
0.5
(= 1/2
) and 0.25
(= 1/4
) can be precisely represented.
print(Decimal(0.5))
# 0.5
print(Decimal(0.25))
# 0.25
Specifying a string (str
) creates a Decimal
with exactly that value. To convert float
to str
, use str()
.
print(Decimal('0.05'))
# 0.05
print(Decimal(str(0.05)))
# 0.05
Round decimals to a specific number of digits
The quantize()
method of Decimal
enables precise rounding with various modes.
Specify a Decimal
with the desired precision as the first argument. You can specify Decimal()
with a string like '0.1'
or '0.01'
. To round the integer part, use scientific notation like '1E1'
. More details will be discussed later.
f = 123.456
print(Decimal(str(f)).quantize(Decimal('0'), ROUND_HALF_UP))
print(Decimal(str(f)).quantize(Decimal('0.1'), ROUND_HALF_UP))
print(Decimal(str(f)).quantize(Decimal('0.01'), ROUND_HALF_UP))
# 123
# 123.5
# 123.46
Specify the rounding mode as the second argument, rounding
. For example, 0.5
rounds to 1
with ROUND_HALF_UP
.
print('0.4 =>', Decimal(str(0.4)).quantize(Decimal('0'), ROUND_HALF_UP))
print('0.5 =>', Decimal(str(0.5)).quantize(Decimal('0'), ROUND_HALF_UP))
print('0.6 =>', Decimal(str(0.6)).quantize(Decimal('0'), ROUND_HALF_UP))
# 0.4 => 0
# 0.5 => 1
# 0.6 => 1
ROUND_HALF_EVEN
performs the same even rounding as the built-in round()
function. By specifying values as strings in Decimal()
, more accurate representation is ensured, avoiding the floating point errors typically associated with round()
, and thereby producing the expected result.
print('0.05 =>', Decimal(str(0.05)).quantize(Decimal('0.1'), ROUND_HALF_EVEN))
print('0.15 =>', Decimal(str(0.15)).quantize(Decimal('0.1'), ROUND_HALF_EVEN))
print('0.25 =>', Decimal(str(0.25)).quantize(Decimal('0.1'), ROUND_HALF_EVEN))
print('0.35 =>', Decimal(str(0.35)).quantize(Decimal('0.1'), ROUND_HALF_EVEN))
print('0.45 =>', Decimal(str(0.45)).quantize(Decimal('0.1'), ROUND_HALF_EVEN))
# 0.05 => 0.0
# 0.15 => 0.2
# 0.25 => 0.2
# 0.35 => 0.4
# 0.45 => 0.4
For a list of rounding modes, refer to the official documentation. There are various rounding modes available besides ROUND_HALF_UP
and ROUND_HALF_EVEN
.
The quantize()
method returns a Decimal
, which can be converted to a float
using float()
. However, this conversion results in a value that is limited to the representational capabilities of a float
.
d = Decimal('123.456').quantize(Decimal('0.01'), ROUND_HALF_UP)
print(d)
# 123.46
print(type(d))
# <class 'decimal.Decimal'>
f = float(d)
print(f)
# 123.46
print(type(f))
# <class 'float'>
print(Decimal(f))
# 123.4599999999999937472239253111183643341064453125
print(Decimal(str(f)))
# 123.46
Round integers to a specific number of digits
When using the quantize()
method to round to integer digits, specifying something like '10'
as the first argument does not return the desired result.
i = 99518
print(Decimal(i).quantize(Decimal('10'), ROUND_HALF_UP))
# 99518
This is because quantize()
performs rounding based on the exponent (exponent
) of the Decimal
object. It is necessary to use a scientific notation string (for example, '1E1'
).
You can check exponent
with the as_tuple()
method.
print(Decimal('10').as_tuple())
# DecimalTuple(sign=0, digits=(1, 0), exponent=0)
print(Decimal('1E1').as_tuple())
# DecimalTuple(sign=0, digits=(1,), exponent=1)
Since integers can be accurately represented as int
types, you can specify them directly as integers (int
) in Decimal()
. Of course, it may be specified as a string.
print(Decimal(i).quantize(Decimal('1E1'), ROUND_HALF_UP))
print(Decimal(i).quantize(Decimal('1E2'), ROUND_HALF_UP))
print(Decimal(i).quantize(Decimal('1E3'), ROUND_HALF_UP))
# 9.952E+4
# 9.95E+4
# 1.00E+5
If you want to use regular notation instead of scientific notation, use the function introduced in the official documentation.
def remove_exponent(d):
return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
d = Decimal(i).quantize(Decimal('1E2'), ROUND_HALF_UP)
print(d)
# 9.95E+4
d_remove = remove_exponent(d)
print(d_remove)
# 99500
print(type(d_remove))
# <class 'decimal.Decimal'>
To convert Decimal
to an integer (int
), use int()
.
i = int(d)
print(i)
# 99500
print(type(i))
# <class 'int'>
Custom functions for standard rounding (rounding half up)
Although the decimal
module is often the better choice due to its precision, if you simply want to perform standard rounding (rounding half up), defining a custom function is another option.
For example, define the following function. The return value is always a floating point number (float
).
def my_round(number, ndigits=0):
p = 10**ndigits
return (number * p * 2 + 1) // 2 / p
If you don't need to specify the number of digits and simply want to round to an integer, a more concise approach can be adopted.
def my_round_int(number):
return int((number * 2 + 1) // 2)
Round decimals to a specific number of digits
Here is an example of the result using the function defined above. my_round()
always returns a floating point number (float
), so use int()
if you want to convert it to an integer (int
).
f = 123.456
print(my_round(f))
# 123.0
print(int(my_round(f)))
# 123
print(my_round(f, 1))
# 123.5
print(my_round(f, 2))
# 123.46
print(my_round_int(f))
# 123
Unlike the built-in round()
function, this rounds 0.5
to 1
.
print('0.4 =>', int(my_round(0.4)))
print('0.5 =>', int(my_round(0.5)))
print('0.6 =>', int(my_round(0.6)))
# 0.4 => 0
# 0.5 => 1
# 0.6 => 1
Round integers to a specific number of digits
Here is an example of the result using the function defined above.
i = 99518
print(int(my_round(i, -1)))
# 99520
print(int(my_round(i, -2)))
# 99500
print(int(my_round(i, -3)))
# 100000
Unlike the built-in round()
function, this rounds 5
to 10
.
print('4 =>', int(my_round(4, -1)))
print('5 =>', int(my_round(5, -1)))
print('6 =>', int(my_round(6, -1)))
# 4 => 0
# 5 => 10
# 6 => 10
Note: In the case of negative values
With the function defined above, -0.5
is rounded to 0
.
print('-0.4 =>', int(my_round(-0.4)))
print('-0.5 =>', int(my_round(-0.5)))
print('-0.6 =>', int(my_round(-0.6)))
# -0.4 => 0
# -0.5 => 0
# -0.6 => -1
There are various approaches to round negative values. If you want to round -0.5
to -1
, for example, do the following. Convert the input value to an absolute value using the built-in abs()
function, and multiply by the sign obtained using math.copysign()
at the end.
- Get the absolute value with abs() and math.fabs() in Python
- Sign function in Python (sign/signum/sgn, copysign)
import math
def my_round2(number, ndigits=0):
p = 10**ndigits
return (abs(number) * p * 2 + 1) // 2 / p * math.copysign(1, number)
print('-0.4 =>', int(my_round2(-0.4)))
print('-0.5 =>', int(my_round2(-0.5)))
print('-0.6 =>', int(my_round2(-0.6)))
# -0.4 => 0
# -0.5 => -1
# -0.6 => -1