How to round numbers in Python
Working with numbers is a significant part of programming, especially when it comes to scientific applications or handling monetary values.
Here, the need to round numbers in Python becomes essential. It allows us to adjust a number to a nearby value, usually to decrease its complexity or to fit it into a certain precision. Let’s dive into how we can perform this in Python.
- 1 Using Built-in round() Function
- 2 Rounding Negative Numbers to Nearest Integer
- 3 Rounding to a Specific Decimal Place
- 4 Rounding with math.floor()
- 5 Rounding with math.ceil()
- 6 Creating a custom round function
- 7 floating point representation and limitations
- 8 Using decimal module
- 9 Python Decimal type for handling precision
- 10 Python 2 and Python 3 round() Functions
- 11 When to use each rounding method
- 12 Float Bug Fixed with Decimal
- 13 F.A.Q
- 14 Further Reading
Using Built-in round() Function
Python’s built-in round()
function is the easiest way to round numbers. It always rounds a number to the nearest even number when exactly halfway between two integers.
Let’s see how this function works with integers, floats, and complex numbers.
# Integer num = 5 print(round(num)) # Float num = 3.14159 print(round(num)) # Complex number num = 3.5 + 4.5j try: print(round(num)) except TypeError as e: print(e)
Output:
5 3 type complex doesn't define __round__ method
The first example returns 5 as it’s already an integer. In the second example, the floating-point number 3.14159 is rounded down to the nearest whole integer, which is 3. The last example results in a TypeError because the round()
function doesn’t support complex numbers.
Rounding Negative Numbers to Nearest Integer
The round()
function can also work with negative numbers, rounding them to the nearest integer just as it does with positive numbers.
Here’s an example:
num = -3.6 print(round(num))
Output:
-4
As you can see, the negative number -3.6 is rounded to -4, each moving towards the nearest whole integer on the number line.
Rounding to a Specific Decimal Place
The round()
function can also take an additional argument to indicate the number of places to which you want the number rounded.
The second argument specifies how many decimal places you want.
Here’s how it works:
num = 3.14159 # Round to 1 decimal place print(round(num, 1)) # Round to 2 decimal places print(round(num, 2)) # Round to 3 decimal places print(round(num, 3))
Output:
3.1 3.14 3.142
In the first case, the number is rounded to the nearest number with 1 decimal place, which is 3.1. In the second case, it’s rounded to the nearest number with 2 decimal places, which is 3.14.
And in the last case, it’s rounded to the nearest number with 3 decimal places, which is 3.142.
Rounding with math.floor()
The math.floor()
function in Python rounds down a number to the nearest integer, moving to the left on the number line. This means it always rounds a number down to the lesser of the two numbers around it.
Let’s illustrate this:
import math # Positive number num = 3.6 print(math.floor(num)) # Negative number num = -3.6 print(math.floor(num))
Output:
3 -4
Here, 3.6 is rounded down to 3, the nearest integer less than it. However, for -3.6, the function rounds to -4, as -4 is to the left of -3.6 on the number line.
Rounding with math.ceil()
The math.ceil()
function in Python is the counterpart of math.floor()
. It rounds up a number to the nearest integer, shifting the number to the right on the number line.
This means it always rounds a number up to the larger of the two numbers around it.
Here’s an example:
import math # Positive number num = 3.6 print(math.ceil(num)) # Negative number num = -3.6 print(math.ceil(num))
Output:
4 -3
In the above example, 3.6 is rounded up to 4, the nearest integer larger than it. However, for -3.6, the function rounds to -3, as -3 is to the right of -3.6 on the number line.
Creating a custom round function
In Python, you have the ability to dictate the rounding behavior of a class by defining a special method named __round__
.
This method will be invoked when the built-in round()
function is used on instances of your class.
For illustration, let’s create a class, CustomRoundNumber
, that will round a number towards zero, a method that is also known as truncation. This is a distinct approach from the standard Python’s rounding behavior:
class CustomRoundNumber: def __init__(self, value): self.value = value def __round__(self, n=None): # if no precision is given, round to the nearest integer if n is None: return int(self.value) # if precision is given, shift the decimal point to the right by the desired number of places multiplier = 10 ** n value = self.value * multiplier # Round towards zero result = int(value) return result / multiplier num = CustomRoundNumber(1.6789) print(round(num, 2)) # 1.67 print(round(num)) # 1
Output:
1.67 1
In the provided code, we’ve defined a class CustomRoundNumber
with a __round__
method. This method is tasked with implementing the round towards zero strategy.
Hence, when round()
is called on an instance of this class, the __round__
method is invoked to round towards zero.
floating point representation and limitations
While rounding can be very useful, it’s important to understand that floating-point numbers in Python (and most programming languages) have limitations due to how they’re represented in binary.
This is due to the fact that floating-point numbers can’t be precisely represented as binary fractions. In base 2, 1/10 is an infinitely repeating fraction.
So, in base 2, 1/10 becomes 0.0001100110011001100110011001100110011001100110011… and so on. Hence, the precision gets lost and can’t be regained.
This isn’t a bug, but rather, it’s a result of a fundamental property of computers, and it’s an issue that everyone who uses floating-point numbers needs to be aware of.
However, we’ll handle this issue using the Decimal type later in this tutorial.
Let’s see an example:
num = 0.1 + 0.1 + 0.1 print(num == 0.3) # Correctly rounded version num_rounded = round(num, 2) print(num_rounded == 0.3)
Output:
False True
Here, adding three instances of 0.1 gives a number that isn’t exactly 0.3 due to the imprecise binary representation of 0.1 Actually, it’s 0.30000000000000004.
However, when we round the result to two decimal places, the comparison with 0.3 returns True.
Using decimal module
The quantize()
method from the decimal
module rounds a number to a fixed amount of decimal places according to a given rounding strategy:
from decimal import * num = Decimal('0.555') # Define the decimal places decimal_places = Decimal('0.00') # Round towards infinity print(num.quantize(decimal_places, rounding=ROUND_CEILING)) # Round towards zero print(num.quantize(decimal_places, rounding=ROUND_DOWN)) # Round towards negative infinity print(num.quantize(decimal_places, rounding=ROUND_FLOOR)) # Round towards nearest, ties go towards zero print(num.quantize(decimal_places, rounding=ROUND_HALF_DOWN)) # Round towards nearest, ties go to nearest even number print(num.quantize(decimal_places, rounding=ROUND_HALF_EVEN)) # Round towards nearest, ties go away from zero print(num.quantize(decimal_places, rounding=ROUND_HALF_UP)) # Round away from zero print(num.quantize(decimal_places, rounding=ROUND_UP))
Output:
0.56 0.55 0.55 0.55 0.56 0.56 0.56
In this example, the quantize()
method rounds the decimal number num
to two decimal places using the specified rounding modes. As you can see, different rounding strategies produce different results.
Python Decimal type for handling precision
The Decimal
type provided by the decimal
module represents decimal floating-point numbers with a user-definable precision.
This can help solve precision issues that arise with the standard floating-point representation.Decimal
can precisely represent numbers like 0.1, which cannot be exactly represented as a binary floating-point number.
Furthermore, Decimal
allows you to control the precision and rounding of the number to match your needs.
Here’s an example of how Decimal can maintain precision:
from decimal import Decimal # Using float num_float = 0.1 + 0.1 + 0.1 print(num_float) # Using Decimal num_decimal = Decimal('0.1') + Decimal('0.1') + Decimal('0.1') print(num_decimal)
Output:
0.30000000000000004 0.3
As shown above, using Decimal
can prevent the precision errors that can occur with floating-point numbers.
Python 2 and Python 3 round() Functions
In Python 2, the round()
function follows the traditional round half away from zero strategy – for instance, round(0.5)
and round(-0.5)
both result in 1.0
and -1.0
respectively.
On the other hand, Python 3 uses the round half to even strategy (also known as Banker’s rounding) by default, where half-way values are rounded to the nearest even number.
So, in Python 3, round(0.5)
results in 0
and round(1.5)
in 2
.
This difference can lead to unexpected results when moving code from Python 2 to Python 3.
When to use each rounding method
Choosing the right rounding method can be critical in certain applications. Here’s a general guideline:
- Use built-in
round()
: For general use cases, especially when you need to round to the nearest even number (Banker’s rounding). - Use
math.floor()
andmath.ceil()
: When you need to always round down (towards negative infinity) or up (towards positive infinity), regardless of the fractional part. - Use custom rounding functions: When you need specific behavior, like always rounding towards or away from zero, or any custom rounding.
- Use the
decimal
module: When precision is crucial, like in financial or scientific applications. This module also allows you to define the precision and use different rounding strategies through thequantize()
method.
It’s important to understand your needs and choose the rounding method that best suits your use case.
Float Bug Fixed with Decimal
I was assigned to investigate a bug in the financial module of the telecom company I worked in. Customers were reporting minor discrepancies in their account balances, which when summed across millions of users, became a significant concern.
I focused on our use of Python’s float type for financial calculations. Floating point arithmetic, while efficient, can introduce minor rounding errors due to its binary fraction representation.
These tiny rounding errors, across millions of transactions, were causing the discrepancies.
I tested this hypothesis with a script that performed the same operations using float and Decimal types. The script confirmed my suspicion: the float arithmetic produced slight differences compared to decimal, causing our discrepancy.
I proceeded to replace the float type with Python’s Decimal type from the decimal module in our financial calculations. It provided accurate decimal floating point arithmetic, perfectly suited for financial transactions.
F.A.Q
Q: How can I round the number to the nearest number with the specified number of decimal places?
A: The round function in Python can be used to round a number to a specified number of digits. In addition to the number, you should pass a second argument representing the number of decimal places you want. Example: round(1.6666, 2) will return 1.67.
Q: How can we round every number to the nearest whole number in a large dataset?
A: If you are dealing with several numbers in a large dataset, such as a list, you can use list comprehension along with Python’s built-in round function to round every number to the nearest whole number. An example is as follows: [round(num) for num in list]
Q: How can a number be rounded up to the ceiling of the number in Python?
A: The math module in Python provides the math.ceil() function to always round up a number. By using this function, you can round up the given number to the ceiling, meaning it will always round the number up.
Q: What is the strategy to round a number to the nearest number with the specified precision?
A: Python’s built-in round function adheres to a strategy known as “round ties to the nearest even number”, which can be used to round a number with the specified precision. If a number is exactly halfway between two others, it will be rounded toward the nearest even number.
Q: What is the round toward negative infinity bias in number rounding in Python?
A: The math.floor() function in Python implements round toward negative infinity bias in number rounding. This means it will always round down to the nearest whole number, irrespective of the decimal part.
Q: How can we round up and round down a number to the nearest whole number in Python?
A: To round up, you can use math.ceil(), and to round down, you can use math.floor(). Both are methods in Python’s math module. For example, math.ceil(1.2) would return 2, and math.floor(1.2) would return 1.
Q: How can we always round a tie away from zero in Python?
A: The standard round() function in Python rounds towards the nearest even choice, but if you want to always round away from zero (i.e., 1.5 rounds to 2, -1.5 rounds to -2), you can use the decimal module’s ROUND_HALF_UP method.
Further Reading
https://docs.python.org/3/library/functions.html#round
https://docs.python.org/3/library/math.html
https://docs.python.org/3/library/decimal.html#decimal.Decimal.quantize
Mokhtar is the founder of LikeGeeks.com. He is a seasoned technologist and accomplished author, with expertise in Linux system administration and Python development. Since 2010, Mokhtar has built an impressive career, transitioning from system administration to Python development in 2015. His work spans large corporations to freelance clients around the globe. Alongside his technical work, Mokhtar has authored some insightful books in his field. Known for his innovative solutions, meticulous attention to detail, and high-quality work, Mokhtar continually seeks new challenges within the dynamic field of technology.