Mathematische Konstante PI-Wert in C.

76

Die Berechnung des PI-Werts ist eines der komplexen Probleme, und Wikipedia spricht über die dafür vorgenommenen Annäherungen und sagt, es sei schwierig, den PI genau zu berechnen.

Wie berechnet C PI? Berechnet es jedes Mal oder verwendet es einen weniger genauen festen Wert?

user1298016
quelle
25
Die Verwendung von pi, berechnet auf nur 39 Dezimalstellen, würde es einem ermöglichen, den Umfang des gesamten Universums mit einer Genauigkeit von weniger als dem Durchmesser eines Wasserstoffatoms zu berechnen . 16 Dezimalstellen (ungefähr das, was Sie mit a erhalten double) sollten ausreichen, um den Durchmesser des Sonnensystems mit einem Fehler von weniger als einer Haarbreite zu berechnen.
PMG
Ich habe dies online gefunden und finde es ziemlich interessant: crypto.stanford.edu/pbc/notes/pi/code.html
Francis Cugler

Antworten:

88

In C ist Pi in math.h definiert: #define M_PI 3.14159265358979323846

Grifos
quelle
2
Und dieser Wert ist die genaueste Darstellung, die für einen Wert mit doppelter Genauigkeit verfügbar ist.
Kapitän Giraffe
35
Nicht ganz - in der Tat eine konforme C - Implementierung kann nicht definieren PIin <math.h>. POSIX gibt an M_PI, aber eine konforme C-Implementierung definiert sie möglicherweise nicht. (POSIX stellt einige Anforderungen, die im Widerspruch zum C-Standard stehen.) Sie können dies jedoch in Ihrem eigenen Programm so definieren.
Keith Thompson
2
Also ist es ein fester Wert und es ist keine höhere Genauigkeit möglich?
user1298016
6
Zusätzliche Informationen: Wenn Sie M_PI verwenden und die Fehlermeldung erhalten, dass es nicht definiert ist, kann dies durch #define _USE_MATH_DEFINES
spin_eight
2
@Danijel M steht für "Mathe". Früher wurde allen "mathematischen Konstanten" ein Präfix vorangestellt M_. Es gab auch Sachen wie M_E, M_LN10etc. Sie es nie zum Standard gemacht.
Lundin
28

Das, was C am nächsten kommt, um π auf eine Weise zu berechnen, die für Anwendungen direkt sichtbar ist, ist acos(-1)oder ähnlich. Dies geschieht fast immer mit polynomialen / rationalen Näherungen für die zu berechnende Funktion (entweder in C oder durch den FPU-Mikrocode).

Allerdings ist eine interessante Frage ist , dass die trigonometrischen Funktionen Berechnung ( sin, cos, und tan) erfordert Reduktion ihres Arguments modulo 2π. Da 2π kein diadisches Rational (und nicht einmal Rational) ist, kann es in keinem Gleitkommatyp dargestellt werden, und daher führt die Verwendung einer Annäherung des Wertes zu einer katastrophalen Fehlerakkumulation für große Argumente (z. B. if xis 1e12und 2*M_PIunterscheidet sich von 2π) durch ε, fmod(x,2*M_PI)unterscheidet sich dann vom korrekten Wert von 2π um bis zu 1e12 * ε / π mal den korrekten Wert von xmod 2π. Das heißt, es ist völlig bedeutungslos.

Eine korrekte Implementierung der Standard-Mathematikbibliothek von C hat einfach eine gigantische, sehr hochpräzise Darstellung von π, die in ihrer Quelle hartcodiert ist, um das Problem der korrekten Argumentreduktion zu lösen (und verwendet einige ausgefallene Tricks, um es nicht ganz so gigantisch zu machen ). So funktionieren die meisten / alle C-Versionen der sin/ cos/ tan-Funktionen. Es ist jedoch bekannt, dass bestimmte Implementierungen (wie glibc) Assembly-Implementierungen auf einigen CPUs (wie x86) verwenden und keine korrekte Argumentreduktion durchführen, was zu völlig unsinnigen Ausgaben führt. (Übrigens läuft der falsche ASM normalerweise ungefähr so ​​schnell wie der richtige C-Code für kleine Argumente.)

