What is the reason for difference between integer division and float to int conversion in python?

Question:

I have recently noticed that int() rounds a float towards 0, while integer division rounds a float towards its floor.

for instance:

-7 // 2 == -4
int(-7/2) == -3

I have read the documentation which specifies:

class int(x, base=10)

Return an integer object constructed from a number or string x, or return 0 if no arguments are >given. If x is a number, return x.__int__(). For floating point numbers, this truncates towards zero.

and:

floor division

Mathematical division that rounds down to nearest integer. The floor division operator is //. For example, the expression 11 // 4 evaluates to 2 in contrast to the 2.75 returned by float true division. Note that (-11) // 4 is -3 because that is -2.75 rounded downward. See PEP 238.

But it seems illogical for me that 2 similar operations (float division to integer) should return different results.

Is there any motivation for the differences between the functions?

Asked By: Isdj

||

Answers:

Consistency.

You’ll need to follow some very basic and seemingly irrelevant explanations to understand it.

In school you have learned division with a remainder. And you have done calculations like this:

8 ÷ 4 = 2 R 0
7 ÷ 4 = 1 R 3
6 ÷ 4 = 1 R 2
5 ÷ 4 = 1 R 1
4 ÷ 4 = 1 R 0
3 ÷ 4 = 0 R 3
2 ÷ 4 = 0 R 2
1 ÷ 4 = 0 R 1
0 ÷ 4 = 0 R 0
        ^------ This is the result of x // 4
            ^-- This is the result of x % 4 (modulo)

Later, you have learned divisions for real numbers:

8 ÷ 4 = 2.0
7 ÷ 4 = 1.75
6 ÷ 4 = 1.5
5 ÷ 4 = 1.25
4 ÷ 4 = 1.0
3 ÷ 4 = 0.75
2 ÷ 4 = 0.5
1 ÷ 4 = 0.25
0 ÷ 4 = 0.0
        ^--- Note that the number in front of the . is int(x/4)

Until this point, you might believe that x // 4 and int(x/4) always give the same result. That’s your current understanding of the situation.

However, have a look what happens in the integer division: the number behind R cycles from 3, 2, 1 to 0 and then restarts: 3, 2, 1, 0. The number in front of the R decreses every 4th step.

So, how will it go on?

 8 ÷ 4 =  2 R 0
 7 ÷ 4 =  1 R 3
 6 ÷ 4 =  1 R 2
 5 ÷ 4 =  1 R 1
 4 ÷ 4 =  1 R 0
 3 ÷ 4 =  0 R 3
 2 ÷ 4 =  0 R 2
 1 ÷ 4 =  0 R 1
 0 ÷ 4 =  0 R 0
-1 ÷ 4 = -1 R 3
         ^------ We have to decrease now, because we already have 0 four times
              ^-- We have to restart the cycle at 3

At the same time, the real number division gives us:

-1 ÷ 4 = -0.25
          ^----- There is still a 0 in front of the .

That’s why -1 // 4 gives -1 but int(-1/4) gives 0.

Is there any motivation for the differences between the functions?

Well, they serve different purposes: // is part of an integer calculation with remainders and int() gives you the part in front of the . of a real number operation.

You decide what you want to calculate, then you decide which operator to use in Python to get the correct result.

Good question. Keep on learning.

Answered By: Thomas Weller

I would say that your observation that those 2 operations should be intuitively similar is expected since on positive numbers they behave identically. But if you look at their origins (one comes from mathematics and the other from computer science) then it makes more sense their different behavior.

You can look behind there concepts:

  • Floor division aka the floor function applied to the math division
  • Type conversion/Type casting

==================================================================

I)Floor division aka the floor function applied to the math division

The floor function is a very well established concept in mathematics.

From mathworld.wolfram:

The floor function |_ x_ |, also called the greatest integer function or integer value (Spanier and Oldham 1987), gives the largest integer less than or equal to x. The name and symbol for the floor function were coined by K. E. Iverson (Graham et al. 1994)

So floor division is nothing more than floor function applied to the math division. The behavior is very clear, “mathematically precise”.

II)Type conversion/Type casting

From wikipedia:

In computer science, type conversion, type casting, type
coercion and type juggling are different ways of changing an
expression from one data type to another.

In most of the programming languages, the casting form float to integer is applied by rounding rule (so there is a convention) :

  • Round toward 0 – directed rounding towards zero (also known as
    truncation)

Rounding rule according to IEEE 754.


So, in other words, the reason for the difference between integer division and float to int conversion in python is a mathematical one, here are some thoughts from Guido van Rossum (I guess I do not have to introduce him :D) (from the blog The history of Python, article “Why Python’s Integer Division Floors”)

This disturbs some people, but there is a good mathematical reason.
The integer division operation (//) and its sibling, the modulo
operation (%), go together and satisfy a nice mathematical
relationship (all variables are integers):

a/b = q with remainder r

such that

b*q + r = a and 0 <= r < b

(assuming a and b are >= 0).

Answered By: kederrac

Based on the answer by @thomas-weller I also found myself a maybe novice explanation for the floor division result from his example of division with a remainder:

  • 7 / 4 = 1 R 3 = 1 + 0,75 = 1.75

  • -> R3 = 3/4 = 0.75

  • -1 /4 = -1 R 3 = -1 + 0,75 (R3) = -0.25

Answered By: s_horus