Führt C ++ 11, 14, 17 oder 20 eine Standardkonstante für pi ein?

170

Es gibt ein ziemlich dummes Problem mit der Zahl pi in C und C ++. Soweit ich weiß, ist die M_PIDefinition in math.hkeiner Norm erforderlich.

Neue C ++ - Standards führten eine Menge komplizierter Mathematik in die Standardbibliothek ein - hyperbolische Funktionen std::hermiteund std::cyl_bessel_iverschiedene Zufallszahlengeneratoren und so weiter und so fort.

Hat einer der "neuen" Standards eine Konstante für pi eingeführt? Wenn nicht - warum? Wie funktioniert all diese komplizierte Mathematik ohne sie?

Mir sind ähnliche Fragen zu pi in C ++ bekannt (sie sind mehrere Jahre alt und Standards alt). Ich würde gerne den aktuellen Stand des Problems erfahren.

Ich bin auch sehr interessiert daran, warum oh, warum C ++ immer noch keine pi-Konstante hat, aber viel kompliziertere Mathematik.

UPD: Ich weiß, dass ich pi selbst als 4 * atan (1) oder acos (1) oder double pi = 3.14 definieren kann. Sicher. Aber warum muss ich es 2018 noch tun? Wie funktionieren Standard-Mathematikfunktionen ohne pi?

UPD2: Laut diesem Reisebericht für die Sitzung des C ++ - Komitees im Juli 2019 in Köln wurde der Vorschlag P0631 (mathematische Konstanten) in C ++ 20 aufgenommen. Es sieht also so aus, als hätten wir endlich die Nummer pi in der Standardbibliothek!

Amomum
quelle
Sie stellen fest, dass es alte Fragen wie die beste plattformunabhängige pi-Konstante gibt? . Wenn Sie befürchten, dass sie nicht mehr aktuell sind, können Sie jederzeit eine Prämie für einen von ihnen festlegen, der nach Antworten auf der Basis von C ++ 17 usw. fragt. Dann befinden sich alle Antworten an einem Ort. Warum ist immer noch eine gute Frage, aber vielleicht sollte sich dies auf das Warum konzentrieren, und das Nachfragen nach Aktualität sollte eine Prämie für bestehende Fragen sein.
Shafik Yaghmour
Ich denke, es könnte sich lohnen, neue Antworten hinzuzufügen, da C ++ 20
meines
@ GuillaumeRacicot Ich habe die Frage aktualisiert. Ich bin mir nicht sicher, ob wir C ++ 20 ansprechen sollen, da es noch nicht offiziell veröffentlicht wurde.
Amomum
@ GuillaumeRacicot: Es ist ein bisschen spät, einen hinzuzufügen ...
Davis Herring

Antworten:

101

Bis einschließlich C ++ 17 pi ist keine Konstante, die in die Sprache eingeführt wird, und es ist ein Schmerz im Nacken.

Ich habe das Glück, dass ich Boost verwende und sie pi mit einer ausreichend großen Anzahl von Dezimalstellen für sogar 128 Bit definieren long double.

Wenn Sie Boost nicht verwenden, können Sie es selbst fest codieren. Es ist verlockend, es mit einer trigonometrischen Funktion zu definieren, aber wenn Sie das tun, können Sie es nicht zu einem machen constexpr. Die Genauigkeit der trigonometrischen Funktionen wird auch von keinem mir bekannten Standard garantiert ( vgl . std::sqrt). Sie befinden sich also tatsächlich auf gefährlichem Boden und verlassen sich tatsächlich auf eine solche Funktion.

Es gibt eine Möglichkeit, mithilfe der Metaprogrammierung einen constexprWert für pi zu erhalten : siehe http://timmurphy.org/2013/06/27/template-metaprogramming-in-c/


Ab C ++ 20 einige gute Neuigkeiten. Es gibt eine Definition für pi . C ++ 20 fügt einige mathematische Konstanten hinzu <numbers>. Zum Beispiel std::numbers::piist ein doubleTyp.

