• Publicidad

¿Bug en Perl 5.10?

Así que programas sin strict y las expresiones regulares son otro modo de hablar. Aquí encontrarás respuestas de nivel avanzado, no recomendable para los débiles de corazón.

¿Bug en Perl 5.10?

Notapor netsoul » 2009-07-05 13:42 @612

Algo muy curioso que he visto.

Considerando el siguiente código:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for($i = 0; $i < 0.4; $i = $i + 0.1)
  2. {
  3. print "$i\n";
  4. }
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


La salida es como se esperaba:

Sintáxis: [ Descargar ] [ Ocultar ]
  1. 0.1 
  2. 0.2 
  3. 0.3 


También con:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for($i = 0; $i < 0.7; $i = $i + 0.1)
  2. {
  3. print "$i\n";
  4. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Salida normal:

Sintáxis: [ Descargar ] [ Ocultar ]
  1. 0.1 
  2. 0.2 
  3. 0.3 
  4. 0.4 
  5. 0.5 
  6. 0.6 


Ahora viene lo mágico, hacemos $i menor que 0.8:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for($i = 0; $i < 0.8; $i = $i + 0.1)
  2. {
  3. print "$i\n";
  4. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


La salida es:

Sintáxis: [ Descargar ] [ Ocultar ]
  1. 0.1 
  2. 0.2 
  3. 0.3 
  4. 0.4 
  5. 0.5 
  6. 0.6 
  7. 0.7 
  8. 0.8 


:shock: , se esperaba hasta 0.7, ¡pero no, hasta 0.8!, que también colocando $i < 0.9, el resultado es hasta 0.9

¿Es un error de estructuración, o es nada más que algo minúsculo que no lo estoy pudiendo ver?
With Perl
Imagination is more important than knowledge. Albert Einstein.
netsoul
Perlero nuevo
Perlero nuevo
 
Mensajes: 150
Registrado: 2008-05-04 01:11 @091

Publicidad

Re: ¿Bug en Perl 5.10?

Notapor explorer » 2009-07-05 17:21 @765

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:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for (my $i = 0; $i < 0.8; $i += 0.1) {
  2.     printf "%.40f\n", $i;
  3. }
  4. __END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Sale:
Sintáxis: [ Descargar ] [ Ocultar ]
  1. 0.0000000000000000000000000000000000000000 
  2. 0.1000000000000000055511151231257827021182 
  3. 0.2000000000000000111022302462515654042363 
  4. 0.3000000000000000444089209850062616169453 
  5. 0.4000000000000000222044604925031308084726 
  6. 0.5000000000000000000000000000000000000000 
  7. 0.5999999999999999777955395074968691915274 
  8. 0.6999999999999999555910790149937383830547 
  9. 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:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for (my $i = 0; $i < 0.8-1e-6; $i += 0.1) {
  2.     printf "%.4f\n", $i;
  3. }
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.
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: ¿Bug en Perl 5.10?

Notapor netsoul » 2009-07-05 21:14 @926

Gracias explorer.

"Lo sospeché desde un principio". Ya me estaba preocupando. Hasta lo estaba probando en C.

Sintáxis: [ Descargar ] [ Ocultar ]
  1. #include<stdio.h> 
  2.  
  3. main(void) 
  4.  
  5. {     
  6.     float i; 
  7.     for(i = 0; i < 0.8; i = i + 0.1) 
  8.     printf("%f\n", i); 


Salida:
Sintáxis: [ Descargar ] [ Ocultar ]
  1. 0.000000 
  2. 0.100000 
  3. 0.200000 
  4. 0.300000 
  5. 0.400000 
  6. 0.500000 
  7. 0.600000 
  8. 0.700000 

Bueno, para este caso creo que se debería definir primero la cantidad de decimales.
With Perl
Imagination is more important than knowledge. Albert Einstein.
netsoul
Perlero nuevo
Perlero nuevo
 
Mensajes: 150
Registrado: 2008-05-04 01:11 @091


Volver a Avanzado

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados