Operación de módulo con números negativos

En el progtwig de CA, estaba probando las siguientes operaciones (solo para verificar el comportamiento)

x = 5 % (-3); y = (-5) % (3); z = (-5) % (-3); printf("%d ,%d ,%d", x, y, z); 

me dio salida como (2, -2 , -2) en gcc. Esperaba un resultado positivo todo el tiempo. ¿Puede un módulo ser negativo? ¿Alguien puede explicar este comportamiento?

C99 requiere que cuando a/b sea ​​representable:

(a/b) * b + a%b será igual a

Esto tiene sentido, lógicamente. ¿Derecha?

Veamos a qué conduce esto:


Ejemplo A. 5/(-3) es -1

=> (-1) * (-3) + 5%(-3) = 5

Esto solo puede suceder si el 5%(-3) es 2.


Ejemplo B. (-5)/3 es -1

=> (-1) * 3 + (-5)%3 = -5

Esto solo puede suceder si (-5)%3 es -2

El operador % en C no es el operador de módulo sino el operador restante .

Los operadores de módulo y rest difieren con respecto a los valores negativos.

Con un operador de rest, el signo del resultado es el mismo que el signo del dividendo, mientras que con un operador de módulo, el signo del resultado es el mismo que el del divisor.

C define la operación % para a % b como:

  a == (a / b * b) + a % b 

con / la división entera con truncamiento hacia 0 . Ese es el truncamiento que se realiza hacia 0 (y no hacia la infinitud negativa) que define el % como un operador de rest en lugar de un operador de módulo.

Basado en la Especificación C99: a = (a / b) * b + a % b

Podemos escribir una función para calcular (a % b) = a - (a / b) * b !

 int remainder(int a, int b) { return a - (a / b) * b; } 

Para la operación del módulo, podemos tener la siguiente función (suponiendo que b> 0)

 int mod(int a, int b) { int r = a % b; return r < 0 ? r + b : r; } 

Mi conclusión es (a% b) en C es un operador de rest y no un operador de módulo.

No creo que haya ninguna necesidad de verificar si el número es negativo. La función general más simple para encontrar el módulo positivo sería esta: funcionaría en los valores positivos y negativos de x.

 int modulo(int x,int N){ return (x % N + N) %N; } 

Las otras respuestas han explicado en C99 o posterior, la división de enteros que involucran operandos negativos siempre se trunca hacia cero .

Tenga en cuenta que, en C89 , si el resultado redondeado hacia arriba o hacia abajo está definido por la implementación. Como (a/b) * b + a%b es igual a a en todos los estándares, el resultado de % involucra operandos negativos también se define en la implementación en C89.

El resultado de la operación Modulo depende del signo del numerador, y por lo tanto obtienes -2 para y y z

Aquí está la referencia

http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_14.html

División entera

Esta sección describe las funciones para realizar la división de enteros. Estas funciones son redundantes en la biblioteca GNU C, ya que en GNU C el operador ‘/’ siempre se redondea hacia cero. Pero en otras implementaciones de C, ‘/’ puede redondear de manera diferente con argumentos negativos. div y ldiv son útiles porque especifican cómo redondear el cociente: hacia cero. El rest tiene el mismo signo que el numerador.

En Matemáticas, de donde surgen estas convenciones, no hay ninguna afirmación de que la aritmética de módulo deba arrojar un resultado positivo.

P.ej.

1 mod 5 = 1, pero también puede ser igual a -4. Es decir, 1/5 produce un rest 1 de 0 o -4 de 5. (Ambos factores de 5)

Del mismo modo, -1 mod 5 = -1, pero también puede ser igual a 4. Es decir, -1/5 produce un rest -1 de 0 o 4 de -5. (Ambos factores de 5)

Para más información, busque en las clases de equivalencia en Matemáticas.

El operador de módulo da el rest. El operador de módulo en c generalmente toma el signo del numerador

  1. x = 5% (-3) – aquí el numerador es positivo, por lo tanto, resulta en 2
  2. y = (-5)% (3) – aquí el numerador es negativo, por lo tanto resulta -2
  3. z = (-5)% (-3) – aquí el numerador es negativo, por lo tanto resulta -2

También el operador de módulo (rest) solo se puede usar con el tipo entero y no se puede usar con coma flotante.

El operador de módulo es como el operador de mod cuando el número es positivo, pero diferente si el número es negativo.

Muchas veces en los problemas se nos pide que demos la respuesta modulo 10 ^ 9 + 7.

Deje que la respuesta (antes de usar módulo) se denote por ‘a’.

Regla sencilla y directa

si a es positivo , entonces un módulo 10 ^ 9 + 7 = a% (10 ^ 9 + 7)

si a es negativo , entonces un módulo 10 ^ 9 + 7 = (a% (10 ^ 9 + 7)) + (10 ^ 9 + 7)

Si, en tales problemas, encontramos que cualquier paso del ciclo puede calcular un valor que está fuera del rango entero (si estamos usando enteros), entonces podemos usar el operador de módulo en ese paso en sí. La respuesta final será como si hubiéramos usado el operador de módulo solo una vez.

Esto es porque- (a * b)% c = ((a% c) (b% c))% c Lo mismo vale para sumr y restar.

De acuerdo con el estándar C99 , sección 6.5.5 Operadores multiplicativos , se requiere lo siguiente:

 (a / b) * b + a % b = a 

Conclusión

El signo del resultado de una operación restante, de acuerdo con C99, es el mismo que el dividendo.

Veamos algunos ejemplos ( dividend / divisor ):

Cuando solo el dividendo es negativo

 (-3 / 2) * 2 + -3 % 2 = -3 (-3 / 2) * 2 = -2 (-3 % 2) must be -1 

Cuando solo el divisor es negativo

 (3 / -2) * -2 + 3 % -2 = 3 (3 / -2) * -2 = 2 (3 % -2) must be 1 

Cuando tanto el divisor como el dividendo son negativos

 (-3 / -2) * -2 + -3 % -2 = -3 (-3 / -2) * -2 = -2 (-3 % -2) must be -1 

6.5.5 Operadores multiplicativos

Sintaxis

  1. expresión multiplicativa
    • cast-expression
    • multiplicative-expression * cast-expression
    • multiplicative-expression / cast-expression
    • multiplicative-expression % cast-expression

Restricciones

  1. Cada uno de los operandos debe tener un tipo aritmético. Los operandos del operador % tendrán un tipo de entero.

Semántica

  1. Las conversiones aritméticas habituales se realizan en los operandos.

  2. El resultado del operador binario * es el producto de los operandos.

  3. El resultado del operador / es el cociente de la división del primer operando por el segundo; el resultado del operador % es el rest. En ambas operaciones, si el valor del segundo operando es cero, el comportamiento no está definido.

  4. Cuando los enteros se dividen, el resultado del operador / es el cociente algebraico con cualquier parte fraccional descartada [1]. Si el cociente a/b es representable, la expresión (a/b)*b + a%b será igual a .

[1]: Esto a menudo se llama “truncamiento hacia cero”.