PI-Wert der mathematischen Konstante in C

Lesezeit: 9 Minuten

Benutzeravatar von user1298016
Benutzer1298016

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

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

Benutzeravatar von grifos
grifos

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

  • Und dieser Wert ist die genaueste Darstellung, die für einen Wert mit doppelter Genauigkeit verfügbar ist.

    – Kapitän Giraffe

    28. März 2012 um 16:53 Uhr


  • Nicht ganz – tatsächlich eine konforme C-Implementierung nicht dürfen definieren PI in <math.h>. POSIX spezifiziert M_PI, aber wiederum kann eine konforme C-Implementierung es nicht definieren. (POSIX stellt einige Anforderungen, die im Widerspruch zum C-Standard stehen.) Aber Sie können es in Ihrem eigenen Programm so definieren.

    – Keith Thompson

    28. März 2012 um 16:53 Uhr


  • Es ist also ein fester Wert und es ist keine höhere Genauigkeit möglich?

    – Benutzer1298016

    28. März 2012 um 17:03 Uhr

  • Zusätzliche Informationen: Wenn Sie M_PI verwenden und eine Fehlermeldung erhalten, dass es nicht definiert ist, kann dies durch #define _USE_MATH_DEFINES behoben werden

    – spin_acht

    2. Juni 2014 um 2:29 Uhr

  • @Danijel M steht für “Mathematik”. Früher wurde allen “mathematischen Konstanten” ein Präfix vorangestellt M_. Es gab auch Sachen wie M_E, M_LN10 usw. Sie haben es nie zum Standard geschafft.

    – Ludin

    31. Mai 2018 um 14:16 Uhr

Das, was C dem “Berechnen von π” auf eine Weise am nächsten kommt, die für Anwendungen direkt sichtbar ist, ist acos(-1) oder ähnliches. Dies erfolgt fast immer mit polynomialen/rationalen Approximationen für die zu berechnende Funktion (entweder in C oder durch den FPU-Mikrocode).

Ein interessantes Problem ist jedoch, dass die Berechnung der trigonometrischen Funktionen (sin, cosund tan) erfordert eine Reduktion ihres Arguments modulo 2π. Da 2π kein diadisches Rational ist (und nicht einmal rational), kann es nicht in einem Fließkommatyp dargestellt werden, und daher führt die Verwendung einer Annäherung des Werts zu einer katastrophalen Fehlerakkumulation für große Argumente (z x ist 1e12und 2*M_PI unterscheidet sich also von 2π um ε fmod(x,2*M_PI) weicht vom korrekten Wert von 2π um bis zu 1e12*ε/π mal dem korrekten Wert von ab x mod 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 ihrem Quellcode 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 des sin/cos/tan Funktionen funktionieren. 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 das falsche asm für kleine Argumente normalerweise etwa so schnell wie der richtige C-Code.)

  • Ich habe nach ISO C, Anhang F, Referenz für Triggerfunktionen gesucht, aber anscheinend gibt es keine zwingende Anforderung, dass es sich um IEEE-Triggerfunktionen handelt (was erfordern würde, dass sie für alle Eingänge korrekt und korrekt gerundet sind). Es kann sich also eher um ein QoI-Problem (Qualität der Implementierung) als um ein Korrektheitsproblem handeln. Aber Implementierungen, die auf fdlibm basieren, haben eine Argumentreduktion, die über den gesamten Bereich darstellbarer Werte hinweg funktioniert.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    31. Juli 2017 um 14:23 Uhr

  • Okay, ich verstehe, was Sie sagen, und danke für den Hinweis auf fdlibm. Mein Gedankengang war mehr, als den Sinus eines so großen zu berechnen x ist fast bedeutungslos und höchstwahrscheinlich ein Fehler im Code, der die Sinusfunktion verwendet. Wenn x so groß ist, dass es ganzzahlig wird, dann können Sie nur etwa 6 Werte darstellen x pro Sinusperiode. Natürlich findet man eine y was die Bedingung erfüllt, und das ist schön, aber ich bezweifle, dass es eine nützliche Anwendung zum Berechnen von Sinuszahlen gibt.

    – Fritz

    1. August 2017 um 7:37 Uhr

  • Interessanter als der Extremfall von Integer x wäre eine Analyse, wie schnell dieser “Epsilon-Fehler” mit ansteigt x. Liegt ein wesentlicher Fehler vor 1000*M_PIdann verstehe ich das Problem und würde Ihnen voll und ganz zustimmen.

    – Fritz

    1. August 2017 um 7:40 Uhr

  • @Fritz: Nach der groben Analyse in meiner Antwort ist der Fehler von fmod(x,2*M_PI) vs der richtige Argument-reduzierte Wert wächst linear in der Größenordnung von x. Angenommen also 1ulp für x direkt außerhalb des Einheitskreises würden Sie nach etwas wie 1000 ulp suchen 1000*M_PI. In der Nähe der Nullen sin ist nahezu linear mit Steigung 1, sodass die # von ulp im Argument direkt in ulp im Ergebnis übersetzt wird.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    1. August 2017 um 22:52 Uhr

  • Und übrigens gibt es interessante Anwendungen von sin(2^n) für große Werte von n; Ich erinnere mich jedoch nicht, was sie sind.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    1. August 2017 um 22:53 Uhr

Benutzeravatar von Martin Krajčírovič
Martin Krajčírovič

