Es gibt ein ziemlich dummes Problem mit der Zahl pi in C und C ++. Soweit ich weiß, ist die M_PI
Definition in math.h
keiner Norm erforderlich.
Neue C ++ - Standards führten eine Menge komplizierter Mathematik in die Standardbibliothek ein - hyperbolische Funktionen std::hermite
und std::cyl_bessel_i
verschiedene 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!
Antworten:
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
constexpr
Wert 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 Beispielstd::numbers::pi
ist eindouble
Typ.Referenz: https://en.cppreference.com/w/cpp/numeric/constants
quelle
constexpr
leider nicht sein , weshalb ich sage "Es mit einer Triggerfunktion zu definieren ist ein Schmerz"double
(oder eine lächerliche Zahl, wenn Sie sich für hypothetische, wirklich lange, lange Doppel interessieren) von Bedeutung sind.fsin
Befehl "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 denlong double
in C ++ verwendeten Konstanten , aber trotzdem ordentlich.Wie andere sagten, gibt es keine,
std::pi
aber wenn Sie einen genauenPI
Wert wünschen, können Sie Folgendes verwenden: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
constexpr
Fall, aber in der Praxis wird die Optimierung von Compilern wie gcc und clang zur Kompilierungszeit ausgewertet. Esconst
ist jedoch wichtig, dass der Optimierer gute Arbeit leistet.quelle
acos()
Funktion eine unendliche Steigung bei hatx = -1
. Folglich beruht diese Methode auf deracos()
Implementierung, um den Fall eines genauen-1
Arguments 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 beix = 1
und Multiplikation mit 4 ist bei Gleitkomma-Mathematik immer präzise).std::acos
in 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.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:
Bei anderen Sprachen wie C # ist die Konstante in ihren Bibliotheken deklariert.
Update: Ab C ++ 20 ist tatsächlich eine
pi
Konstante im<numbers>
Header deklariert . Der Zugriff erfolgt über :std::numbers::pi
.quelle
inline
für C ++ 17 + hinzufügen .double
. C # hat es einfach, da derdouble
Typ festgelegt ist. Wenn ich im C ++ - Standardkomitee wäre, würde ich so etwas vorschlagenstd::constants<double>::pi
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.M_PI
wird 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 Typdouble
) als auch eine variable Vorlage, die Sie verwenden können, wenn Sie einen anderen Gleitkommatyp wünschen, zstd::numbers::pi_v<float>
. Die vollständige Liste der Konstanten finden Sie unter [numbers.syn] .quelle
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 double
wird 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.
quelle
pi
einer polymorphen Konstante der klare Weg nach vorne ist - in einer Sprache mit Inferenz vom Typ Hindley-Milner. In Haskell hatten wir das schon immerpi :: Floating a => a
, sodasspi
der Wert automatisch3.1415927
in einemFloat
Kontext,3.141592653589793
in einemDouble
Kontext 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 festelong double
Implementierung in den meisten Anwendungen zu identischen Ergebnissen führen würde.auto a = pi<float>;
ist völlig in Ordnung, sicherlich besser lesbar als berüchtigt4*atan(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
quelle
std::hermite
undstd::cyl_bessel_i
undstd::cosh
undstd::mersenne_twister_engine
undstd::ranlux48
undstd::cauchy_distribution
undstd::assoc_laguerre
undstd::beta
alle waren absolut notwendig, wir alle benutzen sie jeden Tag!