Sé que Python //
redondea hacia el infinito negativo y en C++ /
se trunca, redondeando hacia 0.
Y esto es lo que sé hasta ahora:
|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
Pero, ¿por qué Python //
elige redondear hacia el infinito negativo? No encontré ningún recurso que explique eso, pero solo encontré y escuché a la gente decir vagamente: "por razones matemáticas" .
Por ejemplo, en ¿Por qué -1/2 se evalúa como 0 en C++, pero como -1 en Python? :
Las personas que manejan estas cosas en abstracto tienden a sentir que redondear hacia el infinito negativo tiene más sentido ( eso significa que es compatible con la función de módulo como se define en matemáticas, en lugar de que % tenga un significado un tanto divertido ).
Pero no veo que C++ /
no sea compatible con la función de módulo. En C++, (m/n)*n + m%n == m
también se aplica.
Entonces, ¿cuál es la razón (matemática) por la que Python elige el redondeo hacia el infinito negativo?
Consulte también la publicación de blog anterior de Guido van Rossum sobre el tema .
Pero, ¿por qué Python
//
elige redondear hacia el infinito negativo?
Según python-history.blogspot.com, Guido van Rossum eligió tal comportamiento para //
porque
(...) hay una buena razón matemática. La operación de división de enteros (//) y su hermana, la operación de módulo (%), van juntas y satisfacen una buena relación matemática (todas las variables son números enteros):
a/b = q con resto r
tal que
b*q + r = a y 0 <= r < b
(suponiendo que a y b son >= 0).
Si desea que la relación se extienda para a negativa (manteniendo b positiva), tiene dos opciones: si trunca q hacia cero, r se volverá negativa, de modo que el invariante cambie a 0 <= abs(r) < de lo contrario, puede bajar q hacia el infinito negativo, y el invariante sigue siendo 0 <= r < b(...) En teoría matemática de números, los matemáticos siempre prefieren la última opción (...). Para Python, tomé la misma decisión porque hay algunas aplicaciones interesantes de la operación de módulo donde el signo de a no es interesante. Considere tomar una marca de tiempo POSIX (segundos desde el comienzo de 1970) y convertirla en la hora del día. Como hay 24*3600 = 86400 segundos en un día, este cálculo es simplemente t % 86400. Pero si tuviéramos que expresar tiempos antes de 1970 usando números negativos, la regla de "truncar hacia cero" daría un resultado sin sentido. Usando la regla del piso todo sale bien. Otras aplicaciones en las que he pensado son los cálculos de posiciones de píxeles en gráficos por computadora. Estoy seguro de que hay más.
Entonces, resumiendo //
la elección del comportamiento se debe a mantenerlo consistente con el %
de comportamiento, este último fue seleccionado debido a su utilidad para trabajar con marcas de tiempo y píxeles negativos (antes del comienzo de 1970).
Aunque no puedo proporcionar una definición formal de por qué/cómo se eligieron los modos de redondeo, la cita sobre la compatibilidad con el operador %
, que ha incluido, tiene sentido si considera que %
no es exactamente lo mismo en C++ y Python.
En C++, es el operador de resto , mientras que en Python es el operador de módulo y, cuando los dos operandos tienen signos diferentes , no son necesariamente lo mismo. Hay algunas buenas explicaciones de la diferencia entre estos operadores en las respuestas a: ¿Cuál es la diferencia entre "mod" y "resto"?
Ahora, teniendo en cuenta esta diferencia, los modos de redondeo (truncamiento) para la división de enteros deben ser como en los dos idiomas, para garantizar que la relación que citó, (m/n)*n + m%n == m
, permanezca válido.
Aquí hay dos programas cortos que demuestran esto en acción (perdone mi código de Python algo ingenuo, soy un principiante en ese idioma):
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; }
Pitón:
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))
Tenga en cuenta que, para las entradas dadas de diferentes signos (-27 y 4), tanto el cociente como el resto/módulo son diferentes entre los idiomas, pero también que el valor de check
restaurado es correcto en ambos casos .