**This tutorial on Rounding Numbers in Python explains different methods to round numbers with multiple programming code examples:**

Computers were originally invented for complex math operations and we didn’t bother as long as integers, subtraction, addition, and multiplication were involved. However, things became unpredictable when floating points and division got involved.

One of the reasons for this unpredictability of floating points or division is mentioned in Python’s documentation. We humans mostly work with the decimal system, which has **base 10**. However, the computer uses and stores the binary system(**0s** and **1s**).

**=> Check ALL Python Tutorials Here**

Coming back to Python’s documentation, this is what it has to say;

Unfortunately, most decimal fractions cannot be represented exactly as binary fractions. A consequence is that, in general, the decimal **floating-point** numbers you enter are only approximated by the **binary floating-point** numbers actually stored in the machine.

FYI, this is in the very nature of binary floating-point and not a bug in Python. So most, if not all programming languages like **Perl**, **C**, **C++**, **Java**, **Fortran** often won’t display the exact decimal number you expect.

**Suggested Reading =>>** **Python Built-in Data Types- None and Numeric**

Table of Contents:

## Rounding Numbers in Python

In this article, we shall learn the various ways of rounding numbers in Python.

### Floating-Point Numbers

This article is all about rounding numbers. But which numbers? In this section, we are going to have a quick look at these numbers.

A floating-point number is basically any number with a decimal point dividing the integer from the fractional parts. Represented as a 64-bit double-precision in Python, it has the data type **‘float’** and can also be represented in scientific notations, with **e** or **E** indicating the power 10. **For example** (1.4E4 = 1.4 x 10^{4} = 14000)

In the introduction, we mentioned that most decimal fractions can’t be represented exactly as binary fractions. Let’s take a look at the example below.

**Example 1:** Unpredictability of floating-point numbers

>>> 0.1 + 0.1 + 0.1 # expected 0.3 0.30000000000000004 >>> 1/10 0.1 >>> 1/10 == 0.10000000000000001 # expected False True >>> format(0.1, '.17f') # expland to 17 decimal places '0.10000000000000001'

From the example above, the first line of code(addition of 0.1s) didn’t return the expected result of **0.3**. Also, we see that **1/10 **equals **0.1**, but surprisingly, the equality operator in the third line of code returned **True**. However, the last line of code reveals the real value of **0.1** in **17** decimal places.

The simple reason is that both results are just the nearest approximate binary fractions. And interestingly, in Python, there are many different decimal numbers that share the same binary fraction. **For example,** the numbers **0.1** and **0.10000000000000001** as we saw above.

This example above shows us how floating-point numbers are inaccurate and thus tricky to work with. This is where** rounding numbers** can spare us a lot by minimizing computing errors.

### Rounding Numbers

Wikipedia defines **rounding** to be the replacement of a number with an approximate value that has a shorter, simpler, or more explicit representation. **For example,** replacing **4.345** with **4.3**, **3.67** with** 4**.

Still from **Wikipedia**, it is mentioned that rounding is often done to obtain a value that is easier to report and communicate than the original. But this usually comes with **round-off errors**.

Most of us were taught two simple rules to apply when rounding numbers. If the digit after the decimal digit we are aiming for is between **0** and **4** inclusively, round down(**add 0**), if it is between **5** and **9** inclusively, round up(**add 1**).

**Check the diagram below for a demonstration:**

Say we have a floating-point number **3.45678** and we want to round it to **n **decimal places, in this case, **3**. From the diagram above, we have **6** as our target decimal number because shifting the decimal point **3** times to the right will be 34**6**.78. The number after the decimal point, in this case, is** 7,** which falls between **5** and **9**. Hence, we round up by adding** 1** to **6**.

Finally, we discard all numbers after the decimal point and bring them back to their normal position, which gives us **3.457**

One of the built-in functions provided by Python to handle rounding numbers is the** round()** function (more details below).

### Built-in Python round() Function

The **round()** function is a Python built-in function that takes in two numeric arguments, **number** and an optional **ndigit**, then returns the number, **n** rounded to a given precision in decimal digits, **ndigit**.

In other words, it rounds the **number** to the closest multiple of **10 ^{-ndigits}**

**Syntax:**

round(number, [, ndigit])

- If
**ndigit**is omitted or**None**, the return value will be the nearest integer. **ndigit**can be negative, which may not give us the results we had in mind.

Let’s now see an example that shows the various ways the **round()** function can be used:

**Example 2:** Using the round() function

def rounding_numbers(): #ex_1 ndigits is None, which is same as no ndigit given number = 1.5 ndigits = None print("Round {} to {} ndigits: {}".format(number, ndigits, round(number, ndigits))) #ex_2 no ndigits is given, which is same as ndigits = None number = 2.5 print("Round {}: {}".format(number, round(number))) #ex_3 round to 3 decimal places number = 3.45678 ndigits = 3 print("Round {} to {} ndigits: {}".format(number, ndigits, round(number, ndigits))) #ex_4 round to zero decimal places number = 35.45678 ndigits = 0 print("Round {} to {} ndigits: {}".format(number, ndigits, round(number, ndigits))) #ex_5 round to a nagative decimal place number = 12.56 ndigits = -1 print("Round {} to {} ndigits: {}".format(number, ndigits, round(number, ndigits))) if __name__ == '__main__': rounding_numbers()

**Output:**

In **ex_1** above, we defined our **ndigits** to be **None**, which is the same as no **ndigits** at all.

In **ex_2**, we can see that rounding** 2.5** to the nearest integer gives **2** instead of the expected **3**.

This is because, as seen in the diagram above, **2.5** is at the middle of the two closest integers, which are; **3 **and **2**

Since there is no closest integer here, Python uses the** IEEE 754** standard called **banker’s rounding,** which rounds to the **nearest least significant even digit**. So, between **3** and **2**, we have **2** as the least significant even digit.

In **ex_4**, with **ndigits** of **0**, all digits after the decimal point are replaced with a single zero. This happens regardless of how many digits appear after the decimal point. It is the same as passing **None** or no **ndigits** at all. The only difference is that with a **ndigits** of zero, the result returned is float.

In **ex_5**, we are rounding to a negative decimal place. Since **ndigits** is **-1**, it will round the number to the closest multiple of **10 ^{-(-1)} = 10**.

From the diagram above, **12.56** is in between the two multiples; **10** and **20**, but closest to **10**.

In **ex_6**, the result is not as expected. The expected value is **2.68** instead of** 2.67**. We shall see later that this is one of the areas where the** Decimal module** outshines the **round() **function.

### Rounding With Math Module

Over the years, mathematicians have developed an awful lot of rounding methods in order to address the problem of rounding. In this section, we shall go through a few of the commonly used methods.

**#1) Truncation**

This is the simplest method of rounding numbers. Here, we simply replace every digit after the position we want to keep with zeros.

The math library has the **trunc()** function that can truncate floating-point values. However, it can only truncate to whole numbers and doesn’t accept an argument for the number of decimal places to keep.

In the example below, we shall customize this function so that it can take into consideration the number of decimal places.

**Example 3:** Customized truncate() function that takes an argument for decimal places to keep

import math def truncate(number, decimal=0): tens = 10.0 if not isinstance(decimal, int): raise TypeError("Argument 'decimal' must be of type int") if decimal == 0: return math.trunc(number) multiples = math.pow(tens, decimal) # tens ** decimal return math.trunc(number * multiples) / multiples if __name__ == '__main__': number = 435.3387743 decimal_list = [0, 2, 3, 4, -1, -2] for decimal in decimal_list: print("Truncate {} to {} decimal: {}".format(number, decimal, truncate(number, decimal)))

**Output:**

