如何在C ++中使用PI常量

我想在一些C ++程序中使用PI常量和三angular函数。 我用include <math.h>得到三angular函数。 但是,在这个头文件中似乎没有PI的定义。

如何获得PI而无需手动定义?

在一些(特别是较老的)平台上(见下面的评论),你可能需要

 #define _USE_MATH_DEFINES 

然后包含必要的头文件:

 #include <math.h> 

而pi的值可以通过以下方式访问:

 M_PI 

在我的math.h (2014)中,它被定义为:

 # define M_PI 3.14159265358979323846 /* pi */ 

但检查你的math.h更多。 “老” math.h (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. */ 

然而:

  1. 在较新的平台(至less在我的64位Ubuntu 14.04)我不需要定义_USE_MATH_DEFINES

  2. 在(近期的)Linux平台上,还有很long double值,作为GNU扩展提供:

     # define M_PIl 3.141592653589793238462643383279502884L /* pi */ 

Pi可以计算为atan(1)*4 。 你可以用这种方法计算出这个值并caching它。

你也可以使用boost,它为要求的types定义了最重要的math常量,即float和double。

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

查看更多示例的boost文档 。

我build议你只需要inputpi来达到你需要的精度。 这将不会增加执行的计算时间,而且可以在不使用任何头文件或#define的情况下进行移植。 计算acos或atan总是比使用预先计算的值更昂贵。

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

从芯片上的FPU单元取而代之:

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

而不是写作

 #define _USE_MATH_DEFINES 

我build议使用-D_USE_MATH_DEFINES/D_USE_MATH_DEFINES取决于你的编译器。

通过这种方式,您可以放心,即使是在包含头文件(包括头文件)的情况下(并且没有#define),您仍然可以使用这些常量,而不是一个难以理解的编译器错误,您将花费很长时间来追踪这些错误。

由于官方的标准库没有定义一个不变的PI,你必须自己定义它。 所以对于你的问题的答案是“我怎样才能得到PI而不需要手动定义呢?” 是“你不知道 – 或者你依赖于一些编译器特定的扩展”。 如果你不关心可移植性,你可以检查你的编译器手册。

C ++允许你写

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

但是这个常量的初始化不能保证是静态的。 G ++编译器将这些math函数作为内在函数处理,并且能够在编译时计算这个常量expression式。

从math.h的Posix手册页 :

  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 

标准C ++没有PI的常量。

许多C ++编译器在cmath (或在math.h为C)定义M_PI作为非标准扩展。 您可能必须#define _USE_MATH_DEFINES才能看到它。

我通常更喜欢定义我自己的: const double PI = 2*acos(0.0); 因为不是所有的实现都为你提供。

这个函数是在运行时被调用还是在编译时被静态的问题通常不是问题,因为它只发生一次。

我会做

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

要么

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

不会 inputπ来达到所需的精度 。 那甚至是什么意思呢? 你需要的精度是T的精度,但是我们对T一无所知。

你可能会说: 你在什么? T将是floatdoublelong double 所以,只要inputlong double的精度,即

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

但是你是否真的知道在未来的标准中将不会有一个新的浮点types,其精度要比long double更高? 你没有。

这就是为什么第一个解决scheme是美丽的。 你可以肯定的是,标准会超载三angular函数的一个新的types。

而且,请不要说在初始化时对三angular函数的评估是性能损失。

我在项目中的一个共同标题中使用了以下内容:

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

在附注中,如果包含<cmath> ,以下所有编译器将定义M_PI和M_PIl常量。 不需要添加只有VC ++需要的#define _USE_MATH_DEFINES。

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

在Windows(cygwin + g ++)上,我发现有必要为预处理器添加标志-D_XOPEN_SOURCE=500来处理math.hM_PI的定义。

C ++ 14可以让你做static constexpr auto pi = acos(-1);

你可以这样做:

 #include <cmath> #ifndef M_PI #define M_PI (3.14159265358979323846) #endif 

如果M_PI已经在cmath定义,那么除了包含cmath之外,这将不会做任何事情。 如果M_PI (例如在Visual Studio中就是这种情况),它将定义它。 在这两种情况下,都可以使用M_PI来获取pi的值。

pi的这个值来自Qt Creator的qmath.h。