64 Stimmen

Warum definieren Sie PI = 4*ATAN(1.d0)

Was ist der Grund für die Definition von PI als

PI=4.D0*DATAN(1.D0)

innerhalb von Fortran 77-Code? Ich verstehe, wie es funktioniert, aber was ist der Grund dafür?

4 Stimmen

Als Alternative würde ich fast erwarten, dass stattdessen PI = 3,1415926535... usw. erscheint.

1 Stimmen

Ich habe auf der Math Stackoverflow-Website eine hervorragende Antwort auf die mathematischen Fragen zu dieser Gleichung gefunden math.stackexchange.com/questions/1211722/

2 Stimmen

Wenn Sie PI = 3.1415926535... verwenden, müssen Sie das Datentypsuffix hinzufügen, um etwas anderes als die standardmäßige reelle Genauigkeit zu erhalten. Da Sie f66 double precision verwenden, wäre dies das Suffix D0.

68voto

John Gietzen Punkte 47223

Dieser Stil stellt sicher, dass bei der Zuweisung eines Wertes an PI die maximale auf JEDER Architektur verfügbare Genauigkeit verwendet wird.

11 Stimmen

Aber seien Sie gewarnt, wenn Sie diesen Ansatz verfolgen - nicht alle Compiler und die zugrundeliegenden Mathematikbibliotheken sind gleich in den Ergebnissen, die sie für trig-Funktionen von Fließkommazahlen zurückgeben, besonders an kritischen Punkten dieser Funktionen. Es gab kürzlich eine lange Diskussion darüber auf comp.lang.fortran, wo sich die meisten Fortran-Experten aufhalten. Ihre Schlussfolgerung: Geben Sie die Konstante mit pi = 3,14159 an... (genügend Stellen für die erforderliche Genauigkeit und dann noch einige für die Sicherheit).

8 Stimmen

High Performance Mark: es wäre schön, wenn Sie einen Link zu dem von Ihnen erwähnten comp.lang.fortran-Thread angeben könnten!

0 Stimmen

Leider geben sich einige Sprachen große Mühe, um sicherzustellen, dass der Wert von Pi, der bei diesem Ansatz zurückgegeben wird, nicht derselbe ist, der bei der Berechnung der Periode von trigonometrischen Funktionen verwendet wird.

17voto

jason Punkte 227577

Da es in Fortran keine eingebaute Konstante für PI . Aber anstatt die Zahl von Hand einzugeben und dabei möglicherweise einen Fehler zu machen oder bei der gegebenen Implementierung nicht die höchstmögliche Genauigkeit zu erzielen, können Sie das Ergebnis von der Bibliothek berechnen lassen, was garantiert, dass keiner dieser Nachteile eintritt.

Diese sind gleichwertig, und man sieht sie manchmal auch:

PI=DACOS(-1.D0)
PI=2.D0*DASIN(1.D0)

4 Stimmen

Beachten Sie, dass in Fortran 77 und später die generischen Namen ACOS und ASIN den spezifischen Namen DACOS und DASIN vorgezogen werden.

14voto

Justin Punkte 149

Ich glaube, das liegt daran, dass dies die kürzeste Serie auf Pi ist. Das bedeutet auch, dass sie die GENAUESTE ist.

Die Gregory-Leibniz-Reihe (4/1 - 4/3 + 4/5 - 4/7...) ist gleich Pi.

atan(x) = x^1/1 - x^3/3 + x^5/5 - x^7/7...

Also, atan(1) = 1/1 - 1/3 + 1/5 - 1/7 + 1/9... 4 * atan(1) = 4/1 - 4/3 + 4/5 - 4/7 + 4/9...

Dies entspricht der Gregory-Leibniz-Reihe und damit ungefähr Pi 3.1415926535 8979323846 2643383279 5028841971 69399373510.

Eine andere Möglichkeit, atan zu verwenden und pi zu finden, ist:

pi = 16*atan(1/5) - 4*atan(1/239), aber ich glaube, das ist etwas komplizierter.