In summary, if the decimal argument is provided and is valid(not float), we first multiply the number with **10.0 ^{n}**, where

**n**is the decimal. Then, we truncate it using the

**math.trunc()**function. Finally, we divide it with the same

**10.0**. The decimal,

^{n}**n**can be negative to truncate the digits to the left of the decimal point.

**#2) Rounding Up**

This technique always rounds a number up to a number of digits greater than or equal to the given number.

The Python **math module** has the ceil() function that rounds a number to the nearest integer greater than or equal to the given number. This function only takes in one argument. However, just as in **example 3**, we shall build a customized function that takes in the number of decimal places to keep.

**Example 4**: Customized rounding_up() function that takes an argument for decimal places to keep

import math def rounding_up(number, decimal=0): tens = 10.0 if not isinstance(decimal, int): raise TypeError("Argument 'decimal' must be of type int") if decimal == 0: return math.ceil(number) multiples = math.pow(tens, decimal) # tens ** decimal return math.ceil(number * multiples) / multiples if __name__ == '__main__': numbers = [1.2, 1.534, 33.2, 3356, -1.6] decimal_list = [0, 1, -1, -2, 0] for decimal, number in zip(decimal_list, numbers): print("Round up {} to {} decimal: {}".format(number, decimal, rounding_up(number, decimal)))

**Output:**

In the output above, rounding up **1.2** gives **2** because the closest integers to **1.2** are **1** and **2** and **2** happens to be the greatest. A negative decimal input rounds up the number to the left of the decimal point. Rounding up** -1.6** to **0** decimal place gives **-1** because the closest integers are **-1** and –**2**, and **-1** happens to be the greatest.

**#3) Rounding Down**

This technique always rounds a number down to a number of digits smaller than or equal to the given number.

The Python **math module** has the floor() function that rounds a number to the nearest integer, smaller than or equal to the given number. Just as **ceil()**, this function doesn’t allow us to specify the number of decimal places to keep.

**Example 5:** Customized rounding_down() function that takes an argument for decimal places to keep

import math def rounding_down(number, decimal=0): tens = 10.0 if not isinstance(decimal, int): raise TypeError("Argument 'decimal' must be of type int") if decimal == 0: return math.floor(number) multiples = math.pow(tens, decimal) # tens ** decimal return math.floor(number * multiples) / multiples if __name__ == '__main__': numbers = [1.2, 1.534, 33.2, 3356, -1.6] decimal_list = [0, 1, -1, -2, 0] for decimal, number in zip(decimal_list, numbers): print("Round down {} to {} decimal: {}".format(number, decimal, rounding_down(number, decimal)))

**Output:**

**#4) Rounding Half Up**

This strategy is the common method of rounding, which is the same as rounding up In addition, it breaks ties by rounding up. That is, half-way values of **x** are always rounded up.

In this strategy, one digit is checked to determine the rounding direction. After shifting the decimal point by **10 ^{-n}** as we did for the above examples, we investigate the digit after the shifted decimal point to know if it is less than or greater than or equal to

**5**.

This is mostly done by adding** 0.5** to the shifted value, which will add a **1** to the integer part of the shifted value if greater than **0.5**. Then we use the **floor() **function to get the largest integer.

**Example 6:** Rounding half up or Round half toward positive infinity.

import math def rounding_half_up(number, decimal=0): tens = 10.0 half_way = 0.5 if not isinstance(decimal, int): raise TypeError("Argument 'decimal' must be of type int") if decimal == 0: return math.floor(number + half_way) multiples = math.pow(tens, decimal) # tens ** decimal return math.floor(number * multiples + half_way) / multiples if __name__ == '__main__': numbers = [7.6, 7.5, 7.4, 1.23, 1.28, 1.25, -1.225] decimal_list = [0,0,0,1,1,1,2] for decimal, number in zip(decimal_list, numbers): print("Round half up {} to {} decimal: {}".format(number, decimal, rounding_half_up(number, decimal)))

