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
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 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
>>> floor(3.1) 3 >>> trunc(3.1) 3
However, the behaviour of
trunc begins to diverge when we pass in negative numbers as arguments.
>>> floor(-3.1) -4 >>> trunc(-3.1) -3
So why does
-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.
-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 function is the opposite of
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 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
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?
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
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
4, bankers' rounding always rounds towards the closest even number.
3.5 therefore rounds towards
2.5 rounds towards
2.5 is much closer to
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.
flooralways rounds towards zero for positive numbers, but away from zero for negative numbers.
3.1therefore rounds to
ceilis the opposite of
ceilalways rounds away from zero for positive numbers, but towards zero for negative numbers.
truncperforms truncation, returning the integer portion of a given number.
roundimplements 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
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.