paulo1205
(usa Ubuntu)
Enviado em 25/01/2017 - 03:51h
O operador
% do C e do C++ é um operador de cálculo de resto de divisão inteira, não de aritmética modular.
Ele é definido da seguinte forma:
x%d, sendo
x e
d inteiros, tem de dar como resultado um valor
r tal que
x==(x/d)*d+r para quaisquer valores válidos de
x e
d.
Como se pode ver, a definição acima usa o resultado da divisão inteira. E qual é a definição da divisão inteira, especialmente quando há operandos negativos?
Aí é que mora o perigo. Nas primeiras versões do C (antes do padrão de 1999), cada implementação escolhia o que fazer. Algumas implementações arredondavam sempre no sentido do valor mais próximo de zero (por exemplo:
7/5==1 e
(-7)/5==-1), mas outras poderiam arredondar sempre para baixo (por exemplo:
7/5==1 e
(-7)/5==-2, já que -2 é o maior valor inteiro menor que o resultado aritmético -1.4). Se a implementação escolhesse arredondar sempre para baixo, então o comportamento do operador
% se parecia mais com o que se tem em aritmética modular (e.g.
(-7)%5==3, pois
(-7)/5==-2, e
-7==(-2)*5+3).
No entanto, a partir do padrão do C de 1999, formalizou-se que a divisão inteira deveria produzir resultados estáveis em qualquer implementação, passando a se requerer sempre o arredondamento para zero. Com a estabilização do comportamento da divisão, também o resultado da aplicação do operador
% passou a ser estável.
No caso do C++, os padrões têm seguido as convenções dos padrões do C que vigoravam na data de homologação dos padrões do C++. Na época do primeiro padrão do C++, de 1998, o padrão em vigor do C ainda era o de 1989/1990, logo cada implementação escolhia suas próprias regras de arredondamento. No padrão de 2011, seguiu-se a convenção do C aplicada a partir de 1999, de arredondar sempre no sentido do zero.
Se você quiser uma função módulo mesmo, e que funcione de modo estável com qualquer versão do C ou do C++, terá de escrever uma, semelhante à que vai abaixo.
int mod(int x, int d){
int abs_r=abs(x)%abs(d);
bool x_neg=x<0, d_neg=d<0;
return
x_neg?
d_neg? -abs_r: d-abs_r
:
d_neg? abs_r+d: abs_r
;
}
Note, porém, que essa função não necessariamente vai satisfazer o resultado
x==(x/d)*d+mod(x, d).