residuales - operacion modulo
¿Cuáles son las reglas para la aritmética modular en C? (3)
El operador % se implementa de manera tal que a == b * (a / b) + (a % b) es verdadero, donde usamos la división entera.
En este caso, -111 / 11 es -10 , por lo que -111 == 11 * -10 + x se cumple con x == -1 .
En clases anteriores, me enseñaron que n % d = r y pensar en ello como n = d*q + r , donde d es el divisor, q es el cociente r es el resto (observando que el resto nunca puede ser negativo).
Entonces, por ejemplo, -111 mod 11 es 10 , porque -111 = -11*-11 + 10 (a diferencia de -111 = -11*10 -1 , dado que eso nos daría un resto negativo).
Sin embargo, cuando se imprimen los resultados de -111 % 11 , -1 es el resultado y no 10 . ¿Por qué? ¿No es esto técnicamente incorrecto?
Para módulo, -1 sería una respuesta incorrecta.
Sin embargo, el operador % de C es un operador de resto, no un operador de módulo, y para el resto, se permite 10 o -1.
Respuesta corta:
El estándar garantiza que (a/b)*b + a%b es igual a a .
En C99, el resultado de la división / se truncará hacia cero. El resultado del operador % será seguro, en este caso, -1 .
En C89, el resultado de la división / se puede truncar de cualquier manera para los operandos negativos. Así que el resultado de % operator también depende de la máquina.
Respuesta larga:
Desde C99 6.5.5.
5 El resultado del operador / es el cociente de la división del primer operando por el segundo; El resultado del operador% es el resto. En ambas operaciones, si el valor del segundo operando es cero, el comportamiento no está definido.
6 Cuando los enteros se dividen, el resultado del operador / es el cociente algebraico con cualquier parte fraccionaria descartada. Si el cociente a / b es representable, la expresión (a / b) * b + a% b será igual a a; de lo contrario, el comportamiento de a / b y a% b no está definido.
Y la nota al pie en la misma página para explicar cómo / funciona, dice:
Esto a menudo se llama "truncamiento hacia cero".
De acuerdo con esta regla, -111 / 11 solo puede ser -10 , no 1. Como (a/b)*b + a%b debe ser igual a a , tenemos -111 % 11 es -1 .
Sin embargo, el Capítulo 2.5 de K&R da una respuesta diferente:
La dirección de truncamiento para / y el signo del resultado para% dependen de la máquina para operandos negativos, como lo es la acción realizada en caso de desbordamiento o subdesbordamiento.
De acuerdo con esto, ya sea -1 o 10 puede ser un resultado legal.
La razón está en C89 3.3.5:
Cuando los enteros se dividen y la división es inexacta, si ambos operandos son positivos, el resultado del operador / es el mayor entero menor que el cociente algebraico y el resultado del operador% es positivo. Si cualquiera de los operandos es negativo, si el resultado del operador / es el mayor entero menor que el cociente algebraico o el mayor entero mayor que el cociente algebraico está definido por la implementación, como es el signo del resultado del operador%. Si el cociente a / b es representable, la expresión (a / b) * b + a% b será igual a a.
Resulta ser un cambio de C89 a C99.
La justificación 6.5.5 de C99 proporciona algunas razones históricas:
En C89, la división de enteros con operandos negativos podría redondearse hacia arriba o hacia abajo de una manera definida por la implementación; la intención era evitar incurrir en gastos generales en el código de tiempo de ejecución para verificar casos especiales y hacer cumplir un comportamiento específico. Sin embargo, en Fortran, el resultado siempre se truncará hacia cero, y la sobrecarga parece ser aceptable para la comunidad de programación numérica. Por lo tanto, C99 ahora requiere un comportamiento similar, lo que debería facilitar la transferencia del código de Fortran a C. La tabla en la Sección 7.20.6.2 de este documento ilustra la semántica requerida.
Y aquí está la tabla en §7.20.6.2:
numer denom quot rem
7 3 2 1
–7 3 –2 –1
7 –3 –2 1
–7 –3 2 –1