1. Números fraccionarios
Supongamos que decidiste escribir una calculadora sencilla. O cualquier otro programa donde se necesiten cálculos (desde el conteo de dinero hasta física compleja). En la vida real no todo es un número entero, ¡y no hay nada que hacer al respecto!
¡Así que armémonos con un nuevo tipo de datos!
En programación, los números fraccionarios también se llaman reales, o números de coma flotante (floating-point). En Java, como en la mayoría de lenguajes, sirven para almacenar no solo enteros, sino también valores «fraccionarios»: cosas como 3.14, -28.57, 2.718281828...
Los números reales vienen en dos tipos principales:
| Tipo | Almacena | Rango de valores (aprox.) | Precisión | Tamaño típico |
|---|---|---|---|---|
|
Números | ±1.5 × 10-45 ... ±3.4 × 1038 | ~7 decimales | 4 bytes |
|
Números | ±5.0 × 10-324 ... ±1.7 × 10308 | ~15–16 decimales | 8 bytes |
Tipo float
El tipo float recibe su nombre de floating-point number — número de coma flotante. Los números reales son números de las matemáticas con ciertas propiedades. Y el ordenador tiene muchas limitaciones. Por eso no es del todo correcto llamar «reales» a los números fraccionarios en Java. Para ellos se usa el nombre «números de coma flotante».
El tipo float suele almacenar 7 cifras significativas (por ejemplo, 0.1234567), el exponente de la potencia de diez y ocupa 4 bytes en memoria. Esto es muy poco para cálculos precisos, por lo que se pasó rápidamente a los números de doble precisión.
Tipo double
El tipo double recibe su nombre de doble (double) precisión. Ocupa 8 bytes en memoria (el doble que float) y puede almacenar hasta 15 cifras significativas: 0.123456789012345. Esto es suficiente para la mayoría de los cálculos con números fraccionarios, por lo que double es el tipo principal para almacenarlos en Java.
En esta lección, el foco principal estará en el tipo double: se recomienda por defecto para todos los números fraccionarios «habituales». Pero más adelante veremos también el tipo float.
2. Declaración e inicialización de variables de tipo double
Todo como con int, solo que ahora usamos double.
// Declaramos una variable y le asignamos el valor de pi
double pi = 3.1415926;
// También se puede declarar sin inicializar
double averageSalary;
averageSalary = 91234.56;
// ¡Se puede calcular!
double pizzaPieces = 8;
double friends = 3;
double piecesPerFriend = pizzaPieces / friends; // 2.666... (y no 2)
Particularidades de la sintaxis:
- Como separador decimal se usa el punto (3.14). Si usas coma, ¡obtendrás un error de compilación!
- En rigor, al escribir double d = 3; no obtendrás error — los tipos se convertirán automáticamente (el número entero se transforma en «de coma flotante» sin pérdidas).
3. Entrada y salida de números fraccionarios con Scanner
Primero intentemos imprimir un número fraccionario:
double amount = 42.75;
System.out.println(amount); // Imprimirá: 42.75
¡Todo bien! Y si añadimos texto:
System.out.println("En tu cuenta: " + amount + " euros."); // En tu cuenta: 42.75 euros.
Entrada por teclado
Para leer un double debes usar un método específico de la clase Scanner: console.nextDouble().
Scanner console = new Scanner(System.in);
System.out.println("Introduce la temperatura exterior:");
double temperature = console.nextDouble(); // Leemos double directamente
System.out.println("Ahora en la calle hay: " + temperature + " grados.");
4. El tipo double en acción: aritmética
Todas las operaciones habituales (+, -, *, /) funcionan igual que para int:
double distance = 100.5;
double time = 2.0;
double speed = distance / time; // 50.25
System.out.println("Velocidad media: " + speed); // Velocidad media: 50.25
Eso es toda la aritmética. La única diferencia: el resultado de una división siempre es fraccionario si al menos uno de los operandos es double.
Comparemos con int
int a = 5, b = 2;
System.out.println(a / b); // 2 (se descarta el resto)
double aa = 5, bb = 2;
System.out.println(aa / bb); // 2.5
5. Errores y rarezas típicos al trabajar con double
Error de conversión de entrada
Caso típico: el usuario introduce 3,14, pero el programa espera 3.14. En Java, el método Scanner.nextDouble() se guía por la configuración regional actual: en la configuración regional rusa/alemana la coma es válida; en la inglesa se requiere el punto. Si es necesario, configura la configuración regional para Scanner o lee la cadena y analízala manualmente.
// Esto causará un problema en Locale.US si se introduce "3,14"
double value = console.nextDouble();
Error de «imprecisión» de los números en el ordenador
Aquí es donde los principiantes suelen sentir cierta perplejidad:
double x = 0.1 + 0.2;
System.out.println(x); // Hmm... 0.30000000000000004
Enhorabuena, te has topado con la «magia» de la representación de los números fraccionarios dentro del ordenador. Sucede que muchos números no pueden representarse con exactitud en el sistema binario. Normalmente no es crítico para la mayoría de las aplicaciones, pero hay matices en finanzas y ciencias exactas.
6. Importante: double y int — conversión automática y explícita
A veces sumas un entero y un fraccionario, o asignas un int a una variable double, y no habrá errores:
int i = 2;
double d = i; // ¡Todo bien!
System.out.println(d); // 2
double dd = 3.7;
int ii = (int) dd; // ¡Hay que convertir explícitamente el tipo double a int!
System.out.println(ii); // 3, se descartó la parte fraccionaria
Esto a menudo sorprende — ¿por qué desapareció la parte fraccionaria tras la conversión? Simplemente porque el tipo int no sabe almacenar fracciones (todo lo que está después del punto desapareció para siempre).
Más detalles sobre la conversión de double a int y el operador (int) en la próxima lección.
7. Salida formateada: mostramos double de forma bonita
A menudo, por defecto, double sale con un montón de ceros de más. Se puede formatear la salida:
double temp = 23.56789;
System.out.println(temp); // 23.56789
// 2 decimales
System.out.println(String.format("%.2f", temp)); // 23.57
// 1 decimal
System.out.println(String.format("%.1f%n", temp)); // 23.6
| Formato | Resultado | Descripción |
|---|---|---|
|
23.57 | número con 2 decimales |
|
23.6 | número con 1 decimal |
8. Errores típicos al trabajar con float y double
Error n.º 1: conversión implícita de double a float
float f = 1.23; // ¡Error!
El compilador se quejará: «Estás intentando meter un double en un float — ¡esto puede provocar pérdida de precisión!». Añade siempre el sufijo f.
Error n.º 2: olvidaste que dividir dos int produce un resultado int
int a = 7, b = 2;
double result = a / b; // 3.0, no 3.5
Para obtener la parte fraccionaria, convierte explícitamente al menos uno de los operandos:
double result = (double) a / b; // 3.5
Error n.º 3: comparación de números fraccionarios
No compares números en coma flotante por igualdad con ==. Usa una comparación con una pequeña tolerancia (épsilon).
Error n.º 4: pérdida de precisión en float
No guardes números grandes ni valores muy precisos en float — pueden «romperse» o perder dígitos significativos.
GO TO FULL VERSION