Comment utiliser la constante PI en C++
Je veux utiliser la constante PI et les fonctions trigonométriques dans un programme C++. J'obtiens les fonctions trigonométriques avec include <math.h>
. Cependant, il ne semble pas y avoir de définition pour PI dans ce fichier d'en-tête.
Comment puis-je obtenir PI sans le définir manuellement?
17 réponses
Sur certaines plates-formes (en particulier les plus anciennes) (voir les commentaires ci-dessous), vous devrez peut-être
#define _USE_MATH_DEFINES
Et ensuite inclure le fichier d'en-tête nécessaire:
#include <math.h>
Et la valeur de pi est accessible via:
M_PI
Mon math.h
(2014) il est défini par:
# define M_PI 3.14159265358979323846 /* pi */
, Mais vérifiez votre math.h
pour plus d'. Un extrait du "vieux" math.h
(en 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.
*/
Cependant:
Sur les plates-formes plus récentes (au moins sur mon Ubuntu 64 bits 14.04), Je n'ai pas besoin de définir le
_USE_MATH_DEFINES
-
Sur les plates-formes Linux (récentes), il y a aussi des valeurs
long double
fournies en tant qu'Extension GNU:# define M_PIl 3.141592653589793238462643383279502884L /* pi */
Pi peut être calculé comme atan(1)*4
. Vous pouvez calculer la valeur de cette façon et la mettre en cache.
Vous pouvez également utiliser boost, qui définit des constantes mathématiques importantes avec une précision maximale pour le type demandé (c'est-à-dire float vs double).
const double pi = boost::math::constants::pi<double>();
Consultez la documentation boost pour plus d'exemples.
Obtenez-le de L'unité FPU sur puce à la place:
double get_PI()
{
double pi;
__asm
{
fldpi
fstp pi
}
return pi;
}
double PI = get_PI();
Je recommande simplement de taper pi à la précision dont vous avez besoin. Cela n'ajouterait aucun temps de calcul à votre exécution, et il serait portable sans utiliser d'en-têtes ou de #defines. Calculer acos ou atan est toujours plus cher que d'utiliser une valeur précalculée.
const double PI =3.141592653589793238463;
const float PI_F=3.14159265358979f;
Plutôt que d'écrire
#define _USE_MATH_DEFINES
Je recommande d'utiliser -D_USE_MATH_DEFINES
ou /D_USE_MATH_DEFINES
en fonction de votre compilateur.
De cette façon, vous êtes assuré que même si quelqu'un inclut l'en-tête avant de le faire (et sans le #define), vous aurez toujours les constantes au lieu d'une erreur de compilateur obscure que vous prendrez du temps à traquer.
Puisque la bibliothèque standard officielle ne définit pas un PI constant, vous devez le définir vous-même. Donc, la réponse à votre question " Comment puis-je obtenir PI sans le définir manuellement?"est" vous ne le faites pas-ou vous comptez sur certaines extensions spécifiques au compilateur.". Si vous n'êtes pas préoccupé par la portabilité, vous pouvez vérifier le manuel de votre compilateur pour cela.
C++ vous permet d'écrire
const double PI = std::atan(1.0)*4;
Mais l'initialisation de cette constante n'est pas garantie pour être statique. Le compilateur g++ cependant, gère ces fonctions mathématiques en tant qu'intrinsèques et est capable de calculer cette expression constante au moment de la compilation.
De la page de manuel Posix de math.h :
The <math.h> 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
Le C++ Standard n'a pas de constante pour PI.
De nombreux compilateurs C++ définissent M_PI
dans cmath
(ou dans math.h
pour C) comme une extension non standard. Vous devrez peut-être #define _USE_MATH_DEFINES
avant de pouvoir le voir.
Je ferais
template<typename T>
T const pi = std::acos(-T(1));
Ou
template<typename T>
T const pi = std::arg(-std::log(T(2)));
Je voudrais pas en tapant dans π pour la précision dont vous avez besoin. Quelle est cette même censé signifier? La précision dont vous avez besoin est la précision de T
, mais nous ne savons rien de T
.
, Vous pourriez dire: de Quoi tu parles? T
sera float
, double
ou long double
. Donc, tapez simplement la précision de long double
, c'est-à-dire
template<typename T>
T const pi = static_cast<T>(/* long double precision π */);
Mais savez-vous vraiment qu'il n'y aura pas de nouveau flottant type de point dans la norme à l'avenir avec une précision encore plus élevée que long double
? Vous ne le faites pas.
Et c'est pourquoi la première solution est beau. Vous pouvez être sûr que la norme surchargerait les fonctions trigonométriques pour un nouveau type.
Et ne dites pas que l'évaluation d'une fonction trigonométrique à l'initialisation est une pénalité de performance.
Je préfère généralement définir le mien: const double PI = 2*acos(0.0);
car toutes les implémentations ne le fournissent pas pour vous.
La question de savoir si cette fonction est appelée à l'exécution ou si elle est statique au moment de la compilation n'est généralement pas un problème, car elle n'arrive qu'une seule fois de toute façon.
J'utilise suivant dans un de mes en-têtes communs dans le projet qui couvre toutes les bases:
#define _USE_MATH_DEFINES
#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
#ifndef M_PIl
#define M_PIl (3.14159265358979323846264338327950288)
#endif
Sur une note de côté, tous les compilateurs ci-dessous définissent les constantes M_PI et M_PIl si vous incluez <cmath>
. Il n'est pas nécessaire d'ajouter ' # define _USE_MATH_DEFINES qui n'est requis que pour VC++.
x86 GCC 4.4+
ARM GCC 4.5+
x86 Clang 3.0+
Je viens de tomber sur Cet article par Danny Kalev qui a un bon conseil pour C++14 et plus.
template<typename T>
constexpr T pi = T(3.1415926535897932385);
Je pensais que c'était assez cool (bien que j'utiliserais la plus haute précision PI là-dedans), surtout parce que les modèles peuvent l'utiliser en fonction du type.
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>
Sous windows (cygwin + g++), j'ai trouvé nécessaire d'ajouter le drapeau -D_XOPEN_SOURCE=500
pour que le préprocesseur traite la définition de M_PI
dans math.h
.
C++14 vous permet de faire static constexpr auto pi = acos(-1);
, Vous pouvez faire ceci:
#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
Si M_PI
est déjà défini dans cmath
, cela ne fera rien d'autre que d'inclure cmath
. Si M_PI
n'est pas défini (ce qui est le cas par exemple dans Visual Studio), il le définira. Dans les deux cas, vous pouvez utiliser M_PI
pour obtenir la valeur de pi.
Cette valeur de pi provient du qmath de Qt Creator.h.
Les valeurs comme M_PI, M_PI_2, m_pi_4, etc ne sont pas standard C++ donc un constexpr semble une meilleure solution. Différentes expressions const peuvent être formulées qui calculent le même pi et cela me préoccupe de savoir si elles (toutes) me fournissent toute la précision. La norme C++ ne mentionne pas explicitement comment calculer pi. Par conséquent, j'ai tendance à revenir à la définition manuelle de pi. Je voudrais partager la solution ci-dessous qui prend en charge toutes sortes de fractions de pi en toute précision.
#include <ratio>
#include <iostream>
template<typename RATIO>
constexpr double dpipart()
{
long double const pi = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899863;
return static_cast<double>(pi * RATIO::num / RATIO::den);
}
int main()
{
std::cout << dpipart<std::ratio<-1, 6>>() << std::endl;
}