web-dev-qa-db-fra.com

Comment utiliser la constante PI en C ++

Je veux utiliser la constante PI et les fonctions trigonométriques dans certains programmes C++. Je reçois les fonctions trigonométriques avec include <math.h>. Cependant, il ne semble pas y avoir de définition de PI dans ce fichier d’en-tête.

Comment puis-je obtenir PI sans le définir manuellement?

418
Etan

Sur certaines plateformes (surtout les plus anciennes) (voir les commentaires ci-dessous), vous devrez peut-être:

#define _USE_MATH_DEFINES

puis incluez le fichier d'en-tête nécessaire:

#include <math.h>

et la valeur de pi est accessible via:

M_PI

Dans mon math.h (2014), il est défini comme:

# define M_PI           3.14159265358979323846  /* pi */

mais vérifiez votre math.h pour plus. Un extrait de "l'ancien" 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.
 */

Pourtant:

  1. sur les nouvelles plates-formes (au moins sur mon Ubuntu 14.04 64 bits), je n'ai pas besoin de définir le _USE_MATH_DEFINES

  2. Sur les plateformes Linux (récentes), il existe des valeurs long double également fournies en tant qu'extension GNU:

    # define M_PIl          3.141592653589793238462643383279502884L /* pi */
    
487
Ferenc Deak

Pi peut être calculé comme atan(1)*4. Vous pouvez calculer la valeur de cette façon et la mettre en cache.

163
Konamiman

Vous pouvez également utiliser boost, qui définit les 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 le documentation boost pour plus d'exemples.

107
BuschnicK

Obtenez-le à partir de l'unité FPU sur puce:

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

double PI = get_PI();
69
Henrik

Je recommanderais simplement de taper pi avec la précision dont vous avez besoin. Cela n’ajouterait aucun temps de calcul à votre exécution et serait portable sans utiliser d’en-têtes ou de #défines. Calculer un acos ou un atan est toujours plus coûteux que d’utiliser une valeur précalculée.

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

Plutôt que d'écrire

#define _USE_MATH_DEFINES

Je recommanderais 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 dans le cas où quelqu'un inclurait l'en-tête avant de le faire (et sans le #define), vous aurez toujours les constantes au lieu d'une erreur de compilation obscure qu'il vous faudra beaucoup de temps pour localiser.

44
Matthieu M.

Étant donné que 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 un PI sans le définir manuellement?" est "Vous ne le faites pas - ou vous utilisez des extensions spécifiques au compilateur". Si vous n'êtes pas préoccupé par la portabilité, vous pouvez consulter le manuel de votre compilateur à ce sujet.

C++ vous permet d'écrire

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

mais l'initialisation de cette constante n'est pas garantie statique. Cependant, le compilateur G ++ traite ces fonctions mathématiques comme des éléments intrinsèques et est capable de calculer cette expression constante au moment de la compilation.

39
sellibitze

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
29
Joakim

Le standard C++ 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.

26
RichieHindle

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 taper π à la précision dont vous avez besoin . Qu'est-ce que c'est censé vouloir dire? 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 parlez-vous? T sera float, double ou long double. Donc, il suffit de taper 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 plus de nouveau type à virgule flottante dans la norme avec une précision encore plus grande que long double? Vous pas.

Et c'est pourquoi la première solution est belle. Vous pouvez être certain que la norme surchargerait les fonctions trigonométriques pour un nouveau type.

Et s'il vous plaît, ne dites pas que l'évaluation d'une fonction trigonométrique à l'initialisation est une pénalité de performance.

14
0xbadf00d

J'utilise le suivant dans l'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

Notons que 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+
8
Shital Shah

Je préfère généralement définir mon propre: const double PI = 2*acos(0.0); parce que toutes les implémentations ne le fournissent pas pour vous.

La question de savoir si cette fonction est appelée à l'exécution ou est statique à la compilation n'est généralement pas un problème, car elle ne se produit qu'une fois de toute façon.

8
Sumudu Fernando

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 plutôt cool (même si j’aurais pu utiliser l’IP le plus précis possible), notamment 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>
6
Beta Jester

Des valeurs telles que M_PI, M_PI_2, M_PI_4, etc. ne sont pas du C++ standard. Un constexpr semble donc une meilleure solution. Différentes expressions constantes peuvent être formulées pour calculer le même pi et il est important de savoir si elles me fournissent toutes l'exactitude. La norme C++ ne mentionne pas explicitement comment calculer pi. Par conséquent, j'ai tendance à retomber manuellement sur la définition 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;
}
4
Jeroen Lammertink

C++ 20 std::numbers::pi

Enfin, il est arrivé: http://eel.is/c++draft/numbers

Je m'attends à ce que l'utilisation soit comme:

#include <numbers>
#include <iostream>

int main() {
    std::cout << std::numbers::pi << std::endl;
}

Je vais essayer quand le support arrive à GCC, GCC 9.1.0 avec g++-9 -std=c++2a ne le supporte toujours pas.

La proposition acceptée décrit:

5.0. “En-têtes” [en-têtes] Dans la table [onglet: cpp.library.headers], un nouvel en-tête <math> doit être ajouté.

[...]

namespace std {
namespace math { 
  template<typename T > inline constexpr T pi_v = unspecified;
    inline constexpr double pi = pi_v<double>;

Il y a aussi un std::numbers::e bien sûr :-) Comment calculer la constante d'Euler ou Euler alimenté en C++?

Ces constantes utilisent la fonctionnalité de modèle de variable C++ 14: Modèles de variable C++ 14: à quoi servent-ils? Un exemple d'utilisation?

Dans les versions précédentes du projet, la constante était sous std::math::pi: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0631r7.pdf =

Sur les fenêtres (cygwin + g ++), j'ai jugé nécessaire d'ajouter l'indicateur -D_XOPEN_SOURCE=500 pour que le préprocesseur puisse traiter la définition de M_PI dans math.h.

2
Papa Smurf

Tu peux le faire:

#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 de qmath.h de Qt Creator.

1
Donald Duck

C++ 14 vous permet de faire static constexpr auto pi = acos(-1);

1
Willy Goat

Quelques solutions élégantes. Je doute toutefois que la précision des fonctions trigonométriques soit égale à celle des types. Pour ceux qui préfèrent écrire une valeur constante, cela fonctionne pour g ++: -

template<class T>
class X {
public:
            static constexpr T PI = (T) 3.14159265358979323846264338327950288419\
71693993751058209749445923078164062862089986280348253421170679821480865132823066\
47093844609550582231725359408128481117450284102701938521105559644622948954930381\
964428810975665933446128475648233786783165271201909145648566923460;
...
}

Une précision de 256 décimales devrait suffire à tout type de double long futur long long. Si davantage sont nécessaires, rendez-vous sur https://www.piday.org/million/ .

0
Jon Guiton