R .. GitHub HÖREN SIE AUF, EIS ZU HELFEN
quelle
2
Ich habe nach ISO C, Anhang F, Referenz für Triggerfunktionen gesucht, aber anscheinend müssen sie nicht unbedingt die IEEE-Triggerfunktionen sein (was erfordern würde, dass sie für alle Eingaben korrekt und korrekt gerundet sind). Es kann sich also eher um ein QoI-Problem (Qualität der Implementierung) als um ein Problem der Korrektheit handeln. Auf fdlibm basierende Implementierungen weisen jedoch eine Argumentreduktion auf, die im gesamten Bereich der darstellbaren Werte funktioniert.
R .. GitHub STOP HELPING ICE
1
Okay, ich verstehe, was Sie sagen und danke für den Hinweis auf fdlibm. Mein Gedankengang war eher, dass die Berechnung des Sinus eines so großen xfast bedeutungslos ist und höchstwahrscheinlich ein Fehler im Code ist, der die Sinusfunktion verwendet. Wenn xes so groß ist, dass es eine Ganzzahl wird, können Sie nur etwa 6 Werte xpro Sinusperiode darstellen. Natürlich kann man eine finden, ydie die Bedingung erfüllt, und das ist schön, aber ich bezweifle, dass es eine nützliche Anwendung für die Berechnung von Sinuszahlen von ganzen Zahlen gibt.
Fritz
1
Interessanter als der Extremfall der ganzen Zahl xwäre eine Analyse, wie schnell dieser "Epsilon-Fehler" mit zunimmt x. Wenn es einen signifikanten Fehler bei gibt 1000*M_PI, dann verstehe ich das Problem und würde Ihnen voll und ganz zustimmen.
Fritz
2
@Fritz: Nach der groben Analyse in meiner Antwort fmod(x,2*M_PI)wächst der Fehler von vs dem korrekten argumentreduzierten Wert linear in der Größe von x. Wenn Sie also 1ulp für xetwas außerhalb des Einheitskreises annehmen , würden Sie sich etwas wie 1000ulp für ansehen 1000*M_PI. Nahe den Nullen sinist nahezu linear mit der Steigung 1, sodass die Anzahl der ulp im Argument im Ergebnis direkt in ulp übersetzt wird.
R .. GitHub STOP HELPING ICE
1
Und übrigens gibt es interessante Anwendungen sin(2^n)für große Werte von n; Ich erinnere mich jedoch nicht, was sie auf Anhieb sind.
R .. GitHub STOP HELPING ICE
21

Definieren Sie einfach:

#define M_PI acos(-1.0)

Es sollte Ihnen die genaue PI-Nummer geben, mit der mathematische Funktionen arbeiten. Wenn sie also den PI-Wert ändern, mit dem sie in Tangente, Cosinus oder Sinus arbeiten, sollte Ihr Programm immer auf dem neuesten Stand sein;)

Martin Krajčírovič
quelle
10
Dies würde jedes Mal, wenn die Konstante verwendet wird, eine ziemlich kostspielige Funktion (acos) bewerten. Kaum ein effektiver und rationaler Ansatz.
Jaromír Adamec
3
@ JaromírAdamec Eigentlich sollte jeder gute Compiler diesen Ausdruck in eine Konstante optimieren, da er eine reine Funktion aus der Standardbibliothek ist, die mit konstanten Argumenten aufgerufen wird. es sei denn, Sie kompilieren mit deaktivierten Optimierungen.
UnrealEagle
2
@ JaromírAdamec im Gegenteil, der * C-Standard erlaubt oder unterstützt sogar ausdrücklich, dass der Compiler komplizierte Details aller Standardbibliotheksfunktionen kennt!
Antti Haapala
1
@ JaromírAdamec Ich sage nichts über die Qualität einer einzelnen Implementierung. Ich behaupte nur, dass ein C-Compiler, der der in ISO 9899 beschriebenen C-Spezifikation entspricht, ausdrücklich alle Verweise auf die Standardbibliothek ersetzen / inline / ersetzen darf, wie im selben Standard beschrieben, vorausgesetzt, dass eine Funktion mit demselben Namen verwendet wird das Verhalten dem im Standard definierten entsprechen. Die Schalter, die in verschiedenen Compilern vorhanden sind, dienen nur dazu, nicht streng konforme Programme in diesen modernen Implementierungen korrekt zu kompilieren.
Antti Haapala
1
Die acosFunktion ist Teil der eigentlichen C-Sprache.
Kaz
7

Trotzdem haben Sie keine unbegrenzte Genauigkeit, also definiert C eine Konstante auf folgende Weise:

#define PI 3.14159265358979323846

Importieren Sie math.h, um dies zu verwenden