**Output:**

**#5) Rounding Half Down**

This strategy is the opposite of** Rounding Half Up**. It breaks ties by rounding to the lesser of the two ties. In short, it makes** 0.5** go down.

To achieve this, the modification we have to do to the** rounding_half_up() **in** example 6** is to change the **floor()** function to **ceil()**. Then we subtract** 0.5** instead of adding.

**Example 7**: Rounding half down

import math def rounding_half_down(number, decimal=0): tens = 10.0 half_way = 0.5 if not isinstance(decimal, int): raise TypeError("Argument 'decimal' must be of type int") if decimal == 0: return math.ceil(number - half_way) multiples = math.pow(tens, decimal) # tens ** decimal return math.ceil(number * multiples - half_way) / multiples if __name__ == '__main__': numbers = [7.6, 7.5, 7.4, 1.23, 1.28, 1.25, -1.225] decimal_list = [0,0,0,1,1,1,2] for decimal, number in zip(decimal_list, numbers): print("Round half down {} to {} decimal: {}".format(number, decimal, rounding_half_down(number, decimal)))

**Output:**

**#6) Rounding Half To Even**

This strategy breaks ties by rounding to the nearest least even number. In short, it rounds **0.5** to the nearest even digit.

This strategy is used by the built-in **round()** function to break ties and it is the default rounding rule in the** IEEE-754 standard. **We already explained why rounding **2.5** returned **2** instead of **3** in **example 2** above.

### Rounding With Decimal Module

The Python Decimal module has several benefits over the round() built-in. It has an exact decimal representation. We saw in **example 1, **the unpredictability of floating-point numbers, where 0.1 + 0.1 + 0.1 == 0.3 returned **False**. With the **Decimal module**, the expected value is returned.

**Example 8:** Exact decimal representation

>>> from decimal import Decimal >>> Decimal('0.1') + Decimal('0.1') + Decimal('0.1') Decimal('0.3')

Let’s examine the default context of the decimal module by invoking its .getcontext() method.

**Example 9:** Viewing the current context of the Decimal module

>>> import decimal >>> decimal.getcontext() Context(prec=1, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[InvalidOperation, DivisionByZero, Overflow])

We can notice that the default rounding strategy used is **rounding half even**. Also, the default precision is **26 digits**. However, note that these values can be altered to suit our needs.

Rounding a decimal is done with the **.quantize()** method. This method takes in a decimal value, representing the number of decimal places to keep.

**Example 10:** Rounding with the Decimal module

>>> from decimal import Decimal >>> d = Decimal('2.675') >>> d.quantize(Decimal('1.00')) # round to 2 decimal places Decimal('2.68')

We can remember in **example 2** that rounding **2.675** to **2** decimal places with the **round() **function failed by returning **2.67** instead of **2.68**.

**As mentioned earlier, we can alter the values of the precision attribute and rounding strategy to one of the following flags:**

**Table 1:** Flags for rounding strategy

Flag | Description |
---|---|

ROUND_CEILING | Round towards Infinity or rounding up. |

ROOUND_DOWN | Round towards zero or truncate. |

ROUND_FLOOR | Round towards -Infinity or rounding down. |

ROUND_HALF_DOWN | Round to nearest with ties going towards zero. |

ROUND_HALF_EVEN | Round to nearest with ties going to nearest even integer. |

ROUND_HALF_UP | Round to the nearest number and break ties by rounding up. |

ROUND_UP | Round away from zero. |

ROUND_05UP | Round up if the last digit is 0 or 5, otherwise round down. |

These flags may not mean the same thing as we saw at the beginning of this article. For example, **ROUND_CEILING** works like our** round_up()** function while the **ROUND_FLOOR** works like our **round_down()** function.

Also, both **ROUND_FLOOR** and **ROUND_CEILING** are not symmetric around zero, unlike both **ROUND_UP** and **ROUND_DOWN**.

