studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones java for-loop floating-point-precision

java - para - manual de programacion android pdf



¿Por qué el bucle con un doble no termina? (5)

Antes que nada, voy a explicar algunas cosas sobre los dobles. Esto realmente tendrá lugar en la base diez para facilitar la comprensión.

Tome el valor de un tercio y trate de expresarlo en la base diez. Obtienes 0.3333333333333 .... Digamos que necesitamos redondearlo a 4 lugares. Obtenemos 0.3333. Ahora, agreguemos otro 1/3. Obtenemos 0.6666333333333 .... que se redondea a 0.6666. Agreguemos otro 1/3. Obtenemos 0.9999, no 1.

Lo mismo ocurre con la base dos y una décima. Como vas por 0.1 10 y 0.1 10 es un valor binario repetido (como 0.1666666 ... en base diez), tendrás el error suficiente como para perder un centenar cuando llegues allí.

1/2 puede representarse en base diez muy bien, y 1/5 también. Esto se debe a que los factores primos del denominador son un subconjunto de los factores de la base. Este no es el caso para un tercio en la base diez o una décima en la base dos.

Estoy repasando viejas preguntas del examen (actualmente el primer año de la universidad) y me pregunto si alguien podría explicar un poco más a fondo por qué el siguiente ciclo for no termina cuando se supone que debe hacerlo. ¿Por qué pasó esto? Entiendo que omite 100.0 debido a un error de redondeo o algo así, pero ¿por qué?

for(double i = 0.0; i != 100; i = i +0.1){ System.out.println(i); }


Como regla general, nunca use double para iterar debido a errores de redondeo (0.1 puede verse bien cuando está escrito en la base 10, pero intente escribirlo en la base 2, que es lo que se usa double ). Lo que debes hacer es usar una variable llana int para iterar y calcular el double de ella.

for (int i = 0; i < 1000; i++) System.out.println(i/10.0);


Debería ser para (doble a = 0.0; a <100.0; a = a + 0.01)

Intenta ver si esto funciona


El número 0.1 no se puede representar exactamente en binario, al igual que 1/3 no se puede representar exactamente en decimal, por lo que no se puede garantizar que:

0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1==1

Esto es porque en binary :

0.1=(binary)0.00011001100110011001100110011001....... forever

Sin embargo, un doble no puede contener una precisión infinita, por lo que, del mismo modo que nos aproximamos a 1/3 a 0.3333333, la representación binaria debe aproximarse a 0.1.


Analogía decimal ampliada

En decimal, puede encontrar que

1/3+1/3+1/3 =0.333+0.333+0.333 =0.999

Este es exactamente el mismo problema. No debe verse como una debilidad de los números de punto flotante ya que nuestro sistema decimal tiene las mismas dificultades (pero para diferentes números, alguien con un sistema de base 3 encontraría extraño que nos costara representar 1/3). Sin embargo, es un tema a tener en cuenta.

Manifestación

Una demostración en vivo proporcionada por Andrea Ligios muestra estos errores acumulados.


Las computadoras (al menos las actuales) funcionan con datos binarios. Además, existe una limitación de longitud para que las computadoras procesen en sus unidades lógicas aritméticas (es decir, 32 bits, 64 bits, etc.). Representar enteros en forma binaria es simple, por el contrario, no podemos decir lo mismo para los puntos flotantes.

Como se muestra arriba, existe una forma especial de representar los puntos flotantes de acuerdo con IEEE-754, que también es aceptado por los productores de procesadores y los creadores de software, por eso es importante que todos lo sepan.

Si miramos el valor máximo de un doble en java (Double.MAX_VALUE) es 1.7976931348623157E308 (> 10 ^ 307). solo con 64 bits, se podrían representar números enormes, sin embargo, el problema es la precisión.

Como los operadores ''=='' y ''! ='' Comparan los números a nivel de bit, en su caso 0.1 + 0.1 + 0.1 no es igual a 0.3 en términos de los bits que están representados.

Como conclusión, para ajustar los números de coma flotante en unos pocos bits, los ingenieros inteligentes decidieron sacrificar la precisión. Si está trabajando en puntos flotantes, no debe usar ''=='' o ''! ='' A menos que esté seguro de lo que está haciendo.