Mientras trabajaba en un ejercicio de programación simple, produje un ciclo while (lazo DO en Fortran) que estaba destinado a salir cuando una variable real había alcanzado un valor preciso.¿Fortran tiene limitaciones inherentes a la precisión numérica en comparación con otros lenguajes?
Noté que debido a la precisión que se usaba, la igualdad nunca se cumplía y el ciclo se hacía infinito. Por supuesto, esto no es desconocido y se aconseja a uno que, en lugar de comparar dos números para la igualdad, lo mejor es ver si la diferencia absoluta entre dos números es menor que un umbral establecido.
Lo que encontré decepcionante fue lo bajo que tuve que establecer este umbral, incluso con variables con doble precisión, para que mi ciclo salga correctamente. Además, cuando reescribí una versión "destilada" de este ciclo en Perl, no tuve problemas con la precisión numérica y el ciclo salió bien.
Dado que el código para producir el problema es tan pequeño, tanto en Perl y Fortran, me gustaría reproducir aquí en caso de que estoy pasando por alto un detalle importante:
Código Fortran
PROGRAM precision_test
IMPLICIT NONE
! Data Dictionary
INTEGER :: count = 0 ! Number of times the loop has iterated
REAL(KIND=8) :: velocity
REAL(KIND=8), PARAMETER :: MACH_2_METERS_PER_SEC = 340.0
velocity = 0.5 * MACH_2_METERS_PER_SEC ! Initial Velocity
DO
WRITE (*, 300) velocity
300 FORMAT (F20.8)
IF (count == 50) EXIT
IF (velocity == 5.0 * MACH_2_METERS_PER_SEC) EXIT
! IF (abs(velocity - (5.0 * MACH_2_METERS_PER_SEC)) < 1E-4) EXIT
velocity = velocity + 0.1 * MACH_2_METERS_PER_SEC
count = count + 1
END DO
END PROGRAM precision_test
Código Perl línea de
#! /usr/bin/perl -w
use strict;
my $mach_2_meters_per_sec = 340.0;
my $velocity = 0.5 * $mach_2_meters_per_sec;
while (1) {
printf "%20.8f\n", $velocity;
exit if ($velocity == 5.0 * $mach_2_meters_per_sec);
$velocity = $velocity + 0.1 * $mach_2_meters_per_sec;
}
La salida comentado en Para tran es lo que necesitaría para que el ciclo salga normalmente. Tenga en cuenta que el umbral está configurado en 1E-4, lo que me parece bastante patético.
Los nombres de las variables provienen del ejercicio de programación basado en el autoaprendizaje que estaba realizando y no tienen ninguna relevancia.
La intención es que el bucle se detiene cuando la variable de velocidad alcanza 1700.
Aquí son las salidas truncadas:
Perl salida
170.00000000
204.00000000
238.00000000
272.00000000
306.00000000
340.00000000
...
1564.00000000
1598.00000000
1632.00000000
1666.00000000
1700.00000000
salida Fortran
170.00000000
204.00000051
238.00000101
272.00000152
306.00000203
340.00000253
...
1564.00002077
1598.00002128
1632.00002179
1666.00002229
1700.00002280
Qué buena es la velocidad de Fortran y facilidad de paralelización si su exactitud apesta? Me recuerda a las tres formas de hacer las cosas:
la manera correcta
la manera incorrecta
El Power Max Camino
"¿No es que solo ¿la forma incorrecta?"
" ¡Sí! Pero más rápido!"
Bromas aparte, debo estar haciendo algo mal.
¿El Fortran tiene limitaciones inherentes en la precisión numérica en comparación con otros idiomas, o soy yo (muy probable) el culpable?
Mi compilador es gfortran (gcc versión 4.1.2), Perl v5.12.1, en un doble núcleo AMD Opteron @ 1 GHz.
¿No debería el # 3 ser "El modo de máxima potencia"? – detly
Whoops. Tienes razón. ¡Gracias! – EMiller
Fortran está usando un doble aquí y sospecho que Perl hará lo mismo. Pero buscar un igual con un número de punto flotante es pedir problemas (a menos que tengas un número "seguro" como '0.0144'). Entonces diría que probablemente sea tu método de prueba lo que está mal. – Wolph