Alba
En un programa C, 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 cada vez. ¿Puede un módulo ser negativo? ¿Alguien puede explicar este comportamiento?
ouah
Él %
El operador en C no es el módulo operador pero el recordatorio operador.
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 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 el %
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 hace hacia 0
(y no hacia el infinito negativo) que define el %
como un operador de resto en lugar de un operador de módulo.
-
El resto es el resultado de la operación de módulo por definición. No debería existir el operador de resto porque no existe la operación de resto, se llama módulo.
– gronostaj
27/06/2015 a las 20:49
-
@gronostaj no en CS. Mire lenguajes de nivel superior como Haskell o Scheme que definen dos operadores diferentes (
remainder
ymodulo
en esquema,rem
ymod
en Haskell). Las especificaciones de estos operadores difieren en estos lenguajes sobre cómo se realiza la división: truncamiento hacia 0 o hacia infinito negativo. Por cierto, el estándar C nunca llama al%
la operador de módulosimplemente lo nombran % operador.– ouah
21 de diciembre de 2015 a las 16:55
-
No debe confundirse con el
remainder
función en C, que implementa el resto IEEE con semántica de redondeo hacia el más cercano en la división–Eric
18 de septiembre de 2017 a las 2:11
-
@gronostaj El enlace que proporcionó hace específicamente la distinción entre resto mínimo positivoy mínimo resto absoluto lo que obviamente no siempre es positivo. Da
-2
como el menor resto absoluto de43 / 5
(ya que43 = 9 * 5 - 2
). La definición de CS es una vez más diferente. Pero vale la pena señalar que solo porque aprendimos algo cuando teníamos 10 años, todavía puede haber algunas sutilezas. Tratarround(2.5)
en Python, por ejemplo. Es 2, no 3. Y eso es matemáticamente correcto, para evitar sesgos en momentos estadísticos.–Mike Williamson
18 de febrero de 2021 a las 17:25
ArjunShankar
C99 requiere que cuando a/b
es 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 5%(-3)
es 2
Ejemplo B. (-5)/3
es -1
=> (-1) * 3
+ (-5)%3
= -5
Esto solo puede suceder si (-5)%3
es -2
-
¿Debería el compilador ser lo suficientemente inteligente y detectar que un módulo sin firmar otro sin firmar siempre es positivo? Actualmente (bueno, GCC 5.2) el compilador parece pensar que “%” devuelve un “int” en este caso, en lugar de “sin firmar”, incluso cuando ambos operandos son uint32_t o más grandes.
– Federico Norte
24/09/2016 a las 14:56
-
@FrederickNord ¿Tiene un ejemplo para mostrar ese comportamiento?
– chux – Reincorporar a Monica
24 de febrero de 2017 a las 16:16
-
Comprenda que lo que describe es la descripción habitual int (a / b) (truncada) de mod. Pero también es posible que la regla sea piso(a/b) (Knuth). En el caso Knuth
-5/3
es-2
y el mod se convierte en 1. En resumen: un módulo tiene un signo que sigue al signo del dividendo (truncado), el otro módulo tiene un signo que sigue al signo del divisor (Knuth).– Isaac
27 de mayo de 2018 a las 9:36
-
Este es un caso en el que el estándar C no es exactamente lo que quiero. Nunca he querido truncar a cero o números de módulo negativos, pero a menudo quiero lo contrario y necesito solucionar C.
– José
6 de agosto de 2018 a las 22:27
-
@Nick el
a/b
en la expresión(a/b) * b + a%b
arriba es la división de enteros, por lo que(a/b) * b
no es igual aa
a no ser quea
es divisible porb
.– Laurence Gonsalves
17 dic 2021 a las 17:51
dewang
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.
-
Esto no da resultados positivos cuando
b
es negativo (y de hecho parar
yb
ambos negativos da resultados menos que-b
). Para garantizar resultados positivos para todas las entradas que podría utilizarr + abs(b)
o para hacer coincidirb
s signo que podría cambiar la condición ar*b < 0
en cambio.– Martín Ender
20 de septiembre de 2016 a las 11:42
-
@MartinEnder
r + abs(b)
es UB cuandob == INT_MIN
.– chux – Reincorporar a Monica
27 de septiembre de 2018 a las 4:20
Udayraj Deshmukh
No creo que haya necesidad de verificar si el número es negativo.
Una función simple para encontrar el módulo positivo sería esta:
Editar: Asumiendo N > 0
y N + N - 1 <= INT_MAX
int modulo(int x,int N){
return (x % N + N) %N;
}
Esto funcionará para tanto positivo como negativo valores 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 reemplace int
con long long int
.
Y si también cruzan los límites de long long (es decir, cerca de LLONG_MAX), entonces deberá manejar los casos positivos y negativos por separado como se describe en otras respuestas aquí.
De acuerdo a estándar C99sección 6.5.5 Operadores multiplicativosse requiere lo siguiente:
(a / b) * b + a % b = a
Conclusión
El signo del resultado de una operación de resto, según C99, es el mismo que el del 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
- expresión-multiplicativa:
cast-expression
multiplicative-expression * cast-expression
multiplicative-expression / cast-expression
multiplicative-expression % cast-expression
Restricciones
- Cada uno de los operandos tendrá tipo aritmético. Los operandos de la % El operador debe tener un tipo entero.
Semántica
Las conversiones aritméticas habituales se realizan en los operandos.
El resultado del binario. * El operador es el producto de los operandos.
el resultado de la / operador es el cociente de la división del primer operando por el segundo; el resultado de la % el operador es el resto. En ambas operaciones, si el valor del segundo operando es cero, el comportamiento es indefinido.
Cuando se dividen números enteros, el resultado de la / operador es el cociente algebraico con cualquier parte fraccionaria descartada [1]. Si el cociente
a/b
es representable, la expresión(a/b)*b + a%b
será iguala
.[1]: Esto a menudo se denomina “truncamiento hacia cero”.
¿Puede un módulo ser negativo?
%
puede ser negativo ya que es el operador resto, el resto después de la división, no después División_euclidiana. Desde C99 el resultado puede ser 0, negativo o positivo.
// a % b
7 % 3 --> 1
7 % -3 --> 1
-7 % 3 --> -1
-7 % -3 --> -1
Él módulo OP buscado es un clasico módulo euclidianono %
.
Esperaba un resultado positivo cada vez.
Para realizar un módulo euclidiano que esté bien definido siempre que a/b
se define, a,b
son de cualquier signo y el resultado nunca es negativo:
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;
}
modulo_Euclidean( 7, 3) --> 1
modulo_Euclidean( 7, -3) --> 1
modulo_Euclidean(-7, 3) --> 2
modulo_Euclidean(-7, -3) --> 2
yuhao
Las otras respuestas han explicado en C99 o posterior, la división de números enteros que involucran operandos negativos siempre truncar hacia cero.
Tenga en cuenta que, en C89, si el redondeo del resultado hacia arriba o hacia abajo está definido por la implementación. Porque (a/b) * b + a%b
es igual a
en todos los estándares, el resultado de %
la participación de operandos negativos también está definida por la implementación en C89.
Posible duplicado de stackoverflow.com/questions/4003232/…
– James
30 de julio de 2012 a las 11:41
posible duplicado del operador Modulo con valores negativos
– sugavaneshb
8 de febrero de 2015 a las 8:46
Hay dos interpretaciones diferentes del módulo. torstencurdt.com/tech/posts/modulo-of-negative-numbers
– tcurdt
1 de febrero a las 12:26