## Introduction

As common as it is to work with numbers in computing, is to round numbers, be it to given significant figures or decimal places, or to the nearest integer, nearest tens, nearest hundreds and so on.

In this chapter, we shall understand all aspects of rounding in Python. Specifically, we'll explore the global `round()` function and then the `trunc()`, `floor()` and `ceil()` functions of the `math` module.

Lastly, we'll consider a bit of string formatting in order to accomplish rounding to a given precision, reliably.

Let's start!

## The `round()` function

The most basic way to round a given number to a given number of significant figures, or decimal places, is using the global `round()` function.

Shown below is the syntax of `round()`:

``round(number, precision)``

The `round()` function takes in two arguments:

1. The first argument `number` specifies the number to round, and is required.
2. The second argument `precision`, which is optional, specifies the digit position at which you want your number to be rounded. The default value is `0` which implies the units digit. Positive values shift this position rightwards, while negative values shift it leftwards.

Let's first consider a few examples of `round()` without the first parameter:

``round(4.2)``
4
``round(4.9)``
5

`round(4.2)` rounds `4.2` to the nearest units giving `4`. Similarly, `round(4.9)` rounds `4.9` to the nearest units giving `5`.

Now let's bring on the second `precision` parameter.

It has to be an integer. A positive value shifts the digit position from the units digit to the right, while a negative value shifts the digit position to the left.

Let's first consider positive values:

``round(3.14, 1)``
3.1
``round(20.636, 2)``
20.64

As you can see here, `round(3.14, 1)` rounds `3.14` to the first digit after the units digit (and after the decimal point), that is highlighted as follows: `3.14`. The result is `3.1`, since the digit following `1` is lesser than 5.

To take in another way, `round(3.14, 1)` rounds `3.14` to 1 decimal place.

On the same lines, `round(20.636, 2)` rounds `20.636` to the second digit after the units digit, that is highlighted as follows: `20.636`. The outcome of the rounding is `20.64`, since the digit following `3` is greater than 5.

One important thing to note here is that since `round()` returns a number, one can't enforce a given decimal place precision on the final number.

Consider the following code:

``````num = 2.5
print(round(num, 2))``````
2.5

We round the `2.5` to 2 decimal places and expect the result to be `2.50`. However, we get back the same value `2.5`. This is not an error with `round())` — rather, it's a limitation arising from the internal representation of floats.

It just isn't possible to store the same float in two ways with a different number of ending zero digits.

So what to do in such cases? What if we want to enfore the rounding to 2, 3, or any number of decimal places?

For such cases, we have to use strings. We'll see this later in this chapter.

Anyways, let's now understand negative values to the `precision` parameter.

``round(232.2, -1)``
230.0
``round(1687.5, -2)``
1700.0

`round(232.2, -1)` rounds `232.2` to the first digit before the units digit, that is highlighted as follows: `232.2`. The result is `230.0`, since the digit following `3` is lesser than `5`.

Now it's your turn to make intuition of the second statement here.

Note that in the snippet above, the results of the rounding expressions have a decimal point and a `0` at their end. This is because the return value of `round()` is of type `float`.

Anyways, if you have confusion in understanding the `precision` argument, the following explanation might be helpful.

#### Remembering the second argument to `round()`

One useful way of thinking about the second argument to `round()` is as follows:

Without any value, or with a value of `0`, it rounds the given number to the units digit. Taking `35094.146` as a reference value, the highlighted number below showcases this position:

`35094.146`

Calling `round(35094.146)` (or equivalently `round(35094.146, 0)`) would return `35094.0`.

A negative value shifts this position to the left, and a positive value shifts it to the right.

For example, `-1` would change the highlighted position as shown below:

`35094.146`

Calling `round(35094.146, -1)` would return `35090.0`.

Similarly, `1` would change the highlighted position as shown below:

`35094.146`

Calling `round(35094.146, 1)` would return `35094.1`.

## Truncation

Truncation is the name given to the process of removing the fractional part of a given number, if it exists. The fractional part is said to be truncated i.e cut off.

In Python, the `math` module provides a function to perform truncation of numbers. That is `trunc()`.

Here is its syntax:

``math.trunc(number)``

As stated before, when given integers, the `trunc()` function returns them as is, since integers don't have a fractional part. But for floats, it cuts off their fractional part and returns the left off integer.

Let's truncate a couple of numbers:

``import math``
``math.trunc(1.15)``
1
``math.trunc(-3.9)``
-3
``math.trunc(500)``
500
``math.trunc(-100.99)``
-100
Restating it: when a float is truncated, its fractional part is chopped off.

## Floor and ceil

In mathematics, there are two special functions that round off numbers to closest integers: ceil and floor.

The floor function rounds a number down to the largest closest integer. The ceil function, in contrast, rounds a number up to the smallest closest integer.

For instance, the floor of `3.2` is `3`, whereas its ceil of `4`. Similarly, the floor of `10.999` is `10`, while its ceil is `11`.

In Python, once again, the `math` module covers these two mathematical concepts in the functions `floor()` and `ceil()`.

The `floor()` function floors its argument and returns the result. Similarly, the `ceil()` function ceils its argument and returns the result.

Shown below are a couple of examples using `floor()`:

``import math``
``math.floor(15.6)``
15
``math.floor(1.99999999)``
1

And here we have a couple of examples using `ceil()`:

``import math``
``math.ceil(15.6)``
16
``math.ceil(0.000001)``
1
``math.ceil(-10.2)``
-10

#### Difference between `trunc()` and `floor()`

At first sight, one might think that `floor()` and `trunc()` do exactly the same thing, however the reality is that they don't!

They only do the same thing for positive numbers. For negative numbers this doesn't hold. A simple example can illustrate why:

The floor of `-2.13` would be the largest integer smaller than `-2.13`, and that is `-3`. However, truncating `-2.13` would give `-2`, throwing away `.13`. For negative numbers, `trunc()` doesn't floor the number, but rather ceils them.

## Rounding in strings

Let's now get back to our old problem of enforcing a given amount of decimal places on a given number. As we've seen above, doing so is not always possible using the `round()` function.

To solve this problem, we need string formatting. The string method `format()` formats a string by filling out given places in the string with given values (passed as arguments to the method).

Now, we won't go in detail of string formatting in this chapter - it's to be covered separately in the Python Strings Basics chapter.

For now, we'll just see how to use it for the purposes of rounding numbers.

Suppose we want to round `2.1` to 3 d.p. to give `2.100`. This is how it'll be done using `format()`:

``````num = '{:.3f}'.format(2.1)
print(num)``````
'2.100'

First a string is written — `format()` is a string method so obviously we have to start with a string. Then inside the string where ever we write a pair of curly braces, `format()` will replace these with a given value.

Then comes the `format()` method with the argument `2.1`. `format()` takes in arguments and puts them in corresponding places in the given string.

These places are denoted by a pair of curly braces. Wherever the first such pair occurs, the method replaces it with its first argument; wherever the second occurs, it's replaced with the second argument; and so on and so forth.

Inside the pair of curly braces, we can optionally even define how the replacing value should be formatted. For example, using the notation `{:.nf}` we can get the provided number to be written with a given number of decimal digits.

In our case, `{:.3f}` converts `2.1` to the string `'2.100'`, enforcing the extra zeroes at the end.

Similarly, `{:.5f}` would show `2.1` as `'2.10000'`, enforcing 5 digits after the decimal point.