**ROUND_DOWN** works like our **truncate()** function by rounding everything towards zero.

Let’s see the first flag in action.

**Example 11:** Rounding up with decimal.ROUND_CEILING

import decimal def decimal_ceil(number, dec=0): return decimal.Decimal(str(number)).quantize(decimal.Decimal(str(dec))) if __name__ == '__main__': # set rounding strategy decimal.getcontext().rounding = decimal.ROUND_CEILING numbers = [1.2, 1.534, -1.6] decimal_list = [0, 1., 0] for dec, number in zip(decimal_list, numbers): print("Round up {} to {} decimal: {}".format(number, dec, decimal_ceil(number, dec)))

**Output:**

### Rounding Numpy Arrays

The **Numpy library** is one of the most commonly used libraries in data science and scientific computing. This library provides many functions that can be used to round float numbers. We are going to look at a few here.

**np.round(a[, decimals=0, out=None])**

It takes in an array-like input data and an optional number of decimal places to round to (**default to 0**). Just as we saw with the built-in **round()** above, this **Numpy round()** function uses the **ROUND HALF TO EVEN** strategy and can take in a negative value for the decimal argument.

It is not a built-in library, so needs to be installed. It comes installed with Anaconda, or we can run this command on our terminal to get it installed.

pip3 install numpy

**Example 12:** Round array of floating-point numbers

import numpy as np # seed so that the same output can be reproduced np.random.seed(234) def round_np(array_data, decimal=0): return np.round(array_data, decimal) if __name__ == '__main__': data = np.random.randn(3,3) print("Raw data:\n {}".format(data)) decimals = 3 result = round_np(data, decimals) print("Rounded data to {} decimals:\n {} ".format(decimals, result))

**Output:**

The cool thing about this **numpy.round()** function is that it takes in an array-like data. Unlike the built-in** round()** function, this function acts on a list or array of numbers at a time.

**NB:** In order to reproduce the same result above, make sure to seed with **234** as in the code above.

### Other Functions

In this section, we shall take a look at a few other functions that Numpy provides for rounding floating-point numbers into the nearest integer;

**Table 2**: Numpy functions for rounding floating-point numbers to the nearest integer.

Numpy function | Description |
---|---|

numpy.floor() | Rounds every floating-point number in an array to the nearest integer lesser or equal to the original number. |

numpy.ceil() | Rounds every floating-point number in an array up to the nearest integer greater or equal to the original number |

numpy.truct() | Rounds every floating-point number in an array to its integer component. |

numpy.rint() | Rounds every floating-point number to its nearest integer using the ROUNDING HALF TO EVEN strategy |

Just as we saw with the built-in math library, we can also customize these functions so that they can round to a specified number of decimal places.

**Example 13:** Customize the** numpy.floor()** function to accept an argument for the number of decimal places to round to.

import numpy as np def rounding_down(array_data, decimal=0): tens = 10.0 if not isinstance(decimal, int): raise TypeError("Argument 'decimal' must be of type int") if decimal == 0: return np.floor(array_data) multiples = tens ** decimal return np.floor(array_data * multiples) / multiples if __name__ == '__main__': np.random.seed(234) data = np.random.randn(3,3) decimals = 3 print("Original Data: {}".format(data)) print("Round Down to {} decimals:\n {}".format(decimals, rounding_down(data, decimals)))

**Output:**

### Rounding Pandas Series and DataFrame

The Pandas library is also one of the most commonly used libraries in data science and data analysis. Just as **Numpy**, It also comes installed with **Anaconda** or we can run the command below to install it.

pip3 install pandas

Pandas have the DataFrame and Series as their data structures and both have the **.round() **function that works exactly like **np.round()** we saw above.

**Example 14:** Rounding with Pandas

In this example, we shall see how to round **Series** and **DataFrame** objects, also, we shall see how to use numpy’s rounding functions on Pandas **Series** and **DataFrame** objects.

import pandas as pd import numpy as np np.random.seed(123) series = pd.Series(np.random.rand(3)) df = pd.DataFrame(np.random.randn(3,4), columns=['A','B','C','D']) print("Original Series:\n {}".format(series)) print("Original DF:\n {}".format(df)) print("\n") # Use .round() and round all data the same on Dataframe and Series decimals = 3 series_result = series.round(decimals) df_result = df.round(decimals) print("Series rounded to {} decimal:\n {}".format(decimals,series_result)) print("DF rounded to {} decimal:\n {}".format(decimals,df_result)) print("\n") # Use .round() and specify column-by-column precision on DataFrame decimals = {"A":2, "B":3, "C":4, "D":5} df_result = df.round(decimals) print("DF rounded to {} decimal:\n {}".format(decimals,df_result)) print("\n") # Use numpy's rounding functions on DataFrame print("DF rounded with np.floor:\n {}".format(np.floor(df))) print("DF rounded with np.ceil:\n {}".format(np.ceil(df)))

**Output:**

## Frequently Asked Questions

**Q #1) How do you round a number in a list Python?**

**Answer: **We have many ways to round numbers in a list in Python. The first will be to use a list comprehension together with any rounding function like below:

>>> a =[1.234, 2.345, 3.45, 1.45] >>> [round(i,1) for i in a] # for each number, round with round() function [1.2, 2.3, 3.5, 1.4]

In this case, the most common way will be to use the **numpy.round() **method:

>>> import numpy as np >>> a = [1.234, 2.345, 3.45, 1.45] >>> np_a = np.array(a) # convert list to numpy array >>> np_a_round = np.round(np_a, 1) # round to 1 decimal place >>> list(np_a_round) # convert numpy array back to list. [1.2, 2.3, 3.4, 1.4]

**Q #2) What is round() in Python**

**Answer: **The** round()** is a built-in function in Python that takes in two arguments; the number to round(**number**) and the number of decimal places to keep(**ndigits**), then returns the closest multiple of **10 ^{-ndigits}** but breaks ties by applying the

**ROUNDING HALF TO EVEN**strategy, which rounds to the nearest least even number.

**Q #3) How do you round to 5 decimal places in Python?**

**Answer: **With the built-in **round()** function, we can round to any decimal place by providing the number of decimal places to keep as the second argument. Say we want to round **3.45610688 **to **5** decimal places.

>>> number = 3.45610688 >>> round(number, 5) 3.45611

**Q #4) How do you round off without using the round function in Python?**

**Answer: **To round up or down without the built-in **round()**, we first multiply the number to be rounded by **10.0 ^{n}**, where

**n**is the decimal place to keep. Then, we use

**math.trunc()**for truncation,

**math.ceil()**for rounding up or

**math.floor()**for rounding down. Finally, we divide the result by the same

**10.0**.

^{n}**Below is an example for rounding up:**

multiples = math.pow(number, n) math.ceil(number * multiples) / multiples

**Q #5) How do you round to the nearest whole number?**

**Answer: **To round to the nearest whole number, we first shift the decimal point **n** times where **n** is the number of decimal places to round. Then we check the first digit after the decimal point.

If it is less than **5**, we do nothing, but if it is greater or equal to **5**, we round up the digit before the decimal point by adding **1** to it. Finally, we shift the decimal point back to its original position.

## Conclusion

In this article, we looked at what rounding numbers are and they apply to floating-point numbers. We examined the Python built-in **round()** function and also looked at rounding with the **math module** where we saw various rounding strategies like **Truncation**, **Rounding Up**, **Rounding Down**, and more.

We also covered rounding with the **Decimal module** and finally, we looked at rounding **Numpy arrays** and **Pandas Series** and **DataFrames**.

**=> Read Through ALL Python Tutorials Here**