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?

367
demandé sur Yu Hao 2009-11-13 11:24:52

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:

  1. 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

  2. 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 */
    
435
répondu fritzone 2014-04-25 06:54:21

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

151
répondu Konamiman 2009-11-13 08:26:27

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.

102
répondu BuschnicK 2009-11-13 12:33:29

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();
53
répondu Henrik 2015-06-04 15:01:45

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;
48
répondu Alex 2014-01-19 05:40:48

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.

38
répondu Matthieu M. 2009-11-13 12:09:42

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.

36
répondu sellibitze 2009-11-13 08:37:38

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
28
répondu Joakim 2013-06-14 21:26:49

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.

24
répondu RichieHindle 2009-11-13 08:27:24

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.

11
répondu 0xbadf00d 2016-03-14 14:23:22

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.

8
répondu Sumudu Fernando 2009-11-18 04:03:41

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+
7
répondu ShitalShah 2017-02-13 15:16:58

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>
4
répondu Beta Jester 2018-01-27 01:50:09

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.

2
répondu Papa Smurf 2014-12-15 12:36:44

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

2
répondu Willy Goat 2016-03-21 20:09:45

, 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.

1
répondu Donald Duck 2016-11-09 11:53:14

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;
}
0
répondu Jeroen Lammertink 2018-07-31 08:49:13