Definiere 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 arbeiten, in Tangens oder Cosinus oder Sinus, dann sollte Ihr Programm immer auf dem neuesten Stand sein;)

  • Dies würde jedes Mal, wenn die Konstante verwendet wird, eine ziemlich kostspielige Funktion (acos) auswerten. Kaum ein effektiver und rationaler Ansatz.

    – Jaromír Adamec

    29. August 2017 um 10:58 Uhr

  • @JaromírAdamec Eigentlich sollte jeder gute Compiler diesen Ausdruck in eine Konstante optimieren, da es sich um eine reine Funktion aus der Standardbibliothek handelt, die mit konstanten Argumenten aufgerufen wird. es sei denn, Sie kompilieren mit ausgeschalteten Optimierungen.

    – AquilaIrreale

    18. Oktober 2017 um 12:26 Uhr

  • @JaromírAdamec im Gegenteil, der * C-Standard erlaubt – oder unterstützt sogar – ausdrücklich, dass der Compiler komplizierte Details aller Standardbibliotheksfunktionen kennt!

    – Antti Haapala – Слава Україні

    31. Mai 2018 um 14:14 Uhr

  • @JaromírAdamec Ich sage nichts über die Qualität einer einzelnen Implementierung. Ich behaupte nur, dass es sich um einen C-Compiler handelt, der der C-Spezifikation entspricht, wie sie in ISO 9899 beschrieben ist ausdrücklich erlaubt, alle Verweise auf Standardbibliotheken zu ersetzen/inline/substituieren, wie in demselben Standard beschrieben, unter der Annahme, dass eine Funktion mit demselben Namen das Verhalten hat, das dem im Standard definierten entspricht. Die Schalter, die in verschiedenen Compilern vorhanden sind, existieren nur, um zu machen nicht streng konforme Programme in diesen modernen Implementierungen korrekt kompilieren.

    – Antti Haapala – Слава Україні

    1. Juni 2018 um 13:39 Uhr


  • Das acos Die Funktion ist ein Teil der eigentlichen C-Sprache.

    – Kas

    12. September 2018 um 22:16 Uhr

Benutzeravatar von Maziar Aboualizadehbehbahani
Maziar Aboualizadehbehbahani

sowieso hast du keine unbegrenzte Genauigkeit, also definiere C eine Konstante auf diese Weise:

#define PI 3.14159265358979323846

Importieren Sie math.h, um dies zu verwenden

Benutzeravatar von Maximilian
Maximilian

Sie könnten eine Funktion erstellen, die PI berechnet, indem Sie eine von mehreren möglichen Endlossummenberechnungen durchführen (ich würde so etwas wie atan () nicht empfehlen, da diese Funktionen wahrscheinlich selbst pi in der einen oder anderen Form verwenden). Das heißt, ich würde nicht empfehlen, Pi manuell zu berechnen. Niemand braucht pi, um genauer zu sein, als math.h mit M_PI bereitstellt. Tatsächlich wäre es wahrscheinlich am besten, stattdessen nur die ersten paar Ziffern davon zu verwenden, da dies Ihnen einen etwas schnelleren Code ermöglichen würde. Warum sollten Sie sich die Mühe machen, es sei denn, Sie wollen die Größe des Universums auf den Zentimeter genau berechnen?

Wenn Sie es trotzdem berechnen möchten, erfahren Sie hier, wie

(Methode aus 3blau 1 braun Das Wallis-Produkt für Pi, geometrisch bewiesen

double caculate_pi(int accuracy){
     double result = 1;
     int a = 2;
     int b = 1;

     for(i = 0;i < accuracy; i ++){
          result = a/b * result;
          if(a < b){
               a = a + 2;
          }
          else if(b < a){
               b = b + 2;
          }
     }

     return result * 2;
}

Benutzeravatar von Douglas G. Allen
Douglas G. Allen

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

Sie haben sie bereits, also warum sie neu definieren? Ihre System-Desktop-Rechner haben sie wahrscheinlich und sind sogar noch genauer, also könnten Sie nur sicher sein, dass Sie nicht mit bestehenden definierten in Konflikt geraten, um Kompilierungswarnungen zu sparen, da sie dazu neigen, Standardwerte für solche Dinge zu erhalten. Genießen!

Ich weiß nicht genau wie C berechnet PI direkt, wie ich mehr vertraut bin C++ als C; Sie könnten jedoch entweder eine vordefinierte haben C macro oder const wie zum Beispiel:

#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önnten 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 mir nicht 100% sicher, aber ich denke atan() ist günstiger als acos().

  • @RyanHaining Das war ein reiner Tippfehler meinerseits, danke, dass du darauf hingewiesen hast. Ich habe die entsprechenden Korrekturen vorgenommen.

    – Franz Cugler

    14. November 2018 um 1:45 Uhr

  • Es ist immer noch kein gültiges C

    – Ryan Haining

    14. November 2018 um 3:04 Uhr

  • @RyanHaining Hmm okay; Ich weiß, dass Sie dies in C++ tun können. Ich war mir nicht sicher, ob C dies zulässt. Es ist zu viele Jahre her, seit ich in C gearbeitet habe. Gibt es ein Äquivalent ohne using; #define CONSTANT numberHere?

    – Franz Cugler

    14. November 2018 um 4:24 Uhr

  • “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 sich von einer Alternative erhoffen, die sich nicht auf ein Makro stützt, aber das ist eines der Hauptprobleme, mit denen Sie es zu tun haben.

    – Johannes Bollinger

    14. November 2018 um 4:36 Uhr

  • @JohnBollinger Macht Sinn; mein C ist sehr rostig, da es fast 20 Jahre her ist, seit ich daran gearbeitet habe, und die Tatsache, dass ich es meistens benutzt habe C++. Diese Frage hatte ich ursprünglich mit a beantwortet C++ Perspektive im Hinterkopf … Ich habe die Antwort aktualisiert, um dies zu berücksichtigen …

    – Franz Cugler

    14. November 2018 um 4:39 Uhr

1419980cookie-checkPI-Wert der mathematischen Konstante in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy