Pergunta

Porque ocorre o arredondamento em algumas operações com números inteiros?

Resposta

O Java é uma linguagem com "tipagem" forte, isto é, o Java não converte valores de um tipo para outro a não ser que seja absolutamente necessário ou que seja indicado pelo programador. Vejamos o exemplo a seguir.

Imaginamos um variável, do tipo float, denominada m e outras duas variáveis s e q, do tipo inteiro. Se realizarmos a operação seguinte com tais variáveis:

m = s/q;

Espera-se que o resultado da operação de divisão seja do tipo float.

Errado! A operação s/q é tratada como uma divisão inteira, ou seja, sem casas decimais, assim 2/3 = 1, 45/10 = 4 e assim por diante. O Java (assim como C e outras linguagens) primeiro resolve a operação de divisão como uma divisão inteira e depois converte o número para o tipo float de forma que possa ser armazenado em m.

Para realizarmos tal operação como uma divisão normal devemos indicar, via uma operação de casting (conversão de tipos), que um dos operandos (variável s ou q) sejam tratados como números reais, assim:

m = s/(float)q; // casting para que q seja tratado como real ou
m = ((float)s)/q; // casting que s seja tratado como real

Sendo assim, quando realizamos operações algébricas (soma, subtração, multiplicação ou divisão) o compilador trata os operadores conforme sua precedência, isto é resolve os mais importantes e depois os demais. Além disso um inteiro é sempre tratado como tal exceto em certas situações quando é convertido para um tipo superior (mais complexo) tal como um número real.

Mas a conversão de um inteiro para um real só é realizada quando o compilador detecta que tipos diferentes estão envolvidos na operação. A divisão de um inteiro por outro inteiro é sempre tratada como uma divisão inteira, ou seja, desprezando qualquer resultado após a vírgula, exigindo nestas situações que se realize uma operação de casting com um dos operandos, ou seja, antes da operação de divisão. Se fizermos como abaixo:

m=(float) s/q; // não funciona

O resultado é o mesmo pois a divisão inteira s/q é realizada antes da operação de casting devido a precedência das operações.

Embora possa parecer ruim, este comportamento permite operar valores inteiros com maior facilidade, evitando o uso de métodos especias para realizar a truncagem ou o arredondamento forçado de resultados de operações.