Encontré un comportamiento extraño en Python con respecto a los números negativos:
>>> -5 % 4
3
¿Alguien podría explicar qué está pasando?
Encontré un comportamiento extraño en Python con respecto a los números negativos:
>>> -5 % 4
3
¿Alguien podría explicar qué está pasando?
..., -9, -5, -1, 3, 7, ...
math.fmod
para obtener el mismo comportamiento que en C o Java.
Respuestas:
A diferencia de C o C ++, el operador de módulo de Python ( %
) siempre devuelve un número que tiene el mismo signo que el denominador (divisor). Tu expresión da 3 porque
(-5) / 4 = -1.25 -> piso (-1.25) = -2
(-5)% 4 = (-2 × 4 + 3)% 4 = 3.
Se elige sobre el comportamiento C porque un resultado no negativo suele ser más útil. Un ejemplo es calcular los días de la semana. Si hoy es martes (día # 2), ¿cuál es el día de la semana N días antes? En Python podemos calcular con
return (2 - N) % 7
pero en C, si N ≥ 3, obtenemos un número negativo que es un número inválido, y necesitamos arreglarlo manualmente agregando 7:
int result = (2 - N) % 7;
return result < 0 ? result + 7 : result;
(Consulte http://en.wikipedia.org/wiki/Modulo_operator para ver cómo se determina el signo del resultado para diferentes idiomas).
Aquí hay una explicación de Guido van Rossum:
http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html
Esencialmente, es para que a / b = q con el resto r conserve las relaciones b * q + r = a y 0 <= r <b.
a
, positivos b
, mientras que Python. Siempre es cierto eso abs(r) < b
, y ceil iff r <= 0
.
No existe una mejor manera de manejar la división de enteros y las modificaciones con números negativos. Sería bueno si a/b
fuera de la misma magnitud y signo opuesto de (-a)/b
. Sería bueno si a % b
fuera un módulo b. Como realmente queremos a == (a/b)*b + a%b
, los dos primeros son incompatibles.
Cuál mantener es una pregunta difícil y hay argumentos para ambas partes. C y C ++ redondean la división entera hacia cero (entonces a/b == -((-a)/b)
), y aparentemente Python no lo hace.
Como se señaló, Python modulo hace una excepción bien razonada a las convenciones de otros lenguajes.
Esto le da a los números negativos un comportamiento uniforme, especialmente cuando se usa en combinación con el //
operador de división de enteros, como %
suele ser el módulo (como en matemáticas. Divmod ):
for n in range(-8,8):
print n, n//4, n%4
Produce:
-8 -2 0
-7 -2 1
-6 -2 2
-5 -2 3
-4 -1 0
-3 -1 1
-2 -1 2
-1 -1 3
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3
%
siempre genera cero o positivo *//
siempre se redondea hacia el infinito negativo* ... siempre que el operando derecho sea positivo. Por otra parte11 % -10 == -9
En Python , el operador de módulo funciona así.
>>> mod = n - math.floor(n/base) * base
entonces el resultado es (para su caso):
mod = -5 - floor(-1.25) * 4
mod = -5 - (-2*4)
mod = 3
mientras que otros lenguajes como C, JAVA, JavaScript usan truncamiento en lugar de floor.
>>> mod = n - int(n/base) * base
lo que resulta en:
mod = -5 - int(-1.25) * 4
mod = -5 - (-1*4)
mod = -1
Si necesita más información sobre el redondeo en Python, lea esto .
Módulo, clases de equivalencia para 4:
Aquí hay un enlace al comportamiento de módulo con números negativos . (Sí, lo busqué en Google)
También pensé que era un comportamiento extraño de Python. Resulta que no estaba resolviendo bien la división (en papel); Le estaba dando un valor de 0 al cociente y un valor de -5 al resto. Terrible ... Olvidé la representación geométrica de los números enteros. Al recordar la geometría de los enteros dada por la recta numérica, uno puede obtener los valores correctos para el cociente y el resto, y verificar que el comportamiento de Python sea correcto. (Aunque supongo que ya hace tiempo que resolvió su inquietud).
También vale la pena mencionar que también la división en python es diferente de C: considere
>>> x = -10
>>> y = 37
en C esperas el resultado
0
¿Qué es x / y en Python?
>>> print x/y
-1
y% es módulo, ¡no el resto! Mientras que x% y en C produce
-10
Python rinde.
>>> print x%y
27
Puede obtener ambos como en C
La división:
>>> from math import trunc
>>> d = trunc(float(x)/y)
>>> print d
0
Y el resto (usando la división de arriba):
>>> r = x - d*y
>>> print r
-10
Este cálculo tal vez no sea el más rápido, pero funciona para cualquier combinación de signos de xey para lograr los mismos resultados que en C y además evita las declaraciones condicionales.