¿Cuál es la diferencia entre "mod" y "resto"?
Mi amigo dijo que existen diferencias entre "mod" y "resto".
Si es así, ¿cuáles son esas diferencias en C y C++? ¿'%' significa "mod" o "rem" en C?
Existe una diferencia entre módulo (división euclidiana) y resto ( %
operador de C). Por ejemplo:
-21
mod 4
es 3
porque -21 + 4 x 6
es 3
.
Pero -21
dividido por 4
con truncamiento hacia 0
(como /
operador de C)
da -5
un resto (C -21 % 4
) de -1
.
Para valores positivos, no hay diferencia entre división euclidiana y truncada.
Consulte https://en.wikipedia.org/wiki/Euclidean_division#Other_intervals_for_the_remainder : la elección de C de truncar el resto hacia 0
( requerido desde C99 ) fuerza un rango de resto negativo para cocientes negativos. Incluso en C89, cuando el estándar permitía la división euclidiana para/
Si el cociente
a/b
es representable, la expresión(a/b)*b + a%b
será igual aa
.
(-21/4) * 4 + (-21%4) == -21
; C99 y posteriores requieren (-5) * 4 + (-1)
, no euclidianos -6
y 3
.
¿'%' significa "mod" o "rem" en C?
En C, %
es el resto 1 .
..., el resultado del
/
operador es el cociente algebraico con cualquier parte fraccionaria descartada... (Esto suele denominarse "truncamiento hacia cero"). C11dr §6.5.5 6Los operandos del
%
operador serán de tipo entero. C11dr §6.5.5 2El resultado del
/
operador es el cociente de la división del primer operando por el segundo; el resultado del%
operador es el resto ... C11dr §6.5.5 5
¿Cuál es la diferencia entre "mod" y "resto"?
C no define un operador/función "mod" ni "módulo", como la función de módulo entero utilizada en la división euclidiana u otro módulo .
C define el resto .
Comparemos el "resto" según el %
operador con el "mod" euclidiano.
El "mod euclidiano" difiere de la operación de C a%b
cuando a
es negativo.
// a % b, the remainder after an integer division that truncates toward 0.
7 % 3 --> 1
7 % -3 --> 1
-7 % 3 --> -1
-7 % -3 --> -1
"Mod" o módulo como en la división euclidiana. El resultado siempre es 0 o positivo.
7 modulo 3 --> 1
7 modulo -3 --> 1
-7 modulo 3 --> 2
-7 modulo -3 --> 2
Código de módulo candidato:
int modulo_Euclidean(int a, int b) {
int m = a % b;
if (m < 0) {
// m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
m = (b < 0) ? m - b : m + b;
}
return m;
}
Nota sobre el punto flotante: double fmod(double x, double y)
aunque se llama "fmod", no es lo mismo que la división euclidiana "mod", pero es similar al resto del entero C:
Las
fmod
funciones calculan el resto de punto flotante dex/y
. C11dr §7.12.10.1 2
fmod( 7, 3) --> 1.0
fmod( 7, -3) --> 1.0
fmod(-7, 3) --> -1.0
fmod(-7, -3) --> -1.0
Desambiguación : C también tiene una función con nombre similar double modf(double value, double *iptr)
que divide el valor del argumento en partes integrales y fraccionarias, cada una de las cuales tiene el mismo tipo y signo que el argumento. Esto tiene poco que ver con la discusión sobre "mod" aquí, excepto la similitud de nombres.
[Editar diciembre de 2020]
Para aquellos que desean una funcionalidad adecuada en todos los casos, una mejora modulo_Euclidean()
que 1) detecta mod(x,0)
y 2) un resultado bueno y sin UB con modulo_Euclidean2(INT_MIN, -1)
. Inspirado en 4 implementaciones diferentes de módulo con comportamiento completamente definido .
int modulo_Euclidean2(int a, int b) {
if (b == 0) TBD_Code(); // perhaps return -1 to indicate failure?
if (b == -1) return 0; // This test needed to prevent UB of `INT_MIN % -1`.
int m = a % b;
if (m < 0) {
// m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
m = (b < 0) ? m - b : m + b;
}
return m;
}
1 Antes de C99, la definición de C de %
todavía era el resto de la división, pero luego /
permitía que los cocientes negativos se redondearan hacia abajo en lugar de "truncarlos hacia cero". Consulte ¿Por qué se obtienen valores diferentes para la división de enteros en C89? . Por lo tanto, con alguna compilación anterior a C99, %
el código puede actuar como la división euclidiana "mod". Lo anterior modulo_Euclidean()
también funcionará con este resto alternativo de la vieja escuela.
En C y C++ y en muchos lenguajes, %
el resto NO es el operador de módulo.
Por ejemplo en la operación -21 / 4
la parte entera es -5
y la parte decimal es -.25
. El resto es la parte fraccionaria multiplicada por el divisor, por lo que nuestro resto es -1
. JavaScript utiliza el operador restante y confirma esto
console.log(-21 % 4 == -1);
El operador de módulo es como si tuvieras un "reloj". Imagine un círculo con los valores 0, 1, 2 y 3 en las posiciones de las 12 en punto, 3 en punto, 6 en punto y 9 en punto respectivamente. Al avanzar el cociente en el sentido de las agujas del reloj, obtenemos el resultado de nuestra operación de módulo o, en nuestro ejemplo, con un cociente negativo, en el sentido contrario a las agujas del reloj, lo que da 3.
Nota: El módulo siempre tiene el mismo signo que el divisor y el resto tiene el mismo signo que el cociente. Sumar el divisor y el resto cuando al menos uno es negativo produce el módulo.