557

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

如何在不手动定义的情况下获得 PI?

4

25 回答 25

625

在某些(尤其是较旧的)平台上(请参阅下面的评论),您可能需要

#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. 在较新的平台上(至少在我的 64 位 Ubuntu 14.04 上)我不需要定义_USE_MATH_DEFINES

  2. 在(最近的)Linux 平台上,也有一些long double值作为 GNU 扩展提供:

    # define M_PIl          3.141592653589793238462643383279502884L /* pi */
    
于 2009-11-13T08:28:16.277 回答
186

Pi 可以计算为atan(1)*4。您可以通过这种方式计算值并将其缓存。

于 2009-11-13T08:26:27.617 回答
119

您还可以使用 boost,它为请求的类型(即 float 与 double)定义了具有最大准确性的重要数学常量。

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

查看boost 文档以获取更多示例。

于 2009-11-13T12:33:29.547 回答
109

而是从芯片上的 FPU 单元获取它:

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

double PI = get_PI();
于 2015-06-04T15:01:45.407 回答
107

C++20std::numbers::pi

终于到了:http ://eel.is/c++draft/numbers

主文件

#include <numbers> // std::numbers
#include <iomanip>
#include <iostream>

int main() {
    std::cout << std::fixed << std::setprecision(20);
    std::cout << "float       " << std::numbers::pi_v<float> << std::endl;
    std::cout << "double      " << std::numbers::pi << std::endl;
    std::cout << "long double " << std::numbers::pi_v<long double> << std::endl;
    std::cout << "exact       " << "3.141592653589793238462643383279502884197169399375105820974944" << std::endl;
}

确切的结果计算如下:

echo "scale=60; 4*a(1)" | BC_LINE_LENGTH=0 bc -l

根据:如何使用 Bash 命令计算 pi

编译并运行:

g++-10 -ggdb3 -O0 -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

输出:

float       3.14159274101257324219
double      3.14159265358979311600
long double 3.14159265358979323851
exact       3.141592653589793238462643383279502884197169399375105820974944

在 Ubuntu 20.04 amd64、GCC 10.2.0 上测试

接受的提案描述:

5.0。“Headers” [headers] 在表 [tab:cpp.library.headers] 中,<math>需要添加一个新的 header。

[...]

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

当然还有一个std::numbers::e:-)如何计算欧拉常数或用 C++ 驱动的欧拉?

这些常量使用 C++14 变量模板功能:C++14 变量模板:它们的用途是什么?有使用示例吗?

在草案的早期版本中,常量位于std::math::pihttp ://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0631r7.pdf

于 2019-07-31T07:26:55.723 回答
52

而不是写

#define _USE_MATH_DEFINES

我建议使用-D_USE_MATH_DEFINES/D_USE_MATH_DEFINES取决于您的编译器。

这样您就可以放心,即使有人在您之前包含标头(并且没有#define),您仍然会拥有常量而不是一个晦涩的编译器错误,您需要很长时间才能找到它。

于 2009-11-13T12:09:42.643 回答
52

我建议您只输入 pi 到您需要的精度。这不会为您的执行增加计算时间,并且无需使用任何标题或#defines 即可移植。计算 acos 或 atan 总是比使用预先计算的值更昂贵。

const double PI  =3.141592653589793238463;
const float  PI_F=3.14159265358979f;
于 2011-11-12T20:51:02.920 回答
41

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

C++ 允许您编写

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

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

于 2009-11-13T08:37:38.200 回答
34

来自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
于 2013-03-12T11:35:05.083 回答
27

标准 C++ 没有 PI 常量。

许多 C++ 编译器将M_PIin cmath(或math.h用于 C)定义为非标准扩展。您可能必须#define _USE_MATH_DEFINES先看到它。

于 2009-11-13T08:27:24.283 回答
20

我会做

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

或者

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

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

你可能会说:你在说什么?Tfloatdoublelong double。因此,只需输入 的精度long double,即

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

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

这就是为什么第一个解决方案很漂亮。您可以确定该标准会为新类型重载三角函数。

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

于 2016-02-26T12:25:28.240 回答
13

我在涵盖所有基础的项目中的一个常见标题中使用了以下内容:

#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>. 无需添加 `#define _USE_MATH_DEFINES,这仅在 VC++ 中需要。

x86 GCC 4.4+
ARM GCC 4.5+
x86 Clang 3.0+
于 2016-05-28T11:42:10.693 回答
8

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

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

于 2009-11-18T04:03:41.310 回答
7

我刚刚看到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>
于 2018-01-27T01:12:52.277 回答
5

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

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

对于任何未来的 long long long double 类型,256 个十进制数字的精度应该足够了。如果需要更多,请访问https://www.piday.org/million/

于 2019-05-18T08:59:07.867 回答
4

M_PI、M_PI_2、M_PI_4 等值不是标准 C++,因此 constexpr 似乎是更好的解决方案。可以制定不同的 const 表达式来计算相同的 pi,我关心的是它们(全部)是否为我提供了完整的准确性。C++ 标准没有明确提到如何计算 pi。因此,我倾向于回退到手动定义 pi。我想分享下面的解决方案,它完全准确地支持所有类型的 pi 分数。

#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;
}
于 2018-07-31T08:49:13.250 回答
4

在 C++20 标准库中,π 被定义为std::numbers::pi_vfor float, doubleand long double,例如

#include <numbers>
auto n = std::numbers::pi_v<float>;

并且可能专门用于用户定义的类型。

于 2021-04-05T08:40:22.810 回答
2

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

于 2014-12-15T12:11:26.487 回答
2
#include <cmath>
const long double pi = acos(-1.L);
于 2020-05-21T20:31:42.993 回答
1

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

于 2016-03-21T20:09:45.893 回答
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。

于 2016-11-09T11:53:14.773 回答
1

你可以使用它:

#define _USE_MATH_DEFINES // for C++
#include <cmath>

#define _USE_MATH_DEFINES // for C
#include <math.h>

标准 C/C++ 中未定义数学常量。要使用它们,您必须先定义_USE_MATH_DEFINES然后包含cmathor math.h

于 2020-01-29T11:53:16.183 回答
0

自从大学(也许是高中)以来,我已经将 pi 记住了 11 位数字,所以这始终是我的首选方法:

#ifndef PI
#define PI 3.14159265359
#endif
于 2021-08-30T00:01:27.050 回答
0

小数点后 15 位让人类到达月球表面并返回。超出此范围的任何事情在规模上都是天文数字。实际上,您能否在较小的范围内进行测量?其他人花了几个月的时间计算到数万亿位数。除了进入记录簿之外,这没有用。

知道您可以将 pi 计算为任意长度,但 keep 是实用的。

于 2021-11-15T04:02:31.763 回答
0

我不喜欢#defines,因为它们是简单的文本替换,类型安全性为零。如果省略括号,它们也可能导致使用表达式出现问题,例如

#define T_PI 2*PI

真的应该

#define T_PI (2*PI)

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

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

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

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

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

于 2022-02-22T23:16:28.810 回答