La operación de módulo en números negativos en Python


94

Encontré un comportamiento extraño en Python con respecto a los números negativos:

>>> -5 % 4
3

¿Alguien podría explicar qué está pasando?


25
me parece bien
wheaties

6
..., -9, -5, -1, 3, 7, ...
NullUserException


8
Puede utilizar math.fmodpara obtener el mismo comportamiento que en C o Java.
0x2b3bfa0

Respuestas:


137

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).


6
Sorprendentemente, el operador de módulo de Python (%) no siempre devuelve un número con el mismo signo que el denominador (divisor). Ver stackoverflow.com/questions/48347515/…
zezollo


9

No existe una mejor manera de manejar la división de enteros y las modificaciones con números negativos. Sería bueno si a/bfuera de la misma magnitud y signo opuesto de (-a)/b. Sería bueno si a % bfuera 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.


1
"Sería bueno si a / b tuviera la misma magnitud y el signo opuesto de (-a) / b". ¿Por qué sería bueno? ¿Cuándo es ese un comportamiento deseado?
user76284

Porque entonces actuaría de la misma manera que la división y la multiplicación regulares y, por lo tanto, es intuitivamente fácil de trabajar. Sin embargo, eso puede no tener sentido matemáticamente.
Demis

6

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
  • Python %siempre genera cero o positivo *
  • Python //siempre se redondea hacia el infinito negativo

* ... siempre que el operando derecho sea positivo. Por otra parte11 % -10 == -9


Gracias, tu ejemplo me hizo entenderlo :)
Lamis

5

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 .



1

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).


1

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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.