Buscar..


Los números de punto flotante son raros

El primer error que casi todos los programadores cometen es suponer que este código funcionará según lo previsto:

float total = 0;
for(float a = 0; a != 2; a += 0.01f) {
    total += a;
}

El programador novato asume que esto resumirá cada número en el rango 0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99 , para obtener el resultado 199 la respuesta matemáticamente correcta.

Dos cosas suceden que hacen esto falso:

  1. El programa como está escrito nunca concluye. a nunca se vuelve igual a 2 , y el bucle nunca termina.
  2. Si reescribimos la lógica del bucle para verificar a < 2 lugar, el bucle termina, pero el total termina siendo algo diferente de 199 . En las máquinas compatibles con IEEE754, a menudo suman aproximadamente 201 lugar.

La razón por la que esto sucede es que los números de punto flotante representan aproximaciones de sus valores asignados .

El ejemplo clásico es el siguiente cálculo:

double a = 0.1;
double b = 0.2;
double c = 0.3;
if(a + b == c)
    //This never prints on IEEE754-compliant machines
    std::cout << "This Computer is Magic!" << std::endl; 
else
    std::cout << "This Computer is pretty normal, all things considered." << std::endl;

Si bien lo que vemos el programador son tres números escritos en base10, lo que ven el compilador (y el hardware subyacente) son números binarios. Debido a que 0.1 , 0.2 y 0.3 requieren una división perfecta por 10 cual es bastante fácil en un sistema base-10, pero imposible en un sistema base-2, estos números deben almacenarse en formatos imprecisos, de manera similar a como se muestra el número 1/3 tiene que ser almacenado en la forma imprecisa 0.333333333333333... en base-10.

//64-bit floats have 53 digits of precision, including the whole-number-part.
double a =     0011111110111001100110011001100110011001100110011001100110011010; //imperfect representation of 0.1
double b =     0011111111001001100110011001100110011001100110011001100110011010; //imperfect representation of 0.2
double c =     0011111111010011001100110011001100110011001100110011001100110011; //imperfect representation of 0.3
double a + b = 0011111111010011001100110011001100110011001100110011001100110100; //Note that this is not quite equal to the "canonical" 0.3!


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow