I know Python //
rounds towards negative infinity and in C++ /
is truncating, rounding towards 0.
And here's what I know so far:
|remainder|
-12 / 10 = -1, - 2 // C++
-12 // 10 = -2, + 8 # Python
12 / -10 = -1, 2 // C++
12 // -10 = -2, - 8 # Python
12 / 10 = 1, 2 // Both
12 // 10 = 1, 2
-12 / -10 = 1, - 2 // Both
= 2, + 8
C++:
1. m%(-n) == m%n
2. -m%n == -(m%n)
3. (m/n)*n + m%n == m
Python:
1. m%(-n) == -8 == -(-m%n)
2. (m//n)*n + m%n == m
But why Python //
choose to round towards negative infinity? I didn't find any resources explain that, but only find and hear people say vaguely: "for mathematics reasons".
For example, in Why is -1/2 evaluated to 0 in C++, but -1 in Python?:
People dealing with these things in the abstract tend to feel that rounding toward negative infinity makes more sense (that means it's compatible with the modulo function as defined in mathematics, rather than % having a somewhat funny meaning).
But I don't see C++ 's /
not being compatible with the modulo function. In C++, (m/n)*n + m%n == m
also applies.
So what's the (mathematical) reason behind Python choosing rounding towards negative infinity?
But why Python
//
choose to round towards negative infinity?
According to python-history.blogspot.com Guido van Rossum elected such behavior for //
because
(...)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).
If you want the relationship to extend for negative a (keeping b positive), you have two choices: if you truncate q towards zero, r will become negative, so that the invariant changes to 0 <= abs(r) < otherwise, you can floor q towards negative infinity, and the invariant remains 0 <= r < b(...) In mathematical number theory, mathematicians always prefer the latter choice (...). For Python, I made the same choice because there are some interesting applications of the modulo operation where the sign of a is uninteresting. Consider taking a POSIX timestamp (seconds since the start of 1970) and turning it into the time of day. Since there are 24*3600 = 86400 seconds in a day, this calculation is simply t % 86400. But if we were to express times before 1970 using negative numbers, the "truncate towards zero" rule would give a meaningless result! Using the floor rule it all works out fine. Other applications I've thought of are computations of pixel positions in computer graphics. I'm sure there are more.
So summing it up //
behavior choice is due to keeping it consistent with %
behavior, latter was selected due to its usefulness in working with negative (before start of 1970) timestamps and pixels.
Although I can't provide a formal definition of why/how the rounding modes were chosen as they were, the citation about compatibility with the %
operator, which you have included, does make sense when you consider that %
is not quite the same thing in C++ and Python.
In C++, it is the remainder operator, whereas, in Python, it is the modulus operator – and, when the two operands have different signs, these aren't necessarily the same thing. There are some fine explanations of the difference between these operators in the answers to: What's the difference between “mod” and “remainder”?
Now, considering this difference, the rounding (truncation) modes for integer division have to be as they are in the two languages, to ensure that the relationship you quoted, (m/n)*n + m%n == m
, remains valid.
Here are two short programs that demonstrate this in action (please forgive my somewhat naïve Python code – I'm a beginner in that language):
C++:
#include <iostream>
int main()
{
int dividend, divisor, quotient, remainder, check;
std::cout << "Enter Dividend: "; // -27
std::cin >> dividend;
std::cout << "Enter Divisor: "; // 4
std::cin >> divisor;
quotient = dividend / divisor;
std::cout << "Quotient = " << quotient << std::endl; // -6
remainder = dividend % divisor;
std::cout << "Remainder = " << remainder << std::endl; // -3
check = quotient * divisor + remainder;
std::cout << "Check = " << check << std::endl; // -27
return 0;
}
Python:
print("Enter Dividend: ") # -27
dividend = int(input())
print("Enter Divisor: ") # 4
divisor = int(input())
quotient = dividend // divisor;
print("Quotient = " + str(quotient)) # -7
modulus = dividend % divisor;
print("Modulus = " + str(modulus)) # 1
check = quotient * divisor + modulus; # -27
print("Check = " + str(check))
Note that, for the given inputs of different signs (-27 and 4), both the quotient and remainder/modulus are different between the languages but also that the restored check
value is correct in both cases.