Wie sind diese Werte mit doppelter Genauigkeit auf 20 Dezimalstellen genau?
Ich teste einige sehr einfache Äquivalenzfehler, wenn Genauigkeit ein Problem ist, und wollte die Operationen mit erweiterter doppelter Genauigkeit ausführen (sodass ich wusste, wie die Antwort aus ~ 19 Ziffern bestehen würde) und dann dieselben Operationen mit doppelter Genauigkeit ausführen ( wo es einen Rundungsfehler in der 16. Stelle geben würde), aber irgendwie behält meine Arithmetik mit doppelter Genauigkeit 19 Stellen Genauigkeit bei.
Wenn ich die Operationen in Extended Double durchführe und dann die Zahlen in einer anderen Fortran-Routine fest codiere, erhalte ich die erwarteten Fehler, aber ist hier etwas Merkwürdiges los, wenn ich einer Variable mit doppelter Genauigkeit eine Variable mit doppelter Genauigkeit zuordnet?
program code_gen
implicit none
integer, parameter :: Edp = selected_real_kind(17)
integer, parameter :: dp = selected_real_kind(8)
real(kind=Edp) :: alpha10, x10, y10, z10
real(kind=dp) :: alpha8, x8, y8, z8
real(kind = dp) :: pi_dp = 3.1415926535897932384626433832795028841971693993751058209749445
integer :: iter
integer :: niters = 10
print*, 'tiny(x10) = ', tiny(x10)
print*, 'tiny(x8) = ', tiny(x8)
print*, 'epsilon(x10) = ', epsilon(x10)
print*, 'epsilon(x8) = ', epsilon(x8)
do iter = 1,niters
x10 = rand()
y10 = rand()
z10 = rand()
alpha10 = x10*(y10+z10)
x8 = x10
x8 = x8 - pi_dp
x8 = x8 + pi_dp
y8 = y10
y8 = y8 - pi_dp
y8 = y8 + pi_dp
z8 = z10
z8 = z8 - pi_dp
z8 = z8 + pi_dp
alpha8 = alpha10
write(*, '(a, es30.20)') 'alpha8 .... ', x8*(y8+z8)
write(*, '(a, es30.20)') 'alpha10 ... ', alpha10
if( alpha8 .gt. x8*(y8+z8) ) then
write(*, '(a)') 'ERROR(.gt.)'
elseif( alpha8 .lt. x8*(y8+z8) ) then
write(*, '(a)') 'ERROR(.lt.)'
endif
enddo
end program code_gen
worand()
ist die Gfortran-Funktion gefundenHie.
Wenn es sich nur um einen Präzisionstyp handelt (z. B. double), können wir machine epsilon als @ bezeichneE16
was ungefähr @ i2.22E-16
. Wenn wir einfach zwei reelle Zahlen addieren,x+y
, dann ist die resultierende Maschine ausgedrückt Zahl(x+y)*(1+d1)
woabs(d1) < E16
. Ebenso, wenn wir dann diese Zahl mit @ multiplizierz
, der resultierende Wert ist wirklich(z*((x+y)*(1+d1))*(1+d2))
das ist fast(z*(x+y)*(1+d1+d2))
woabs(d1+d2) < 2*E16
. Wenn wir jetzt zu erweiterter doppelter Präzision übergehen, dann ist das einzige, was sich ändert, dassE16
wendet sich anE20
und hat einen Wert von ungefähr1.08E-19
.
Meine Hoffnung war, die Analyse in erweiterter doppelter Genauigkeit durchzuführen, damit ich zwei Zahlen vergleichen konnte, diesollt ist gleich, zeigt aber, dass gelegentlich Rundungsfehler dazu führen, dass Vergleiche fehlschlagen. Durch die Zuweisung vonx8=x10
, Ich hatte gehofft, eine 'Version' mit doppelter Genauigkeit des erweiterten Werts mit doppelter Genauigkeit zu erstellenx10
, wobei nur die ersten ~ 16 Stellen vonx8
entspricht den Werten vonx10
, aber beim Ausdrucken der Werte wird angezeigt, dass alle 20 Stellen gleich sind und der erwartete Rundungsfehler mit doppelter Genauigkeit nicht wie erwartet auftritt.
Es sollte auch beachtet werden, dass ich vor diesem Versuch ein Programm geschrieben habe, das tatsächlich @ schreibEin weitere Programm, in dem die Werte vonx
, y
, undz
sind auf 20 Dezimalstellen 'hartcodiert'. In dieser Programmversion werden die Vergleiche von.gt.
und.lt.
ist wie erwartet fehlgeschlagen, aber ich kann dieselben Fehler nicht duplizieren, indem ich einen erweiterten Wert mit doppelter Genauigkeit als Variable mit doppelter Genauigkeit umsetze.
ei dem Versuch, die Werte mit doppelter Genauigkeit weiter zu stören und einen Rundungsfehler hinzuzufügen, habe ich hinzugefügt und dann subtrahierpi
von meinen Variablen mit doppelter Genauigkeit, die die verbleibenden Variablen mit einem Rundungsfehler mit doppelter Genauigkeit belassen sollten, aber ich sehe das immer noch nicht im Endergebnis.