Ich hoffe, das hilft!

(Um ehrlich zu sein, denke ich, dass die Gregory-Leibniz-Reihe auf atan basiert, nicht auf 4*atan(1), das auf der Gregory-Leibniz-Reihe basiert. Mit anderen Worten, der ECHTE Beweis ist:

sin^2 x + cos^2 x = 1 [Lehrsatz] Wenn x = pi/4 Bogenmaß ist, ist sin^2 x = cos^2 x, oder sin^2 x = cos^2 x = 1/2.

Dann gilt: sin x = cos x = 1/(Wurzel 2). tan x (sin x / cos x) = 1, atan x (1 / tan x) = 1.

Wenn also atan(x) = 1 ist, ist x = pi/4, und atan(1) = pi/4. Schließlich ist 4*atan(1) = pi.)

Bitte belästigen Sie mich nicht mit Kommentaren - ich bin noch ein Teenager.

0 Stimmen

Ich verstehe nicht, wie man von atan x (1/tan x) = 1 zu atan(x) = 1 kommt.

2 Stimmen

Bemerken, dass mit der Formel pi = 16*atan(1/5) - 4*atan(1/239) ist numerisch gesehen keine gute Wahl. Beide 1/5 y 1/239 können mit Gleitkommazahlen nicht genau dargestellt werden. Daher führt der Atan-Wert bereits aufgrund dieser Fließkomma-Näherungen zu Fehlern.

11voto

kvantour Punkte 22682

Hinter dieser Frage verbirgt sich mehr, als man auf den ersten Blick sieht. Warum 4 arctan(1) ? Warum nicht eine andere Darstellung wie z. B. 3 arccos(1/2) ?

Damit wird versucht, eine Antwort durch Ausschluss zu finden.

Mathematische Einführung: Bei der Verwendung von inverse trigonometrische Funktionen wie zum Beispiel arccos, arcsin y arctan kann man leicht auf verschiedene Weise berechnen:

 = 4 arctan(1) = arccos(-1) = 2 arcsin(1) = 3 arccos(1/2) = 6 arcsin(1/2)
  = 3 arcsin(sqrt(3)/2) = 4 arcsin(sqrt(2)/2) = ...

Es gibt viele andere exakte algebraische Ausdrücke für trigonometrische Werte die hier verwendet werden könnten.

Fließkomma-Argument 1: Es ist allgemein bekannt, dass ein endliche binäre Gleitkommadarstellung kann nicht vertreten todo reellen Zahlen. Einige Beispiele für solche Zahlen sind 1/3, 0.97, , sqrt(2), ... . Zu diesem Zweck sollten wir ausschließen alle mathematischen Berechnungen, bei denen das Argument der inversen trigonometrischen Funktionen nicht numerisch dargestellt werden kann. Damit bleiben uns die Argumente -1,-1/2,0,1/2 y 1 .

 = 4 arctan(1) = 2 arcsin(1)
   = 3 arccos(1/2) = 6 arcsin(1/2)
   = 2 arccos(0)
   = 3/2 arccos(-1/2) = -6 arcsin(-1/2)
   = -4 arctan(-1) = arccos(-1) = -2 arcsin(-1)

Fließkomma-Argument 2: In der binären Darstellung wird eine Zahl wie folgt dargestellt 0.b n b n-1 ...b 0 x 2 m . Wenn die inverse trigonometrische Funktion die beste numerische binäre Näherung für ihr Argument liefert, wollen wir nicht durch Multiplikation an Präzision verlieren. Zu diesem Zweck sollten wir nur mit Potenzen von 2 multiplizieren.

 = 4 arctan(1) = 2 arcsin(1)
  = 2 arccos(0)
  = -4 arctan(-1) = arccos(-1) = -2 arcsin(-1)

Note : dies ist sichtbar in der IEEE-754 binär64 Darstellung (die häufigste Form der DOUBLE PRECISION o kind=REAL64 ). Dort haben wir

