Während ich an einer einfachen Programmierübung arbeitete, erstellte ich eine while-Schleife (DO-Schleife in Fortran), die beendet werden sollte, wenn eine reelle Variable einen genauen Wert erreicht hatte.Hat Fortran inhärente Einschränkungen der numerischen Genauigkeit im Vergleich zu anderen Sprachen?
Ich bemerkte, dass aufgrund der Präzision, die verwendet wurde, die Gleichheit nie erreicht wurde und die Schleife unendlich wurde. Dies ist natürlich nicht unüblich und man wird darauf hingewiesen, dass man, anstatt zwei Zahlen für die Gleichheit zu vergleichen, am besten sehen sollte, ob die absolute Differenz zwischen zwei Zahlen kleiner als ein festgelegter Schwellenwert ist.
Was ich enttäuschend fand, war, wie niedrig ich diesen Grenzwert einstellen musste, sogar mit Variablen mit doppelter Genauigkeit, damit meine Schleife richtig beendet wurde. Außerdem, als ich eine "destillierte" Version dieser Schleife in Perl umschrieb, hatte ich keine Probleme mit der numerischen Genauigkeit und die Schleife endete gut.
Da der Code das Problem zu erzeugen, so klein ist, sowohl in Perl und Fortran, würde Ich mag es für den Fall, hier zu reproduzieren ich ein wichtiges Detail am Beschönigung:
Fortran-Code
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
Perl-Code
#! /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;
}
Die kommentierten-out Linie in Für tran ist, was ich für die Schleife verwenden müsste, um normal zu beenden. Beachten Sie, dass der Schwellenwert auf 1E-4 eingestellt ist, was meiner Meinung nach ziemlich erbärmlich ist.
Die Namen der Variablen stammen aus der selbstlernbasierten Programmierübung, die ich durchgeführt habe, und haben keine Relevanz.
Die Absicht ist, dass die Schleife beendet, wenn die Geschwindigkeitsgröße erreicht 1700.
Hier sind die trunkierten Ausgänge:
Perl Output
170.00000000
204.00000000
238.00000000
272.00000000
306.00000000
340.00000000
...
1564.00000000
1598.00000000
1632.00000000
1666.00000000
1700.00000000
Fortran Ausgabe
170.00000000
204.00000051
238.00000101
272.00000152
306.00000203
340.00000253
...
1564.00002077
1598.00002128
1632.00002179
1666.00002229
1700.00002280
Was nützt Geschwindigkeit und Leichtigkeit der Parallelisierung des Fortran, wenn seine Genauigkeit stinkt? Erinnert mich an die drei Möglichkeiten, Dinge zu tun:
Der richtige Weg
The Wrong Way
Die Max Power Way
„Ist das nicht nur der falsche Weg?"
" Ja! Aber schneller!“
Alle beiseite ein Scherz, ich muss etwas falsch machen.
Does Fortran haben inhärente Beschränkungen auf numerische Genauigkeit im Vergleich zu anderen Sprachen, oder bin ich (sehr wahrscheinlich) die eine Schuld?
Mein Compiler ist gfortran (gcc Version 4.1.2), Perl v5.12.1, auf einem Dual-Core AMD Opteron @ 1 GHZ.
Sollte nicht # 3 "Max Power" sein? – detly
Whoops. Du hast recht. Vielen Dank! – EMiller
Fortran benutzt hier ein Double und ich vermute, dass Perl dasselbe tut. Aber die Suche nach einem Gleichheitszeichen mit einer Fließkommazahl verlangt nach Problemen (es sei denn, Sie haben eine "sichere" Zahl wie "0.0144"). Also würde ich sagen, dass es wahrscheinlich Ihre Testmethode ist, die falsch ist. – Wolph