Recently we released a post on the floor division and modulo operators, where we highlighted some potentially unexpected behaviour when using these operators with negative numbers. The source of this unexpected behaviour turned out to be the `floor` function: one of several rounding functions defined in the `math` module.

In this post I want to go into a little more detail about these rounding functions, in addition to the built-in `round` function, and highlight some things you should be aware of when using them.

## Floor

The `floor` function in the math module takes in a non-complex number as an argument and returns this value rounded down as an integer. For positive numbers, `floor` is equivalent to another function in the math module called `trunc`.

``````>>> floor(3.1)
3
>>> trunc(3.1)
3
``````

However, the behaviour of `floor` and `trunc` begins to diverge when we pass in negative numbers as arguments.

``````>>> floor(-3.1)
-4
>>> trunc(-3.1)
-3
``````

So why does `floor(-3.1)` return `-4`? The answer can be found in the Python documentation for the math module.

Return the floor of x, the largest integer less than or equal to x.

So `floor(-3.1)` returns `-4` because `-4` is the largest number less than `-3.1`. It is further left along the number line.

`trunc` on the other hand is simply truncating the value we provide as an argument, throwing away everything after the decimal point.

The important takeaway here, is that `floor` rounds towards zero for positive numbers, and away from zero for negative numbers.

## Ceil

The `ceil` function is the opposite of `floor`.

Return the ceiling of x, the smallest integer greater than or equal to x.

For positive numbers, `ceil` rounds away from zero.

``````>>> ceil(3.1)
4
>>> ceil(5.7)
6
``````

But for negative numbers, `ceil` rounds towards zero.

``````>>> ceil(-3.1)
-3
>>> ceil(-5.7)
-5
``````

In the above example, `-3` is greater than `-3.1`. It's closer to zero.

## Round

Unlike `ceil`, `floor`, and `trunc`, `round` can be found in the standard library as a built-in function. The documentation can be found here.

I think with round, it's best to look at a few examples first.

``````>>> round(3.5)
4
>>> round(2.5)
2
>>> round(2.51)
3
>>> round(-3.5)
-4
>>> round(-2.5)
-2
``````

Okay, so the first thing to notice is that `round`, unlike `ceil` and `floor` provides the same result for positive and negative numbers, just with the opposite sign. There is something fishy going on, however. `2.5` rounded to `2` (rounding down), but `3.5` rounded to `4` (rounding up). What's going on?

### Bankers' rounding

As it turns out, `round` implements a type of rounding called bankers' rounding. So, what is bankers' rounding? And why does it exist?

In most cases, bankers' rounding works as we might expect. It rounds to the closest significant figure. So `0.346` rounded to two decimal places yields `0.35`. `5.3` rounded to the nearest integer yields `5`. Bankers' rounding is special in how it deals with ties.

In the event of a tie, for example `3.5`, which is equally close to `3` and `4`, bankers' rounding always rounds towards the closest even number. `3.5` therefore rounds towards `4`, but `2.5` rounds towards `2`, as `2.5` is much closer to `2` than `4`.

Why would we want to do this kind of rounding?

The main reason is that for large sets of numbers, bankers' rounding is less biased, so a series of additions and subtractions with rounded numbers more accurately represents the true total of the unrounded numbers. We can easily imagine a case with a large amount of positive numbers get rounded up, therefore inflating the final result. Using bankers' rounding, many of those numbers would instead be rounded down, balancing those that were rounded up, and producing a more accurate result.

## Recap

• `floor` always rounds towards zero for positive numbers, but away from zero for negative numbers. `3.1` therefore rounds to `3` using `floor`, but `-3.1` rounds to `-4`.
• `ceil` is the opposite of `floor`, and `ceil` always rounds away from zero for positive numbers, but towards zero for negative numbers.
• `trunc` performs truncation, returning the integer portion of a given number.
• `round` implements a type of rounding called bankers' rounding. In bankers' rounding, we round towards the closest significant figure, except in the case of a tie. In the event of a tie, we  round towards the closest even significant figure. So `3.5` rounds to `4`, but `2.5` rounds to `2`.

I hope you learnt something new, and if you're looking to upgrade your Python skills even further, you might want to check out our Complete Python Course.