我想在一些c++程序中使用PI常数和三角函数。我得到三角函数包含<math。h>。然而,在这个头文件中似乎没有PI的定义。

如何获得PI而不手动定义它?


当前回答

我刚刚看到了Danny Kalev写的一篇文章,它为c++ 14及以上版本提供了一个很好的建议。

template<typename T>
constexpr T pi = T(3.1415926535897932385);

我认为这非常酷(尽管我会在其中使用最高精度的PI),特别是因为模板可以基于类型使用它。

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>

其他回答

来自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

一些优雅的解决方案。不过,我怀疑三角函数的精度是否等于类型的精度。对于那些喜欢编写常量值的人来说,这适用于g++:-

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

256十进制数字的精度应该足以用于任何未来的长长长双精度类型。如果需要更多信息,请访问https://www.piday.org/million/。

我不喜欢#定义,因为它们是零类型安全的简单文本替换。如果省略括号,它们也会在使用表达式时引起问题。

#define T_PI 2*PI

真的应该

#define T_PI (2*PI)

我目前对这个问题的解决方案是使用常量的硬编码值,例如my_constants.hxx

namespace Constants {
    constexpr double PI = 3.141... ;
}

但是我没有硬编码这些值(因为我也不喜欢这种方法),而是使用一个单独的Fortran程序来编写这个文件。我使用Fortran是因为它完全支持四精度(VisualStudio上的c++不支持),三角函数是c++的constexpr等价函数。 如。

real(8), parameter :: pi = 4*atan(1.0d0)

毫无疑问,其他语言也可以用来做同样的事情。

在一些(特别是旧的)平台上(参见下面的评论),您可能需要这样做

#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.
 */

然而:

在更新的平台上(至少在我的64位Ubuntu 14.04上),我不需要定义_use_math_definitions 在(最近的)Linux平台上,GNU扩展也提供了长double值: #定义M_PIl 3.141592653589793238462643383279502884L /* pi */

我会这么做

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

or

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

我不会把π输入到你需要的精度。这到底是什么意思?你需要的精度是T的精度,但是我们对T一无所知。

你可能会说:What are You talking about?T是float, double或long double。因此,只需输入long double的精度,即。

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

但是你真的知道在未来的标准中不会有比long double精度更高的新的浮点类型吗?你不。

这就是为什么第一个解很漂亮。可以肯定的是,这个标准将会使三角函数过载而产生一种新的类型。

请不要说三角函数在初始化时的计算是性能损失。