python - operator - Operación del módulo con valores negativos-¿Algo raro?
python module operator (12)
Bueno, -2 dividido por 5 sería 0 con un resto de 3. No creo que deba depender mucho de la plataforma, pero he visto cosas extrañas.
¿Puedes decirme cuánto es (-2) % 5
? Según mi intérprete de Python es 3, ¿pero tienes una explicación sensata para esto?
He leído que en algunos idiomas el resultado puede depender de la máquina, pero no estoy seguro.
Bueno, 0% 5 debería ser 0, ¿verdad?
-1% 5 debería ser 4 porque ese es el próximo dígito permitido que va en la dirección inversa (es decir, no puede ser 5, ya que está fuera de rango).
Y siguiendo esa lógica, -2 debe ser 3.
La forma más fácil de pensar cómo funcionará es que sigas sumando o restando 5 hasta que el número se encuentre entre 0 (inclusive) y 5 (exclusivo).
No estoy seguro acerca de la dependencia de la máquina. Nunca he visto una implementación que fuera, pero no puedo decir que nunca haya terminado.
Como se explica en otras respuestas, hay muchas opciones para una operación de módulo con valores negativos. En general, diferentes idiomas (y diferentes arquitecturas de máquina) darán un resultado diferente.
De acuerdo con el manual de referencia de Python ,
El operador de módulo siempre produce un resultado con el mismo signo que su segundo operando (o cero); el valor absoluto del resultado es estrictamente menor que el valor absoluto del segundo operando.
es la elección tomada por Python. Básicamente, el módulo se define de modo que esto siempre se cumple:
x == (x/y)*y + (x%y)
entonces tiene sentido que (-2)% 5 = -2 - (-2/5) * 5 = 3
De hecho, es 3. En la aritmética modular , un módulo es simplemente el resto de una división, y el resto de -2 dividido por 5 es 3.
El resultado de la operación de módulo en negativos parece depender del lenguaje de programación y aquí hay una lista http://en.wikipedia.org/wiki/Modulo_operation
El resultado depende del idioma. Python devuelve el signo del divisor, donde, por ejemplo, c # devuelve el signo del dividendo (es decir, -2% 5 devuelve -2 en c #).
Por cierto: la mayoría de los lenguajes de programación estarían en desacuerdo con Python y darían el resultado -2
. Dependiendo de la interpretación del módulo, esto es correcto. Sin embargo, la definición matemática más acordada establece que el módulo de a y b es el resto r (estrictamente positivo) de la división de a / b . Más precisamente, 0 <= r < b por definición.
Tenga cuidado de no confiar en este comportamiento de mod en C / C ++ en todos los sistemas operativos y arquitecturas. Si recuerdo correctamente, traté de confiar en el código C / C ++ como
float x2 = x % n;
para mantener x2 en el rango de 0 a n-1, pero los números negativos se arrastraron cuando compilaría en un sistema operativo, pero las cosas funcionarían bien en otro sistema operativo. ¡Esto provocó una depuración de mal tiempo, ya que solo ocurrió la mitad del tiempo!
Una explicación podría ser que los números negativos se almacenan usando el complemento de 2 . Cuando el intérprete de Python intenta hacer la operación de módulo, se convierte en un valor sin signo. Como tal, en lugar de hacer (-2)% 5, en realidad calcula 0xFFFF_FFFF_FFFF_FFFD% 5 que es 3.
Al igual que la documentación dice en operaciones aritméticas binarias , Python asegura que:
Los operadores de división entera y módulo están conectados por la siguiente identidad:
x == (x/y)*y + (x%y)
. La división entera y el módulo también están conectados con la función incorporada divmod ():divmod(x, y) == (x/y, x%y)
.
Y de verdad,
>>> divmod(-2, 5)
(-1, 3).
Otra forma de visualizar la uniformidad de este método es calcular divmod
para una pequeña secuencia de números:
>>> for number in xrange(-10, 10):
... print divmod(number, 5)
...
(-2, 0)
(-2, 1)
(-2, 2)
(-2, 3)
(-2, 4)
(-1, 0)
(-1, 1)
(-1, 2)
(-1, 3)
(-1, 4)
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(0, 4)
(1, 0)
(1, 1)
(1, 2)
(1, 3)
(1, 4)
Parece haber una confusión común entre los términos "módulo" y "resto".
En matemáticas, un resto siempre debe definirse de manera coherente con el cociente, de modo que si a / b == c rem d
entonces (c * b) + d == a
. Dependiendo de cómo redondee su cociente, obtiene diferentes remanentes.
Sin embargo, módulo siempre debe dar un resultado 0 <= r < divisor
, que solo es consistente con la división de redondeo a infinito si permite números enteros negativos. Si la división se redondea hacia cero (lo cual es común), módulo y resto solo son equivalentes para valores no negativos.
Algunos lenguajes (notablemente C y C ++) no definen los comportamientos de redondeo / resto requeridos y %
es ambiguo. Muchos definen el redondeo como hacia cero, aunque usan el término módulo donde el resto sería más correcto. Python es relativamente inusual en cuanto redondea al infinito negativo, por lo que el módulo y el resto son equivalentes.
Ada redondea hacia cero IIRC, pero tiene operadores mod
y rem
.
La política C tiene la intención de permitir a los compiladores elegir la implementación más eficiente para la máquina, pero la OMI es una optimización falsa, al menos en estos días. Un buen compilador probablemente podrá usar la equivalencia para la optimización dondequiera que un número negativo no pueda ocurrir (y casi seguramente si usa tipos sin firmar). Por otro lado, donde pueden ocurrir números negativos, es casi seguro que se preocupan por los detalles; por razones de portabilidad, debe utilizar algoritmos y / o controles overcomplex cuidadosamente diseñados para asegurarse de obtener los resultados que desea, independientemente del redondeo y el resto comportamiento.
En otras palabras, la ganancia para esta "optimización" es mayormente (si no siempre) una ilusión, mientras que en algunos casos hay costos muy reales, por lo que es una optimización falsa.
Tu intérprete de Python es correcto. Una forma (estúpida) de calcular un módulo es restar o agregar el módulo hasta que el valor resultante esté entre 0 y (módulo - 1).
por ejemplo: 13 mod 5 = (13 - 5) mod 5 = (13 - 10) mod 5 = 3
o en su caso: -2 mod 5 = (-2 + 5) mod 5 = 3