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

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


当前回答

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

#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)

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

其他回答

M_PI, M_PI_2, M_PI_4等值不是标准的c++,因此constexpr似乎是更好的解决方案。不同的const表达式可以计算相同的pi,它关心我是否他们(所有)提供了完整的精度。c++标准没有明确提到如何计算圆周率。因此,我倾向于手动定义圆周率。我想分享下面的解决方案,它支持圆周率的所有分数的完全准确。

#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;
}

我刚刚看到了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>

我在项目中使用了一个覆盖所有基础的公共头文件:

#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_definitions。

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

我会这么做

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精度更高的新的浮点类型吗?你不。

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

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

因为官方标准库没有定义常数PI,你必须自己定义它。因此,对于你的问题“如何获得PI而不手动定义它?”的答案是“你没有——或者你依赖于一些特定于编译器的扩展。”如果你不关心可移植性,你可以查看编译器手册。

c++允许你编写

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

但是这个常数的初始化不能保证是静态的。然而,g++编译器将这些数学函数作为内在函数处理,并能够在编译时计算这个常量表达式。