1. Arredondamento de números reais

Como já discutimos, quando um número real é atribuído a uma intvariável, ele sempre é arredondado para o inteiro menor mais próximo — a parte fracionária é simplesmente descartada.

Mas é fácil imaginar uma situação em que um número fracionário precisa ser arredondado para o inteiro mais próximo em qualquer direção ou até mesmo arredondado para cima. O que você faz neste caso?

Para isso e para muitas situações semelhantes, Java possui a Mathclasse, que possui os métodos round(), ceil()e floor().


Math.round()método

O Math.round()método arredonda um número para o inteiro mais próximo:

long x = Math.round(real_number)

Mas há outra nuance aqui: esse método retorna um longinteiro (não um int). Como os números reais podem ser muito grandes, os criadores do Java decidiram usar o maior tipo inteiro disponível do Java: long.

Assim, se um programador deseja atribuir o resultado a uma intvariável, ele deve indicar explicitamente ao compilador que aceita a possível perda de dados (caso o número resultante não se encaixe em um inttipo).

int x = (int) Math.round(real_number)

Exemplos:

Declaração Resultado
int x = (int) Math.round(4.1);
4
int x = (int) Math.round(4.5);
5
int x = (int) Math.round(4.9);
5

Math.ceil()método

O Math.ceil()método arredonda um número para um inteiro. Aqui estão exemplos:

Declaração Resultado
int x = (int) Math.ceil(4.1);
5
int x = (int) Math.ceil(4.5);
5
int x = (int) Math.ceil(4.9);
5

Math.floor()método

O Math.floor()método arredonda um número para baixo para um inteiro. Aqui estão exemplos:

Declaração Resultado
int x = (int) Math.floor(4.1);
4
int x = (int) Math.floor(4.5);
4
int x = (int) Math.floor(4.9);
4

Obviamente, ao arredondar um número para baixo para um inteiro, é mais fácil simplesmente usar um operador de conversão de tipo:(int)

Declaração Resultado
int x = (int) 4.9
4

Se você achar difícil lembrar desses nomes, uma breve aula de inglês ajudará:

  • Mathsignifica matemática
  • Roundsignifica redondo
  • Ceilingsignifica teto
  • Floorsignifica chão

2. Como os números de ponto flutuante são estruturados

O doubletipo pode armazenar valores no intervalo de a . Essa enorme gama de valores (em comparação com o tipo) é explicada pelo fato de que o tipo (assim como ) tem uma estrutura interna completamente diferente dos tipos inteiros. Internamente, o tipo codifica seu valor como dois números: o primeiro é chamado de mantissa e o segundo é chamado de expoente .-1.7*10308+1.7*10308intdoublefloatdouble

Digamos que temos o número 123456789e o armazenamos em uma doublevariável. Quando o fazemos, o número é convertido em , e internamente o tipo armazena dois números — e . O significando ("parte significativa do número" ou mantissa) é destacado em vermelho, enquanto o expoente é destacado em azul.1.23456789*108double234567898

Essa abordagem permite armazenar números muito grandes e muito pequenos. Mas como a representação do número é limitada a 8 bytes (64 bits) e alguns dos bits são usados ​​para armazenar o expoente (assim como o sinal da mantissa e o sinal do expoente), os dígitos máximos disponíveis para representar a mantissa é 15 .

Esta é uma descrição muito simplificada de como os números reais são estruturados.


3. Perda de precisão ao trabalhar com números reais

Ao trabalhar com números reais, tenha sempre em mente que os números reais não são exatos . Sempre pode haver erros de arredondamento e erros de conversão ao converter de decimal para binário. Além disso, a fonte mais comum de erro é a perda de precisão ao adicionar/subtrair números em escalas radicalmente diferentes.

Este último fato é um pouco alucinante para programadores novatos.

Se subtrairmos de , obtemos .1/109109109

Subtraindo números em escalas radicalmente diferentes Explicação
 1000000000.000000000;
-         0.000000001;
 1000000000.000000000;
O segundo número é extremamente pequeno , o que fará com que seu significante (destacado em cinza) seja ignorado. Os 15 dígitos significativos são destacados em laranja.

O que podemos dizer, programação não é o mesmo que matemática.


4. Armadilha ao comparar números reais

Outro perigo está à espreita dos programadores quando eles comparam números reais. Surge ao trabalhar com números reais, porque os erros de arredondamento podem se acumular. O resultado é que há situações em que se espera que os números reais sejam iguais, mas não são. Ou vice-versa: espera-se que os números sejam diferentes, mas são iguais.

Exemplo:

Declaração Explicação
double a = 1000000000.0;
double b = 0.000000001;
double c = a - b;
O valor da variável a será 1000000000.0
O valor da variável c será 1000000000.0
(o número na b variável é excessivamente pequeno)

No exemplo acima, ae cnão deveriam ser iguais, mas são.

Ou vamos pegar outro exemplo:

Declaração Explicação
double a = 1.00000000000000001;
double b = 1.00000000000000002;
O valor da variável a será 1.0
O valor da variável b será1.0

5. Um fato interessante sobrestrictfp

Java tem uma strictfppalavra-chave especial ( ponto flutuante estrito ) , que não é encontrado em outras linguagens de programação . E sabe porque você precisa disso? Isso piora a precisão das operações com números de ponto flutuante. Aqui está a história de como surgiu:

Criadores do Java:
Nós realmente queremos que o Java seja super popular e execute programas Java no maior número possível de dispositivos. Portanto, garantimos que a especificação para a máquina Java diga que todos os programas devem ser executados da mesma maneira em todos os tipos de dispositivos!
Fabricantes de processadores Intel:
Ei, pessoal! Melhoramos nossos processadores e agora todos os números reais são representados usando 10 bytes em vez de 8 bytes dentro de nossos processadores. Mais bytes significa dígitos mais significativos. O que isso significa? Isso mesmo! Agora seus cálculos científicos serão ainda mais precisos!
Cientistas e todos os envolvidos em cálculos ultraprecisos:
Legal! Bom trabalho. Excelente notícia!
Criadores do Java:
Não-não-não, pessoal! Já dissemos que todos os programas Java devem ser executados da mesma forma em todos os dispositivos . Vamos desabilitar forçosamente a capacidade de usar números reais de 10 bytes dentro dos processadores Intel.
Agora está tudo bem de novo! Não nos agradeça.
Cientistas e todos os envolvidos em cálculos ultraprecisos:
Você ficou totalmente louco? Recupere rapidamente tudo como estava!
Criadores do Java:
Pessoal, isso é para o seu bem! Imagine só: todos os programas Java rodam da mesma forma em todos os dispositivos . Isto é tão legal!
Cientistas e todos os envolvidos em cálculos ultraprecisos:
Não. Não é nada legal. Rapidamente coloque tudo de volta como estava! Ou sabe onde colocaremos seu Java?
Criadores do Java:
Hum. Por que você não disse isso imediatamente? Claro, vamos colocá-lo de volta.
Restauramos sua capacidade de usar todos os recursos dos processadores mais recentes.
A propósito... Também adicionamos especialmente a strictfppalavra-chave ao idioma. Se você escrevê-lo antes do nome de uma função, todas as operações envolvendo números reais dentro dessa função serão igualmente ruins em todos os dispositivos !