1

Para un programa que estoy diseñando, pido al usuario un float por pantalla. Como quiero un número entre 0 y 99.999 (ambos incluidos) si el usuario introduce cualquier número fuera de ese rango, vuelvo a pedir el número. El código es este:

public static void main(String[] args) {

    double number;
    Scanner sc = new Scanner(System.in);

    do {
        System.out.println("Ingrese un número entre 0 y 99.999");
        number = (float)sc.nextFloat();
    } while (!(number >= 0 && number <= 99.999));
}

Haciendo pruebas he descubierto que si se introduce por pantalla el número 99.999 la condición del while da false y vuelve al do, así que pide otra vez el número, y no entiendo por qué. ¿Me podéis ayudar?

Arcones
  • 113
  • 4
  • Si pruebas cambiar tu condicion por `Float.compareTo` en lugar de `>=` y `<=` quiza el problema sea [este](http://es.stackoverflow.com/q/197/2027) – jasilva Feb 23 '16 at 21:02

2 Answers2

3

Como bien indica jasilva, la explicación a tu problema se explica acá: ¿Por qué mis programas no pueden hacer cálculos aritméticos correctamente? Para resolverlo, lo mejor sería almacenar el número en una variable de tipo BigDecimal y realizar las comparaciones correspondientes.

Acá un ejemplo:

BigDecimal maxValor = new BigDecimal("99.999");
BigDecimal bd;
do {
    System.out.println("Ingrese un número entre 0 y 99.999");
    bd = new BigDecimal(sc.next());
} while (!(bd.compareTo(BigDecimal.ZERO) >= 0 && bd.compareTo(maxValor) <= 0));
  • 1
    bueno, la segunda tomaría 99.9999 como verdadero y debería ser falso. Para mayor exactitud la primera es mejor. – rnrneverdies Feb 23 '16 at 21:13
  • 1
    @rnd corregido. Aunque en realidad la comparación a 99.999 o 99.9999 o 99.999999 o 99.99999999...999 es un poco insulso para este caso. Lo usaría si es que estoy trabajando con operaciones matemáticas que necesitan mayor precisión como operaciones financieras o científicas. Para este caso, el `< 100` sería lo más apropiado puesto que los otros decimales se pueden considerar despreciables. –  Feb 23 '16 at 21:17
0

No es necesario el compareTo, por lo menos en mi caso el programa compiló y corrió bien:

public static void main(String []args){
    float number;

    Scanner sc = new Scanner(System.in);

    do {
        System.out.println("Ingrese un numero entre 0 y 99.999");
        number = Float.parseFloat(sc.nextLine());
    } while (!(number >= 0 && number <= 99.999));
 }

La línea donde se asigna lo digitado a number hace un doble cast y segundo, en principio se declara como double pero se asigna un float por lo que el valor siempre será falso: https://stackoverflow.com/questions/11581337/different-values-for-float-and-double

El ejemplo compilado:

Glorfindel
  • 801
  • 1
  • 11
  • 20
Néstor
  • 199
  • 1
  • 11
  • Ese es el problema con los números flotantes representados en binario. **En tu caso** corre bien, en el mío también puede correr bien, pero si lo llevas al ambiente de producción puede explotar y generar pérdidas de millones de dólares!!! o quizás solo encontrar otra PC donde esto falle y evidencies que ejecutar operaciones con los tipos de punto flotante `float` y `double` no permiten obtener valores exactos –  Feb 23 '16 at 23:03
  • si señor, aunque dudo que en un equipo los operadores de comparación se comporten diferente que en otro ya que eso sería nativo del propio lenguaje. el código de la pregunta a mi me dio un error en la asignación de la variable number por lo que me tocó convertir la variable en float. – Néstor Feb 24 '16 at 21:26
  • En realidad eso sucede con las operaciones de comparación de punto flotante. Acá hay material que respalda la información: https://en.wikipedia.org/wiki/IEEE_floating_point https://en.wikipedia.org/wiki/Single-precision_floating-point_format http://www.exploringbinary.com/why-0-point-1-does-not-exist-in-floating-point/ y hay más: https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html http://lectures.molgen.mpg.de/AlgoStoc/ieee.html http://grouper.ieee.org/groups/754/ y más... –  Feb 24 '16 at 21:30