write(*,'(F26.20)') 4.0d0*atan(1.0d0) -> "    3.14159265358979311600"
write(*,'(F26.20)') 3.0d0*acos(0.5d0) -> "    3.14159265358979356009"

Dieser Unterschied ist nicht vorhanden in IEEE-754 binary32 (die häufigste Form von REAL o kind=REAL32 ) und IEEE-754 binär128 (die häufigste Form von kind=REAL128 )

Argument der Umsetzung: Bei Intel-CPUs wird die atan2 ist Teil der x86-Befehlssatz als FPATAN während die anderen inversen trigonometrischen Funktionen sich ableiten aus atan2 . Eine mögliche Ableitung könnte lauten:

          mathematically         numerically
ACOS(x) = ATAN2(SQRT(1-x*x),1) = ATAN2(SQRT((1+x)*(1-x)),1)
ASIN(x) = ATAN2(1,SQRT(1-x*x)) = ATAN2(1,SQRT((1+x)*(1-x)))

Dies ist aus dem Assemblercode dieser Anweisungen ersichtlich (siehe aquí ). Zu diesem Zweck würde ich für die Verwendung von sprechen:

 = 4 arctan(1)

Note : Das ist ein unscharfes Argument. Ich bin sicher, dass es Leute gibt, die eine bessere Meinung dazu haben.
Interessante Lektüre über FPATAN : Wie wird arctan implementiert? , x87 trigonometrische Anweisungen

Das Fortran-Argument: warum sollten wir uns annähern als:

integer, parameter :: sp = selected_real_kind(6, 37)
integer, parameter :: dp = selected_real_kind(15, 307)
integer, parameter :: qp = selected_real_kind(33, 4931)

real(kind=sp), parameter :: pi_sp = 4.0_sp*atan2(1.0_sp,1.0_sp)
real(kind=dp), parameter :: pi_dp = 4.0_dp*atan2(1.0_dp,1.0_dp)
real(kind=qp), parameter :: pi_qp = 4.0_qp*atan2(1.0_qp,1.0_qp)

und nicht :

real(kind=sp), parameter :: pi_sp = 3.14159265358979323846264338327950288_sp
real(kind=dp), parameter :: pi_dp = 3.14159265358979323846264338327950288_dp
real(kind=qp), parameter :: pi_qp = 3.14159265358979323846264338327950288_qp

Die Antwort liegt in der Fortran-Standard . Die Norm niemals besagt, dass ein REAL jeglicher Art sollte eine IEEE-754 Gleitkommazahl . Die Darstellung von REAL ist prozessorabhängig. Das bedeutet, dass ich mich erkundigen könnte selected_real_kind(33, 4931) und erwarten, eine binäre128-Gleitkommazahl aber vielleicht bekomme ich eine kind zurückgegeben, die eine Gleitkommazahl mit viel höherer Genauigkeit darstellt. Vielleicht 100 Ziffern, wer weiß. In diesem Fall ist meine obige Zahlenfolge zu kurz! Man kann nicht verwenden este nur um sicherzugehen? Auch diese Datei könnte zu kurz sein!

Interessante Tatsache: sin(pi) is never zero

write(*,'(F17.11)') sin(pi_sp) => "   -0.00000008742"
write(*,'(F26.20)') sin(pi_dp) => "    0.00000000000000012246"
write(*,'(F44.38)') sin(pi_qp) => "    0.00000000000000000000000000000000008672"

was so verstanden wird:

pi = 4 ATAN2(1,1) =  + 
SIN(pi) = SIN(pi - ) = SIN()  

