Operación de módulo con números negativos
En un programa en C estaba probando las siguientes operaciones (solo para comprobar el comportamiento)
x = 5 % (-3);
y = (-5) % (3);
z = (-5) % (-3);
printf("%d ,%d ,%d", x, y, z);
Me dio resultados como (2, -2 , -2)
en gcc. Esperaba siempre un resultado positivo. ¿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á iguala
Esto tiene sentido, lógicamente. ¿Bien?
Veamos a qué conduce esto:
El ejemplo A. 5/(-3)
es-1
=> (-1) * (-3)
+ 5%(-3)
=5
Esto sólo puede suceder si 5%(-3)
es 2.
El ejemplo B. (-5)/3
es-1
=> (-1) * 3
+ (-5)%3
=-5
Esto sólo 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 resto difieren con respecto a los valores negativos.
Con un operador de resto, el signo del resultado es el mismo que el signo del dividendo (numerador) mientras que con un operador de módulo el signo del resultado es el mismo que el del divisor (denominador).
C define la %
operación para a % b
como:
a == (a / b * b) + a % b
con /
la división de enteros con truncamiento hacia 0
. Ese es el truncamiento que se realiza hacia 0
(y no hacia el infinito negativo) que define a %
como un operador de resto 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 de módulo, podemos tener la siguiente función (asumiendo b > 0
)
int mod(int a, int b)
{
int r = a % b;
return r < 0 ? r + b : r;
}
Mi conclusión es que a % b
en C es una operación de resto y NO una operación de módulo.
No creo que no sea necesario comprobar si el número es negativo.
Una función simple para encontrar el módulo positivo sería esta:
Editar: asumiendo N > 0
yN + N - 1 <= INT_MAX
int modulo(int x,int N){
return (x % N + N) %N;
}
Esto funcionará tanto para valores positivos como negativos de x.
PD original: también como lo señaló @chux, si su x y N pueden alcanzar algo como INT_MAX-1 e INT_MAX respectivamente, simplemente reemplácelo int
con long long int
.
Y si también cruzan límites largos (es decir, cerca de LLONG_MAX), deberá manejar los casos positivos y negativos por separado como se describe en otras respuestas aquí.