Maziar Aboualizadehbehbahani
quelle
Das heißt, ich kann es schaffen, eine höhere Genauigkeit für PI zu erzielen als durch C definiert? Wenn ich double x = 1345 * PI verwende; Aber es ist begrenzt durch die Genauigkeit der im Programm verwendeten Doppelvariablen nicht ??? Das heißt, neu definierter genauer Wert ist nutzlos?
user1298016
teilweise ja: D ... "double x = 1345 * PI" durch diese Arbeit verlieren Sie etwas an Genauigkeit, weil PI so genau wie möglich ist. Wenn Sie mehr Genauigkeit wünschen, sollten Sie IHRE EIGENE Struktur implementieren und das Ergebnis in einem Array speichern (wie BigInteger in Java). OKAY?
Maziar Aboualizadehbehbahani
1
Ist eigentlich M_PInicht in C. Es ist Teil der XSI-Erweiterungsoption in POSIX.
R .. GitHub STOP HELPING ICE
@R .., bist du sicher, dass es nur XSI ist? Die Dokumente haben nicht den normalen [XSI] -Marker, den sie nur für XSI-Inhalte haben (siehe z . B. wer ).
Matthew Flaschen
2
Ah, Sie haben sich SUSv2 angesehen, das nicht POSIX ist . Dies war vor dem Zusammenschluss der UNIX / POSIX-Spezifikation, zu diesem Zeitpunkt war der gesamte SUS XSI. Beginnend mit SUSv3 wurden die Unix- und POSIX-Standards zusammengeführt, wobei die XSI-Option die Teile von Unix waren, die nicht als ausreichend nützlich oder universell angesehen wurden, um alle POSIX-Systeme zu unterstützen. Später in SUSv4 (POSIX 2008) wurden einige der nützlicheren XSI-Optionen in den Basisstandard (POSIX) verschoben, und die weniger nützlichen Optionen werden nach und nach als veraltet markiert, sodass die XSI-Option mit etwas Glück irgendwann aufhört existieren ...
R .. GitHub STOP HELPING ICE
0

Abhängig von der Bibliothek, in der Sie die standardmäßigen GNU C-vordefinierten mathematischen Konstanten verwenden, finden Sie hier ... https://www.gnu.org/software/libc/manual/html_node/Mathematical-Constants.html

Sie haben sie bereits. Warum sollten Sie sie neu definieren? Ihre System-Desktop-Rechner haben sie wahrscheinlich und sind sogar noch genauer, sodass Sie sicher sein können, dass Sie nicht mit vorhandenen definierten in Konflikt stehen, um beim Kompilieren von Warnungen zu sparen, da diese in der Regel Standardeinstellungen für solche Dinge erhalten. Genießen!

Douglas G. Allen
quelle
-2

Ich weiß nicht genau, wie Cman PIdirekt berechnet, da ich besser vertraut bin C++als C; Sie können jedoch entweder eine vordefinierte C macrooder eine constsolche haben:

#define PI 3.14159265359.....
const float PI = 3.14159265359.....
const double PI = 3.14159265359.....
/* If your machine,os & compiler supports the long double */
const long double PI = 3.14159265359..... 

oder Sie können es mit einer dieser beiden Formeln berechnen:

#define M_PI acos(-1.0);
#define M_PI (4.0 * atan(1.0)); // tan(pi/4) = 1 or acos(-1)

IMHO bin ich nicht 100% sicher, aber ich denke, atan()ist billiger als acos().

Francis Cugler
quelle
@ RyanHaining Das war ein Tippfehler von meiner Seite. Danke, dass Sie darauf hingewiesen haben. Ich habe die entsprechenden Korrekturen vorgenommen.
Francis Cugler
1
Es ist immer noch nicht gültig C
Ryan Haining
@ RyanHaining Hmm okay; Ich weiß, dass Sie dies in C ++ tun können. Ich war mir nicht sicher, ob C dies zuließ. Es ist zu viele Jahre her, seit ich in C gearbeitet habe. Gibt es ein Äquivalent ohne Verwendung? #define CONSTANT numberHere?
Francis Cugler
"Alle Ausdrücke in einem Initialisierer für ein Objekt mit statischer oder Thread-Speicherdauer müssen konstante Ausdrücke oder Zeichenfolgenliterale sein" ( C2011, 6.7.9 / 4 ). Mir ist nicht klar, welche Eigenschaften Sie in einer Alternative haben möchten, die nicht auf einem Makro beruht, aber das ist eines der wichtigsten Dinge, mit denen Sie konfrontiert sind.
John Bollinger
@ JohnBollinger macht Sinn; Meins Cist sehr rostig, da es fast 20 Jahre her ist, seit ich daran gearbeitet habe und die Tatsache, dass ich es meistens benutzt habe C++. Ich hatte diese Frage ursprünglich mit einer C++Perspektive beantwortet ... Ich habe die Antwort aktualisiert, um dies zu berücksichtigen ...
Francis Cugler