Today I learned a new thing that forced me to reckon my understanding of Python. It is about
//. It is just not a double slash or typo. It is an operator called integer division. The detail about how this operator works is mentioned in PEP 238. So I came across the Code Signal test and stuck at this question:
I thought that the result of both snippets should be the same. Because in Python, it uses // and in Java, it uses
int data type. I don’t want to judge alone; you see that the question itself was downvoted a lot. Well, I downvoted it too!
Here are the answers:
I tried to run the Java (or C++) snippet with an online C++ compiler and played with a random number, but no clue. However, I know that the problem lies in how the rounding process. Maybe Java and C++ round the number to ceil instead of the floor, or vice versa. Fortunately, I gave up quickly and look at
// instead. As everybody knows, me included, that
// yields an integer:
5//4 # 1 1.25 3//2 # 1 17//3 # 5
/ yields a floating-point number:
5/4 #1.25 3/2 # 1.5 17/3 # 5.666666666666667
But I don’t know that
// is using
floor division! as mentioned on PEP 238 page:
Floor division will be implemented in all the Python numeric types and will have the semantics of:
a // b == floor(a/b)
Except that the result type will be the common type into which a and b are coerced before the operation.
Meh, maybe you already guess that, from two snippets before you noticed that
5, instead of
6. You may also think that it is maybe
truncate. But did you know that in negative numbers for example
17//-3, the result is not
-6? I did not, at least until today. This stuff is easy if you take a look at the image below:
I just realized that when dealing with a negative number, the
floor is toward greater digits, in a negatively way. Pun intended. That makes sense. Why
17//-3 is equal to
-6. Here are other examples:
import numpy np.ceil((-1.9, -1.5, -1.1, 0, 1.1, 1.5, 1.9)) # array([-1., -1., -1., 0., 2., 2., 2.]) np.floor((-1.9, -1.5, -1.1, 0, 1.1, 1.5, 1.9)) # array([-2., -2., -2., 0., 1., 1., 1.]) np.round_((-1.9, -1.5, -1.1, 0, 1.1, 1.5, 1.9)) # array([-2., -2., -1., 0., 1., 2., 2.])
Now it is clear how
After digging the rabbit’s hole deeper, I can’t ignore how the
round function works. Just in case. Let’s take a look at the
round function. It is a bit tricky they said:
Note The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float. See Floating Point Arithmetic: Issues and Limitations for more information.
This is totally understandable since it is an unavoidable technical error about how a computer represents a floating-point number 1. Nevertheless, it is only matters if we work with something that requires cautious number operation.
NumPy also posted a special note about how NumPy
round_() (equivalent with
around()) function works:
For values exactly halfway between rounded decimal values, NumPy rounds to the nearest even value. Thus 1.5 and 2.5 round to 2.0, -0.5 and 0.5 round to 0.0, etc.
This blog post certainly will help me to remember that I should do a test when dealing with division and negative floating-point numbers. I hope it will help you too.