643 Stimmen

Verwendung der PI-Konstante in C++

Ich möchte die PI-Konstante und trigonometrische Funktionen in einem C++-Programm verwenden. Ich erhalte die trigonometrischen Funktionen mit include <math.h> . Allerdings scheint es in dieser Header-Datei keine Definition für PI zu geben.

Wie kann ich PI bekommen, ohne es manuell zu definieren?

3 Stimmen

@tiwo, wollen Sie wissen, was der Unterschied ist zwischen 3.14 , 3.141592 et atan(1) * 4 ?

46 Stimmen

Nebenbei bemerkt: cmath sollte in C++ anstelle von math.h verwendet werden, die für C bestimmt ist.

5 Stimmen

In loser Verbindung: siehe cise.ufl.edu/~manuel/obfuscate/pi.c wie man den Wert von PI direkt aus der Definition berechnet.

21voto

0xbadf00d Punkte 15905

Ich würde tun

template<typename T>
T const pi = std::acos(-T(1));

o

template<typename T>
T const pi = std::arg(-std::log(T(2)));

Ich würde no Eingabe in der erforderlichen Genauigkeit . Was soll das überhaupt bedeuten? Die Präzision, die Sie brauchen ist die Genauigkeit von T , aber wir wissen nichts über T .

Man könnte sagen: Was soll das heißen? T wird float , double o long double . Geben Sie also einfach die Genauigkeit von long double d.h.

template<typename T>
T const pi = static_cast<T>(/* long double precision  */);

Aber wissen Sie wirklich, dass es in der Zukunft nicht einen neuen Gleitkommatyp in der Norm geben wird, der eine noch höhere Genauigkeit als long double ? Sie haben keine.

Und deshalb ist die erste Lösung so schön. Sie können ziemlich sicher sein, dass der Standard die trigonometrischen Funktionen für einen neuen Typ überladen würde.

Und bitte, sagen Sie nicht, dass die Auswertung einer trigonometrischen Funktion bei der Initialisierung eine Leistungseinbuße darstellt.

1 Stimmen

Beachten Sie, dass arg(log(x)) == für alle 0 < x < 1 .

2 Stimmen

Dies ist eine schreckliche Idee. Verwenden Sie eine pro Typ überladene Vorlage constexpr, auf diese Weise erhalten Sie einen Kompilierungsfehler, um Sie zu zwingen, es zu definieren, wenn ein neuer Typ erscheint. Es ist auch im Allgemeinen eine schreckliche, weil die trig-Typen sind nicht auf Fließkomma-Typen beschränkt. Genießen Sie also den atan(1)-Fehler... Der Standard garantiert nicht, dass trigonometrische Funktionen ihre tatsächlichen trigonometrischen Werte mit der Genauigkeit des Typs berechnen. Im Allgemeinen tun sie das nicht, und es wird noch schlimmer mit z.B. fastmath und ist immer besonders schlecht für die speziellen Werte.

14voto

Shital Shah Punkte 54846

Ich verwende das Folgende in einer meiner gemeinsamen Kopfzeilen in dem Projekt, das alle Grundlagen abdeckt:

#define _USE_MATH_DEFINES
#include <cmath>

#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif

#ifndef M_PIl
#define M_PIl (3.14159265358979323846264338327950288)
#endif

Nebenbei bemerkt, definieren alle unten aufgeführten Compiler M_PI und M_PIl Konstanten, wenn Sie <cmath> . Es besteht keine Notwendigkeit, `#define _USE_MATH_DEFINES hinzuzufügen, was nur für VC++ erforderlich ist.

x86 GCC 4.4+
ARM GCC 4.5+
x86 Clang 3.0+

0 Stimmen

Kann der Downvoter kommentieren, was an dieser Antwort falsch ist? Sie ist gut recherchiert und getestet und wird in einem realen System verwendet. Ich möchte sie auf jeden Fall verbessern, wenn etwas falsch ist.

1 Stimmen

Zu Ihrer Information: Borland C++ Compiler definieren auch M_PI ohne zu benötigen _USE_MATH_DEFINES

14voto

John McFarlane Punkte 4692

In der C++20-Standardbibliothek ist sie definiert als std::numbers::pi_v pour float , double y long double , z.B..

#include <numbers>
auto n = std::numbers::pi_v<float>;

und kann für benutzerdefinierte Typen spezialisiert werden.

8voto

Sumudu Fernando Punkte 1763

Ich ziehe es im Allgemeinen vor, meine eigene Definition zu finden: const double PI = 2*acos(0.0); weil nicht alle Implementierungen dies für Sie bereitstellen.

Die Frage, ob diese Funktion zur Laufzeit aufgerufen wird oder zur Kompilierzeit statisch ist, spielt in der Regel keine Rolle, da sie ohnehin nur einmal ausgeführt wird.

3 Stimmen

Das Laden eines unmittelbaren Operanden erfordert oft weniger CPU-Befehle und/oder eine geringere Latenzzeit als das Lesen eines Operanden aus einem Speicherplatz. Außerdem können nur Ausdrücke, die zur Kompilierzeit bekannt sind, vorberechnet werden (ich meine double x = pi * 1.5; und dergleichen). Wenn Sie PI jemals in knackiger Mathematik in engen Schleifen verwenden wollen, stellen Sie besser sicher, dass der Wert dem Compiler bekannt ist.

7voto

Beta Jester Punkte 79

Ich bin gerade auf dieser Artikel von Danny Kalev die einen guten Tipp für C++14 und höher enthält.

template<typename T>
constexpr T pi = T(3.1415926535897932385);

Ich dachte, dies war ziemlich cool (obwohl ich die höchste Präzision PI in dort könnte ich verwenden), vor allem, weil Vorlagen können es auf der Grundlage der Art verwenden.

template<typename T>
T circular_area(T r) {
  return pi<T> * r * r;
}
double darea= circular_area(5.5);//uses pi<double>
float farea= circular_area(5.5f);//uses pi<float>

1 Stimmen

3.1415926535897932385 ist eine double konstant. Die Genauigkeit geht bei der Umwandlung der Zahl in double und die Umwandlung dieser double à long double lässt den Wert unverändert, wobei die Genauigkeit verloren geht.

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