El problema está en que los ordenadores siguen la matemática binaria, y en ella,
es difícil representar los números decimales.
Si hacemos el siguiente cambio:
Using perl Syntax Highlighting
for (my $i = 0; $i < 0.8; $i += 0.1) {
printf "%.40f\n", $i;
}
__END__
Coloreado en 0.001 segundos, usando
GeSHi 1.0.8.4
Sale:
- 0.0000000000000000000000000000000000000000
- 0.1000000000000000055511151231257827021182
- 0.2000000000000000111022302462515654042363
- 0.3000000000000000444089209850062616169453
- 0.4000000000000000222044604925031308084726
- 0.5000000000000000000000000000000000000000
- 0.5999999999999999777955395074968691915274
- 0.6999999999999999555910790149937383830547
- 0.7999999999999999333866185224906075745821
Como ves, el penúltimo número no es exactamente igual a 0.7, así al sumarle 0.1, se sigue cumpliendo la condición, por lo que sigue una vuelta más.
Si salen bien en pantalla es por la precisión que elegiste, que hace el redondeo. Pero una cosa es verlo y otra cosa es lo que realmente es.
Esto no es un error del lenguaje, sino del propio funcionamiento de los ordenadores.
En Informática existe, en la asignatura de Matemáticas, un apartado dedicado a tratar estos temas (y otros) bajo el nombre de
cálculo numérico, en concreto,
redondeo,
truncamiento y
error de aproximación (buscar por error computacional).
La solución es adoptar medidas de seguridad, tolerancia a los errores, cuando trabajamos con estos números. Por ejemplo:
Using perl Syntax Highlighting
for (my $i = 0; $i < 0.8-1e-6; $i += 0.1) {
printf "%.4f\n", $i;
}
Coloreado en 0.001 segundos, usando
GeSHi 1.0.8.4
Aquí, incluimos una tolerancia de una millonésima por debajo del límite del 0.8 por la cual ya salimos del bucle.