2008-09-04 14 views
15

¿Puede decirme cuánto es (-2) % 5? De acuerdo con mi intérprete de Python es 3, pero ¿tiene una buena explicación para esto?Funcionamiento del módulo con valores negativos - ¿Algo raro?

He leído que en algunos idiomas el resultado puede ser dependiente de la máquina, pero no estoy seguro.

+0

Puede usar 'math.fmod' para obtener el mismo comportamiento que en C o Java. – Helio

Respuesta

16

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 mayor parte acordados estados definición matemática que el módulo de un y b es el (estrictamente positivo) r descansar de la división de un /b . Más precisamente, 0 < = r < b por definición.

11

Su 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

+1

Depende de cómo se defina la división entera. Si la división se redondea hacia 0, entonces el resto debería tener el mismo signo que el cociente, de modo que 'b * (a/b) + a% b == a'. Si la división se redondea hacia el infinito negativo (como en Python), el resto siempre debe ser positivo. – augurar

0

Bueno, -2 dividido por 5 sería 0 con un remanente de 3. No creo que deba depender mucho de la plataforma, pero he visto cosas extrañas.

+3

Seguramente significa: "-2 dividido por 5 sería -1 con un resto de 3", ¿verdad? Esto es lo que hace Python, de todos modos. – tzot

+0

En algunos sistemas, -2 dividido por 5 es 0 con un resto de -2. En otros, es -1 con un resto de 3. Solo por gusto, no hay una respuesta "correcta". – augurar

0

De hecho, es 3. En modular arithmetic, un módulo es simplemente el resto de una división, y el resto de -2 dividido por 5 es 3.

+0

En la expresión 'c = a% b',' b' es el módulo, no 'c'. – augurar

4

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 a lo largo de esa lógica, debe ser -2 3.

La manera más fácil de pensar en cómo va a funcionar es que se mantenga la adición o sustracción 5 hasta que el número se sitúa entre 0 (ambos 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.

0

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

0

Una explicación podría ser que los números negativos se almacenan usando 2's complement. Cuando el intérprete de Python intenta hacer la operación de módulo, se convierte en valor sin signo. Como tal en lugar de hacer (-2)% 5, en realidad calcula 0xFFFF_FFFF_FFFF_FFFD% 5 que es 3.

4

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.

Según la Python reference manual,

El operador 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 de Python. Básicamente Modulo se define de manera que esto siempre tiene:

x == (x/y)*y + (x%y) 

así que tiene sentido que (-2) 5% = -2 - (-2/5) * 5 = 3

0

Tenga cuidado de no confíe en este comportamiento de mod en C/C++ en todos los sistemas operativos y arquitecturas. Si no recuerdo mal, me trató de apoyarse 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 deslizó en cuando me gustaría compilar en un solo sistema operativo, pero las cosas serían funciona bien en otro sistema operativo. ¡Esto provocó una depuración de mal tiempo, ya que solo ocurrió la mitad del tiempo!

6

Al igual que la documentación dice en Binary arithmetic operations, Python asegura que: los operadores

La división de enteros y de módulo están conectadas 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 en verdad,

>>> divmod(-2, 5) 
(-1, 3). 

Otra manera de visualizar la uniformidad de este método es calcular divmod por 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) 
0

No parece haber una confusión común entre los términos "módulo" y "resto".

En matemáticas, un resto debe siempre ser definido de conformidad con el cociente, por lo que si a/b == c rem d continuación (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 coherente con la división de redondeo a infinito si se permiten 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 a cero IIRC, pero tiene los operadores mod y rem.

La política C tiene como objetivo permitir a los compiladores elegir la implementación más eficiente para la máquina, pero IMO 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 usar 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.

Cuestiones relacionadas