1. Números fracionários
Suponha que você decidiu escrever uma calculadora simples. Ou qualquer outro programa em que sejam necessários cálculos (desde a contagem básica de dinheiro até física complexa). Nem tudo na vida real é um número inteiro — e não há o que fazer quanto a isso!
Então vamos nos munir de um novo tipo de dados!
Na programação, os números fracionários também são chamados de reais, ou números de ponto flutuante (floating-point). Em Java, como na maioria das linguagens, eles servem para armazenar não apenas inteiros, mas também valores “fracionários”: como 3.14, -28.57, 2.718281828...
Os números de ponto flutuante existem em dois tipos principais:
| Tipo | Armazena | Intervalo de valores (aprox.) | Precisão | Tamanho típico |
|---|---|---|---|---|
|
Números | ±1.5 × 10-45 ... ±3.4 × 1038 | ~7 casas decimais | 4 bytes |
|
Números | ±5.0 × 10-324 ... ±1.7 × 10308 | ~15–16 casas decimais | 8 bytes |
Tipo float
O tipo float recebeu seu nome de floating-point number — número de ponto flutuante. Números reais são objetos da matemática e possuem certas propriedades. Já o computador tem muitas limitações. Por isso, não é totalmente correto chamar números fracionários em Java de “reais”. Para eles, usa-se o nome “números de ponto flutuante”.
O tipo float normalmente armazena 7 dígitos significativos (por exemplo, 0.1234567), a potência de dez e ocupa 4 bytes na memória. Isso é muito pouco para cálculos precisos, por isso todos migraram rapidamente para números de precisão dupla.
Tipo double
O tipo double recebeu seu nome de precisão dupla (double). Ele ocupa 8 bytes na memória (2 vezes mais do que float) e pode armazenar até 15 dígitos significativos: 0.123456789012345. Isso é suficiente para a maioria dos cálculos com números fracionários, portanto double é o tipo principal para armazenar números fracionários em Java.
Nesta aula, o foco principal será no tipo double: ele é recomendado por padrão para todos os números fracionários “comuns”. Mas adiante também veremos o tipo float.
2. Declaração e inicialização de variáveis do tipo double
Tudo como com int — só que agora usamos double.
// Declaramos uma variável e atribuímos a ela o valor de Pi
double pi = 3.1415926;
// Também é possível declarar sem inicializar
double averageSalary;
averageSalary = 91234.56;
// Podemos fazer contas!
double pizzaPieces = 8;
double friends = 3;
double piecesPerFriend = pizzaPieces / friends; // 2.666... (e não 2)
Particularidades de sintaxe:
- Como separador decimal usa-se o ponto (3.14). Se você usar vírgula — terá erro de compilação!
- Rigorosamente falando, ao escrever double d = 3;, você não terá erro — os tipos serão convertidos automaticamente (o número inteiro vira “de ponto flutuante” sem perdas).
3. Entrada e saída de números fracionários com Scanner
Primeiro, vamos tentar imprimir um número fracionário:
double amount = 42.75;
System.out.println(amount); // Vai imprimir: 42.75
Tudo certo! E se adicionarmos texto:
System.out.println("No seu saldo: " + amount + " euros."); // No seu saldo: 42.75 euros.
Entrada pelo teclado
Para ler um double, é preciso usar um método especial da classe Scanner: console.nextDouble().
Scanner console = new Scanner(System.in);
System.out.println("Digite a temperatura lá fora:");
double temperature = console.nextDouble(); // Lemos um double diretamente
System.out.println("Lá fora agora: " + temperature + " graus.");
4. Tipo double em ação: aritmética
Todas as operações conhecidas (+, -, *, /) funcionam como para int:
double distance = 100.5;
double time = 2.0;
double speed = distance / time; // 50.25
System.out.println("Velocidade média: " + speed); // Velocidade média: 50.25
Essa é toda a aritmética. A única diferença: o resultado da divisão é sempre fracionário se pelo menos um dos operandos for double.
Comparando com int
int a = 5, b = 2;
System.out.println(a / b); // 2 (o resto é descartado)
double aa = 5, bb = 2;
System.out.println(aa / bb); // 2.5
5. Erros e peculiaridades típicos ao trabalhar com double
Erro de conversão da entrada
Situação clássica: o usuário digita 3,14 — mas o programa espera 3.14. Em Java, o método Scanner.nextDouble() se orienta pela localidade atual: em locais russo/alemão a vírgula é aceitável; em inglês — é necessário ponto. Se preciso, configure a localidade do Scanner ou leia a string e faça o parse manualmente.
// Isso causará problema em Locale.US se for digitado "3,14"
double value = console.nextDouble();
Erro de “imprecisão” dos números no computador
É aqui que normalmente começa um leve estranhamento para iniciantes:
double x = 0.1 + 0.2;
System.out.println(x); // Hmm... 0.30000000000000004
Parabéns, você esbarrou na “magia” da representação de números fracionários dentro do computador. O fato é que muitos números não podem ser representados exatamente no sistema binário. Isso costuma não ser crítico para a maioria dos aplicativos, mas há nuances em finanças e ciências exatas.
6. Importante: double e int — conversão automática e explícita
Às vezes você soma um inteiro e um fracionário, ou atribui um int a uma variável double — e não haverá erros:
int i = 2;
double d = i; // Tudo ok!
System.out.println(d); // 2
double dd = 3.7;
int ii = (int) dd; // É necessário converter explicitamente de double para int!
System.out.println(ii); // 3, a parte fracionária foi descartada
Muitas vezes isso causa surpresa — por que a parte fracionária desapareceu após a conversão? Simplesmente porque o tipo int não consegue armazenar frações (tudo o que vem após o ponto desaparece para sempre).
Mais detalhes sobre a conversão de double para int e o operador (int) na próxima aula.
7. Saída formatada: exibindo double com elegância
Muitas vezes, por padrão, double é impresso com um monte de zeros desnecessários. É possível formatar a saída:
double temp = 23.56789;
System.out.println(temp); // 23.56789
// 2 casas decimais
System.out.println(String.format("%.2f", temp)); // 23.57
// 1 casa decimal
System.out.println(String.format("%.1f%n", temp)); // 23.6
| Formato | Resultado | Descrição |
|---|---|---|
|
23.57 | número com 2 casas decimais |
|
23.6 | número com 1 casa decimal |
8. Erros típicos ao trabalhar com float e double
Erro nº 1: conversão implícita de double para float
float f = 1.23; // Erro!
O compilador vai reclamar: “Você está tentando colocar um double em um float — isso pode levar à perda de precisão!” Sempre adicione o sufixo f.
Erro nº 2: esquecer que a divisão de dois int resulta em int
int a = 7, b = 2;
double result = a / b; // 3.0, e não 3.5
Para obter a parte fracionária, converta explicitamente pelo menos um dos operandos:
double result = (double) a / b; // 3.5
Erro nº 3: comparação de números de ponto flutuante
Não compare números de ponto flutuante por igualdade usando ==. Use comparação com uma pequena tolerância (epsilon).
Erro nº 4: perda de precisão com float
Não armazene números grandes ou valores muito precisos em float — eles podem “quebrar” ou perder dígitos importantes.
GO TO FULL VERSION