program print_pi
! use iso_fortran_env, sp=>real32, dp=>real64, qp=>real128

  integer, parameter :: sp = selected_real_kind(6, 37)
  integer, parameter :: dp = selected_real_kind(15, 307)
  integer, parameter :: qp = selected_real_kind(33, 4931)

  real(kind=sp), parameter :: pi_sp = 3.14159265358979323846264338327950288_sp
  real(kind=dp), parameter :: pi_dp = 3.14159265358979323846264338327950288_dp
  real(kind=qp), parameter :: pi_qp = 3.14159265358979323846264338327950288_qp

  write(*,'("SP "A17)') "3.14159265358..."
  write(*,'(F17.11)') pi_sp
  write(*,'(F17.11)')        acos(-1.0_sp)
  write(*,'(F17.11)') 2.0_sp*asin( 1.0_sp)
  write(*,'(F17.11)') 4.0_sp*atan2(1.0_sp,1.0_sp)
  write(*,'(F17.11)') 3.0_sp*acos(0.5_sp)
  write(*,'(F17.11)') 6.0_sp*asin(0.5_sp)

  write(*,'("DP "A26)') "3.14159265358979323846..."
  write(*,'(F26.20)') pi_dp
  write(*,'(F26.20)')        acos(-1.0_dp)
  write(*,'(F26.20)') 2.0_dp*asin( 1.0_dp)
  write(*,'(F26.20)') 4.0_dp*atan2(1.0_dp,1.0_dp)
  write(*,'(F26.20)') 3.0_dp*acos(0.5_dp)
  write(*,'(F26.20)') 6.0_dp*asin(0.5_dp)

  write(*,'("QP "A44)') "3.14159265358979323846264338327950288419..."
  write(*,'(F44.38)') pi_qp
  write(*,'(F44.38)')        acos(-1.0_qp)
  write(*,'(F44.38)') 2.0_qp*asin( 1.0_qp)
  write(*,'(F44.38)') 4.0_qp*atan2(1.0_qp,1.0_qp)
  write(*,'(F44.38)') 3.0_qp*acos(0.5_qp)
  write(*,'(F44.38)') 6.0_qp*asin(0.5_qp)

  write(*,'(F17.11)') sin(pi_sp)
  write(*,'(F26.20)') sin(pi_dp)
  write(*,'(F44.38)') sin(pi_qp)

end program print_pi

0 Stimmen

Zusammen mit dem Argument sin(pi) /= 0 habe ich immer gezögert, anzunehmen, dass acos(-1d0) genauso genau ist wie 4*atan(1d0), obwohl es je nach Implementierung so sein kann.

0 Stimmen

Ich glaube, es gibt einen bewährten Algorithmus für sin(), um einen korrekt gerundeten Wert für große Argumente zu erzeugen, auch wenn dies mit erheblicher zusätzlicher Ausführungszeit verbunden ist. Ich habe die Referenz nicht gesehen. Bei einigen IBM-Bibliotheken ist das standardmäßig der Fall. Jede qualitativ hochwertige Implementierung beinhaltet eine Simulation zusätzlicher Präzision, die eine signifikante Verschlechterung der Genauigkeit bis zu Argumenten vermeidet, die so groß sind, wie sie in der Praxis nützlich sein könnten, z. B. +-20 Pi, oder den (kleineren) Punkt, an dem die interne m387-Implementierung abrupt von der Rückgabe eines genauen Wertes zur Rückgabe des Arguments wechselt.

0 Stimmen

Übrigens wird die interne Pi-Konstante in der m387-Firmware mit einer Genauigkeit von 66 Bit beworben. Tatsächlich ist dies nichts Besonderes in der Implementierung; der korrekt gerundete 66-Bit-Präzisionswert hat 2 Nullbits niedriger Ordnung. Ein qualitativ hochwertiger C-Compiler wird Ihnen diesen Wert für eine lange Doppelkonstante mit 21 Ziffern liefern.

9voto

John Feminella Punkte 292907

Denn dies ist eine exakte Methode zur Berechnung von pi mit beliebiger Genauigkeit. Sie können die Funktion einfach weiter ausführen, um eine immer höhere Genauigkeit zu erreichen, und an einem beliebigen Punkt anhalten, um eine Annäherung zu erhalten.

Im Gegensatz dazu ist die Angabe von pi als Konstante liefert Ihnen genau so viel Genauigkeit wie ursprünglich angegeben, was für hochwissenschaftliche oder mathematische Anwendungen (wie sie in Fortran häufig verwendet werden) nicht unbedingt geeignet ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X