Referenz: https://en.cppreference.com/w/cpp/numeric/constants

Bathseba
quelle
9
@ Lundin: Aber das kann constexprleider nicht sein , weshalb ich sage "Es mit einer Triggerfunktion zu definieren ist ein Schmerz"
Bathsheba
9
Warum spielt es eine Rolle? Pi ist eine Konstante, die keiner Änderung oder Implementierung entspricht. Schreiben Sie einfach den Wert (in einem const-Objekt, wenn Sie möchten) in die Anzahl der Stellen, die für double(oder eine lächerliche Zahl, wenn Sie sich für hypothetische, wirklich lange, lange Doppel interessieren) von Bedeutung sind.
R .. GitHub STOP HELPING ICE
10
@ R..Das Problem, das ich damit habe, ist das, was jetzt lächerlich erscheint und in ungefähr 20 Jahren vollkommen gesund werden kann. (Bill Gates '640k fällt mir ein). Ich vertraue darauf, dass Boost mit der Entwicklung der Architektur Schritt hält.
Bathseba
10
@KonradRudolph: Ein hochpräzises Pi ist wichtig, wenn eine Reduzierung der Reichweite implementiert wird. Zum Beispiel führt die interne Pi-Konstante von x86 / x87 (volle 64-Bit-Mantisse) zu einem Worst-Case-Fehler für kleine Eingaben in den fsinBefehl "ungefähr 1,37 Billionen Einheiten an letzter Stelle, wobei weniger als vier Bits korrekt bleiben" , und das ist es Noch schlimmer bei großen Eingaben, bei denen die Entfernungsreduzierung mehrmals auftritt. Dies ist etwas tangential zu den long doublein C ++ verwendeten Konstanten , aber trotzdem ordentlich.
Peter Cordes
31

Wie andere sagten, gibt es keine, std::piaber wenn Sie einen genauen PIWert wünschen, können Sie Folgendes verwenden:

constexpr double pi = std::acos(-1);

Dies setzt voraus, dass Ihre C ++ - Implementierung einen korrekt gerundeten Wert von PI aus erzeugt acos(-1.0), was üblich, aber nicht garantiert ist .

Dies ist nicht der constexprFall, aber in der Praxis wird die Optimierung von Compilern wie gcc und clang zur Kompilierungszeit ausgewertet. Es constist jedoch wichtig, dass der Optimierer gute Arbeit leistet.

0x476f72616e
quelle
2
Dies ist gefährlich, da die acos()Funktion eine unendliche Steigung bei hat x = -1. Folglich beruht diese Methode auf der acos()Implementierung, um den Fall eines genauen -1Arguments grundsätzlich explizit zu erfassen und die richtige Konstante direkt zurückzugeben. Verwenden Sie besser etwas, 4*atan(1)das mathematisch viel robuster ist (gut erzogene Steigung bei x = 1und Multiplikation mit 4 ist bei Gleitkomma-Mathematik immer präzise).
cmaster
1
Wir dürfen nicht std::acosin einem konstanten Ausdruck verwenden. clang meldet dies als Fehler. Bitte beachten Sie, dass dies eine nicht konforme Erweiterung ist und eventuell in gcc behoben werden sollte. Bitte beziehen Sie sich auf diese Antwort für weitere Details.
Badola
31

Bis C ++ 20 führt keiner der Standards die Konstante ein, die die Zahl pi (π) darstellen würde. Sie können die Zahl in Ihrem Code approximieren:

constexpr double pi = 3.14159265358979323846;

Bei anderen Sprachen wie C # ist die Konstante in ihren Bibliotheken deklariert.

Update: Ab C ++ 20 ist tatsächlich eine piKonstante im <numbers>Header deklariert . Der Zugriff erfolgt über : std::numbers::pi.

Ron
quelle
6
Möglicherweise möchten Sie inlinefür C ++ 17 + hinzufügen .
Deduplikator
8
Ta. Haben Sie eine positive Bewertung, aber beachten Sie, dass Ihre Definition bei Plattformen mit unterschiedlichen Definitionen von immer noch anfällig für Ungenauigkeiten ist double. C # hat es einfach, da der doubleTyp festgelegt ist. Wenn ich im C ++ - Standardkomitee wäre, würde ich so etwas vorschlagenstd::constants<double>::pi
Bathsheba
11
@Deduplicator ist constexpr nicht auch implizit inline ...?
Wann
4
@R. Fair genug, obwohl Sie std::numeric_limits<double>::is_iec559;in diesem Fall statisch behaupten sollten . Was ich gestehe, habe ich in meinem "Master-Header". Beachten Sie, dass Sie formal alle Gleitkommatypen separat prüfen müssen. Nur weil man IEEE754 ist, heißt das nicht, dass sie alle sind.
Bathseba
2
@ DanielSchepler Also, was soll diese "Zahl" sein? Ich wusste nicht, dass es doppelte Zahlen mit 16 Basen gibt.
BЈовић
29

M_PIwird durch "einen Standard" definiert, wenn nicht durch einen Sprachstandard : POSIX mit der Erweiterung X / Open System Interfaces (die sehr häufig unterstützt wird und für das offizielle UNIX-Branding erforderlich ist).

Es ist (noch) nicht sicher, was in C ++ 20 sein wird, aber da Sie gefragt haben: Es wird wahrscheinlich solche Konstanten haben . Das Papier wurde in der letzten Runde der C ++ 20-Funktionen zusammengeführt (für den Ausschussentwurf im August 2019).

Insbesondere gibt es sowohl eine std::numbers::pi(vom Typ double) als auch eine variable Vorlage, die Sie verwenden können, wenn Sie einen anderen Gleitkommatyp wünschen, z std::numbers::pi_v<float>. Die vollständige Liste der Konstanten finden Sie unter [numbers.syn] .

Davis Herring
quelle
Fühlen Sie sich frei, meine Bearbeitung nach Belieben neu zu formulieren - ich wollte hier nur die tatsächliche Schreibweise der neuen Konstanten für die Nachwelt hinzufügen.
Barry
12

Es ist offensichtlich keine gute Idee, da es keinen offensichtlichen Typ gibt, mit dem pi definiert wird, der für alle Domänen universell anwendbar ist.

Pi ist natürlich eine irrationale Zahl, daher kann es von keinem C ++ - Typ korrekt dargestellt werden . Sie könnten argumentieren, dass der natürliche Ansatz daher darin besteht, ihn im größten verfügbaren Gleitkommatyp zu definieren. Die Größe des größten Standard-Gleitkommatyps long doublewird jedoch nicht vom C ++ - Standard definiert, sodass der Wert der Konstante zwischen den Systemen variieren würde. Schlimmer noch, für jedes Programm, in dem der Arbeitstyp nicht dieser größte Typ war, wäre die Definition von pi unangemessen, da sie bei jeder Verwendung von pi Leistungskosten verursachen würde.

Es ist für jeden Programmierer auch trivial, den Wert von pi zu finden und eine eigene Konstante zu definieren, die für die Verwendung geeignet ist. Daher bietet es keinen großen Vorteil, ihn in die Mathe-Header aufzunehmen.

Jack Aidley
quelle
10
C ++ 14 gab uns variable Vorlagen. Ist es nicht das, wofür sie sind?
Amomum
21
Sprechen Sie wie ein echtes Komiteemitglied und sprechen Sie darüber, wie dies trotz klarer Wege nicht möglich ist. Siehe das überraschend relevante Beispiel für Variablenvorlagen . Ich denke nicht, dass Ihre Antwort schlecht ist, aber ich bin sicher, es würde Bjarne Stroustrups ewiger Depression über das Bedauern, die Kontrolle über die Zukunft von C ++ an ein sehr unentschlossenes Komitee übergeben zu können, nicht helfen.
Wann
4
@snb Ich stimme zu, dass das Erstellen pieiner polymorphen Konstante der klare Weg nach vorne ist - in einer Sprache mit Inferenz vom Typ Hindley-Milner. In Haskell hatten wir das schon immer pi :: Floating a => a, sodass pider Wert automatisch 3.1415927in einem FloatKontext, 3.141592653589793in einem DoubleKontext und πin einem symbolischen Berechnungskontext angezeigt wird. Aber möchten die Leute den Vorlagenparameter wirklich explizit instanziieren müssen? Scheint etwas umständlich, insbesondere wenn eine feste long doubleImplementierung in den meisten Anwendungen zu identischen Ergebnissen führen würde.
links um den
2
@leftaroundabout Ich glaube, das Schreiben auto a = pi<float>;ist völlig in Ordnung, sicherlich besser lesbar als berüchtigt4*atan(1)
Amomum
1
Ugh, ich habe das durch einen Fehlklick abgelehnt und jetzt kann ich es nicht mehr rückgängig machen. Es tut uns leid. Dies verdient eine +1 für eine ziemlich gute Erklärung der Argumentation des Ausschusses, warum sie nicht hinzugefügt wurde, auch wenn ich persönlich denke, dass die Argumentation aus den Gründen, auf die die Leute bereits hingewiesen haben, grundlegend fehlerhaft ist.
Fund Monica Klage
-1

Bearbeitet - Um den Begriff zu entfernen, der notwendig ist, weil er sich als kontrovers erwiesen hat. Es ist zu viel von einem absoluten Begriff.

C ++ ist eine große und komplexe Sprache. Aus diesem Grund enthält das Standards Committee nur Dinge, die dringend benötigt werden . So viel wie möglich bleibt nichtsprachlichen Standardbibliotheken wie Boost überlassen.
boost :: math :: constants

Tiger4Hire
quelle
29
Sicher, std::hermiteund std::cyl_bessel_iund std::coshund std::mersenne_twister_engineund std::ranlux48und std::cauchy_distributionund std::assoc_laguerreund std::betaalle waren absolut notwendig, wir alle benutzen sie jeden Tag!
Amomum
2
Ich bin mir ziemlich sicher, dass Sie nicht einmal das Komitee selbst dazu bringen konnten, die Idee zu unterzeichnen, dass alles, in dem sie abstimmen, "absolut notwendig" ist. Es geht nicht um Notwendigkeit, sondern darum, der Sprache einen Mehrwert zu verleihen - fast nichts in der Standardbibliothek ist erforderlich, um Programme zu schreiben, und im Übrigen kann der größte Teil der Kernsprache auch weggeworfen werden (wenn es Ihnen nichts ausmacht, in einer Sprache zu arbeiten) Turing Tarpit, das heißt). Der Wert der Aufnahme einer Konstante für pi kann diskutiert werden, aber die Idee, dass sie nicht vorhanden ist, weil sie einfach nicht notwendig ist, hält kein Wasser.
Jeroen Mostert
Beschwere dich nicht bei mir, ich zitiere nur das Normungskomitee. Es gab lange offene Diskussionen darüber, wie viel Boost im C ++ 11-Standard enthalten sein sollte. Der Grund, warum eine so kleine Teilmenge es geschafft hat, ist, dass sich die Compiler-Autoren darüber beschwert haben, wie viel Test involviert war. Wenn also etwas in den Standards enthalten ist, ist es vorhanden, weil jemand es für notwendig hielt, es zu standardisieren. Nur weil Sie nicht wissen warum, heißt das nicht, dass es keinen Grund gab.
Tiger4Hire
1
@ Tiger4Hire Ich bin sicher, es gibt Grund für alles, ich kann einfach nicht verstehen, warum die Konstante für pi nicht hinzugefügt wurde, als viele komplexere Dinge waren. Constant ist mit variablen Vorlagen einfach zu schreiben und erfordert keine großen Tests durch Compiler-Writer.
Amomum
@ Amomum: Ja, das Hinzufügen von pi scheint ein kleiner Aufwand für einen großen Gewinn zu sein. Ich persönlich würde es vorziehen, std :: network vor std :: math :: constants zu sehen.
Tiger4Hire