CodeGym /Cursos /JAVA 25 SELF /Introdução aos números de ponto flutuante e ao tipo doubl...

Introdução aos números de ponto flutuante e ao tipo double

JAVA 25 SELF
Nível 6 , Lição 2
Disponível

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
float
Números ±1.5 × 10-45 ... ±3.4 × 1038 ~7 casas decimais 4 bytes
double
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
"%.2f"
23.57 número com 2 casas decimais
"%.1f"
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.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION