Come usare la costante PI in C ++

Voglio usare la costante PI e le funzioni trigonometriche in qualche programma C ++. Ottengo le funzioni trigonometriche con include . Tuttavia, non sembra esserci una definizione per PI in questo file di intestazione.

Come posso ottenere PI senza definirlo manualmente?

Su alcune piattaforms (specialmente più vecchie) (vedi i commenti sotto) potrebbe essere necessario

 #define _USE_MATH_DEFINES 

e quindi includere il file di intestazione necessario:

 #include  

e il valore di pi è accessibile tramite:

 M_PI 

In math.h (2014) è definito come:

 # define M_PI 3.14159265358979323846 /* pi */ 

ma controlla la tua math.h per ulteriori informazioni. Un estratto dal “vecchio” math.h (nel 2009):

 /* Define _USE_MATH_DEFINES before including math.h to expose these macro * definitions for common math constants. These are placed under an #ifdef * since these commonly-defined names are not part of the C/C++ standards. */ 

Però:

  1. su piattaforms più recenti (almeno sulla mia 64 bit Ubuntu 14.04) non ho bisogno di definire il _USE_MATH_DEFINES

  2. Sulle (recenti) piattaforms Linux ci sono long double valori forniti come estensione GNU:

     # define M_PIl 3.141592653589793238462643383279502884L /* pi */ 

Pi può essere calcolato come atan(1)*4 . È ansible calcolare il valore in questo modo e memorizzarlo nella cache.

È anche ansible utilizzare boost, che definisce importanti costanti matematiche con la massima precisione per il tipo richiesto (ad esempio float vs double).

 const double pi = boost::math::constants::pi(); 

Controlla la documentazione di boost per ulteriori esempi.

Prendilo invece dall’unità FPU su chip:

 double get_PI() { double pi; __asm { fldpi fstp pi } return pi; } double PI = get_PI(); 

Consiglierei solo digitando in pi la precisione di cui hai bisogno. Ciò non aggiungerebbe tempo di calcolo alla tua esecuzione, e sarebbe portatile senza usare intestazioni o #define. Il calcolo di aco o atan è sempre più costoso rispetto all’utilizzo di un valore precalcolato.

 const double PI =3.141592653589793238463; const float PI_F=3.14159265358979f; 

Piuttosto che scrivere

 #define _USE_MATH_DEFINES 

Ti consiglio di utilizzare -D_USE_MATH_DEFINES o /D_USE_MATH_DEFINES seconda del compilatore.

In questo modo ti assicuri che anche nel caso in cui qualcuno includa l’intestazione prima di te (e senza #define), avrai comunque le costanti invece di un oscuro errore del compilatore che impiegheresti anni a rintracciare.

Dal momento che la libreria standard ufficiale non definisce un PI costante, dovresti definirlo tu stesso. Quindi la risposta alla tua domanda “Come posso ottenere PI senza definirlo manualmente?” è “Non lo fai – o ti affidi ad alcune estensioni specifiche del compilatore”. Se non sei preoccupato per la portabilità puoi controllare il manuale del compilatore per questo.

C ++ ti permette di scrivere

 const double PI = std::atan(1.0)*4; 

ma l’inizializzazione di questa costante non è garantita per essere statica. Il compilatore G ++ tuttavia gestisce le funzioni matematiche come intrinseche ed è in grado di calcolare questa espressione costante in fase di compilazione.

Dalla pagina man di Posix di math.h :

  The  header shall provide for the following constants. The values are of type double and are accurate within the precision of the double type. M_PI Value of pi M_PI_2 Value of pi/2 M_PI_4 Value of pi/4 M_1_PI Value of 1/pi M_2_PI Value of 2/pi M_2_SQRTPI Value of 2/ sqrt pi 

Il C ++ standard non ha una costante per PI.

Molti compilatori C ++ definiscono M_PI in cmath (o in math.h per C) come un’estensione non standard. Potresti dover #define _USE_MATH_DEFINES prima che tu possa vederlo.

farei

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

o

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

Non scriverei in π alla precisione che ti serve . Cosa dovrebbe significare? La precisione di cui hai bisogno è la precisione di T , ma non sappiamo nulla di T

Potresti dire: di cosa stai parlando? T sarà float , double o long double . Quindi, basta digitare la precisione del long double , vale a dire

 template T const pi = static_cast(/* long double precision π */); 

Ma sai davvero che non ci sarà un nuovo tipo di virgola mobile nello standard in futuro con una precisione ancora maggiore del long double ? Non lo fai.

Ed è per questo che la prima soluzione è bella. Puoi essere sicuro che lo standard sovraccaricherebbe le funzioni trigonometriche per un nuovo tipo.

E per favore, non dire che la valutazione di una funzione trigonometrica all’inizializzazione è una penalizzazione delle prestazioni.

Generalmente preferisco definire il mio: const double PI = 2*acos(0.0); perché non tutte le implementazioni lo forniscono per te.

La questione se questa funzione viene richiamata in fase di runtime o che è statica al momento della compilazione di solito non è un problema, perché si verifica solo una volta.

Uso il seguente in uno dei miei header comuni nel progetto che copre tutte le basi:

 #define _USE_MATH_DEFINES #include  #ifndef M_PI #define M_PI (3.14159265358979323846) #endif #ifndef M_PIl #define M_PIl (3.14159265358979323846264338327950288) #endif 

In una nota a margine, tutti i compilatori sottostanti definiscono le costanti M_PI e M_PIl se si include . Non è necessario aggiungere `#define _USE_MATH_DEFINES che è richiesto solo per VC ++.

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

Ho appena trovato questo articolo di Danny Kalev che ha un ottimo consiglio per C ++ 14 e versioni successive.

 template constexpr T pi = T(3.1415926535897932385); 

Ho pensato che fosse abbastanza bello (anche se avrei potuto usare il PI di più alta precisione ansible), soprattutto perché i modelli possono usarlo in base al tipo.

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

Su windows (cygwin + g ++), ho trovato necessario aggiungere il flag -D_XOPEN_SOURCE=500 per il preprocessore per elaborare la definizione di M_PI in M_PI

C ++ 14 ti permette di fare static constexpr auto pi = acos(-1);

Puoi farlo:

 #include  #ifndef M_PI #define M_PI (3.14159265358979323846) #endif 

Se M_PI è già definito in cmath , questo non farà altro che includere cmath . Se M_PI non è definito (come ad esempio in Visual Studio), lo definirà. In entrambi i casi, è ansible utilizzare M_PI per ottenere il valore di pi.

Questo valore di pi deriva da qmath.h di Qt Creator.

Valori come M_PI, M_PI_2, M_PI_4, ecc. Non sono C ++ standard, quindi un constexpr sembra una soluzione migliore. Si possono formulare diverse espressioni const che calcolano lo stesso pi e mi riguarda se (tutto) mi forniscono la massima accuratezza. Lo standard C ++ non menziona esplicitamente come calcolare il pi. Pertanto, tendo a tornare a definire manualmente il pi. Mi piacerebbe condividere la soluzione qui sotto che supporta tutti i tipi di frazioni di pi in piena precisione.

 #include  #include  template constexpr double dpipart() { long double const pi = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899863; return static_cast(pi * RATIO::num / RATIO::den); } int main() { std::cout << dpipart>() << std::endl; }