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