Em um programa C, eu estava tentando as operações abaixo (Apenas para verificar o comportamento)
x = 5 % (-3);
y = (-5) % (3);
z = (-5) % (-3);
printf("%d ,%d ,%d", x, y, z);
me deu saída como (2, -2 , -2)
no gcc. Eu estava sempre esperando um resultado positivo. Um módulo pode ser negativo? Alguém pode explicar esse comportamento?
Respostas:
C99 exige que quando
a/b
é representável:(a/b) * b
+a%b
será iguala
Isso faz sentido, logicamente. Certo?
Vamos ver o que isso leva a:
O exemplo A.
5/(-3)
é-1
=>
(-1) * (-3)
+5%(-3)
=5
Isso só pode acontecer se
5%(-3)
for 2.O exemplo B.
(-5)/3
é-1
=>
(-1) * 3
+(-5)%3
=-5
Isso só pode acontecer se
(-5)%3
for-2
fonte
-5/3
é-2
eo mod se torna 1. Em suma: um módulo tem uma placa que segue o sinal de dividendos (truncar), o outro módulo tem uma placa que segue o sinal divisor (Knuth).O
%
operador em C não é o operador de módulo , mas o operador restante .Os operadores de módulo e restante diferem em relação aos valores negativos.
Com um operador restante, o sinal do resultado é o mesmo que o sinal do dividendo, enquanto que com um operador de módulo, o sinal do resultado é o mesmo que o divisor.
C define a
%
operação paraa % b
:com
/
a divisão inteira com truncamento para0
. Esse é o truncamento que é feito para0
(e não para a inifinidade negativa) que define o%
operador como restante em vez de operador de módulo.fonte
remainder
emodulo
no Schemerem
emod
no Haskell). Essas especificações dos operadores diferem nesses idiomas em como a divisão é feita: truncamento para 0 ou para infinito negativo. Pela forma como o C padrão nunca chama o%
o operador módulo , eles apenas nome do operador% .remainder
função em C, que implementa IEEE restante com a semântica mais próximas redondas-para-a-na divisãoCom base na especificação C99:
a == (a / b) * b + a % b
Podemos escrever uma função para calcular
(a % b) == a - (a / b) * b
!Para operação do módulo, podemos ter a seguinte função (assumindo
b > 0
)Minha conclusão é que
a % b
em C é uma operação restante e NÃO uma operação de módulo.fonte
b
é negativo (e, de fato, parar
eb
ambos negativos, resultados menores que-b
). Para garantir resultados positivos para todas as entradas que você poderia usarr + abs(b)
ou para corresponder aob
sinal de s, você poderia alterar a condição parar*b < 0
.r + abs(b)
é UB quandob == INT_MIN
.Acho que não há necessidade de verificar se o número é negativo.
Uma função simples para encontrar o módulo positivo seria esta -
Edit: Assumindo
N > 0
eN + N - 1 <= INT_MAX
Isso funcionará para valores positivos e negativos de x.
PS original: também como indicado pelo @chux, se o seu x e N podem alcançar algo como INT_MAX-1 e INT_MAX, respectivamente, substitua
int
porlong long int
.E se eles também estão ultrapassando limites de muito tempo (ou seja, perto de LLONG_MAX), você deve lidar com casos positivos e negativos separadamente, conforme descrito em outras respostas aqui.
fonte
N < 0
o resultado pode ser negativo como emmodulo(7, -3) --> -2
. Tambémx % N + N
pode estourarint
matemática, que é um comportamento indefinido. por exemplo,modulo(INT_MAX - 1,INT_MAX)
pode resultar em -3.long long int
ou lidar com o caso negativo separadamente (ao custo de perder a simplicidade).As outras respostas explicaram em C99 ou posterior, a divisão de números inteiros envolvendo operandos negativos sempre trunca em direção a zero .
Observe que, em C89 , se o resultado arredondado para cima ou para baixo é definido pela implementação. Como
(a/b) * b + a%b
é iguala
em todos os padrões, o resultado do%
envolvimento de operandos negativos também é definido na implementação em C89.fonte
%
pode ser negativo, pois é o operador restante , o restante após a divisão, não após a divisão Euclidean . Desde C99, o resultado pode ser 0, negativo ou positivo.O módulo OP desejado é um módulo euclidiano clássico , não
%
.Executar um módulo euclidiano que seja bem definido sempre que
a/b
for definidoa,b
é de qualquer sinal e o resultado nunca é negativo:fonte
O resultado da operação do módulo depende do sinal do numerador e, portanto, você obtém -2 para y e z
Aqui está a referência
http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_14.html
fonte
Em Matemática, de onde essas convenções se originam, não há afirmação de que o módulo aritmético deva produzir um resultado positivo.
Por exemplo.
1 mod 5 = 1, mas também pode ser igual a -4. Ou seja, 1/5 produz um restante 1 de 0 ou -4 de 5. (Ambos os fatores de 5)
Da mesma forma, -1 mod 5 = -1, mas também pode ser igual a 4. Ou seja, -1/5 produz um restante -1 de 0 ou 4 de -5. (Ambos os fatores de 5)
Para uma leitura mais aprofundada, procure classes de equivalência em Matemática.
fonte
a
eb
,b <> 0
. De acordo com o teorema da divisão euclidiana, existe exatamente um par de números inteirosm
,r
ondea = m * b + r
e0 <= r < abs( b )
. O ditor
é o resultado da operação do módulo (matemático) e, por definição, não é negativo. Mais leitura e mais links na Wikipedia: en.wikipedia.org/wiki/Euclidean_division1 mod 5
é sempre 1. também-4 mod 5
pode ser 1, mas são coisas diferentes.De acordo com o padrão C99 , seção 6.5.5 Operadores multiplicativos , é necessário o seguinte:
Conclusão
O sinal do resultado de uma operação remanescente, de acordo com C99, é o mesmo que o do dividendo.
Vamos ver alguns exemplos (
dividend / divisor
):Quando apenas o dividendo é negativo
Quando apenas o divisor é negativo
Quando o divisor e o dividendo são negativos
fonte
O operador de módulo fornece o restante. O operador de módulo em c geralmente leva o sinal do numerador
O operador módulo (restante) também pode ser usado apenas com o tipo inteiro e não pode ser usado com ponto flutuante.
fonte
Eu acredito que é mais útil pensar
mod
como definido na aritmética abstrata; não como uma operação, mas como uma classe aritmética totalmente diferente, com diferentes elementos e diferentes operadores. Isso significa que a adiçãomod 3
não é igual à adição "normal"; isso é; adição de número inteiro.Então, quando você faz:
Você está tentando mapear o número inteiro 5 para um elemento no conjunto de
mod -3
. Estes são os elementos demod -3
:Assim:
Digamos que você tenha que ficar acordado por algum motivo 30 horas, quantas horas você terá nesse dia?
30 mod -24
.Mas o que C implementa não é
mod
, é um restante. De qualquer forma, a questão é que faz sentido retornar negativos.fonte