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

发布于 2024-08-11 05:33:45 字数 130 浏览 4 评论 0原文

我想在一些 C++ 程序中使用 PI 常数和三角函数。我使用 include 获得三角函数。但是,这个头文件中似乎没有PI的定义。

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

I want to use the PI constant and trigonometric functions in some C++ program. I get the trigonometric functions with include <math.h>. However, there doesn't seem to be a definition for PI in this header file.

How can I get PI without defining it manually?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(25

故事还在继续 2024-08-18 05:33:45

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

#define _USE_MATH_DEFINES

然后包含必要的头文件:

#include <math.h>

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

M_PI

In my 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 */
    

On some (especially older) platforms (see the comments below) you might need to

#define _USE_MATH_DEFINES

and then include the necessary header file:

#include <math.h>

and the value of pi can be accessed via:

M_PI

In my math.h (2014) it is defined as:

# define M_PI           3.14159265358979323846  /* pi */

but check your math.h for more. An extract from the "old" math.h (in 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.
 */

However:

  1. on newer platforms (at least on my 64 bit Ubuntu 14.04) I do not need to define the _USE_MATH_DEFINES

  2. On (recent) Linux platforms there are long double values too provided as a GNU Extension:

    # define M_PIl          3.141592653589793238462643383279502884L /* pi */
    
ゝ偶尔ゞ 2024-08-18 05:33:45

C++20 std::numbers::pi

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

main.cpp

#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。 “标题”[标题]
在表 [tab:cpp.library.headers] 中,需要添加新的

标头。

[...]

命名空间 std {
命名空间数学{ 
 模板<类型名称 T>内联 constexpr T pi_v = 未指定;
   内联 constexpr double pi = pi_v;

当然还有一个 std::numbers::e :-) 如何在 C++ 中计算欧拉常数或欧拉幂?

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

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

C++20 std::numbers::pi

At last, it has arrived: http://eel.is/c++draft/numbers

main.cpp

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

where the exact result was calculated with:

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

as per: How can I calculate pi using Bash command

Compile and run:

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

Output:

float       3.14159274101257324219
double      3.14159265358979311600
long double 3.14159265358979323851
exact       3.141592653589793238462643383279502884197169399375105820974944

Tested on Ubuntu 20.04 amd64, GCC 10.2.0

The accepted proposal describes:

5.0. “Headers” [headers]
In the table [tab:cpp.library.headers], a new <math> header needs to be added.

[...]

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

There is also a std::numbers::e of course :-) How to calculate Euler constant or Euler powered in C++?

These constants use the C++14 variable template feature: C++14 Variable Templates: what is their purpose? Any usage example?

In earlier versions of the draft, the constant was under std::math::pi: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0631r7.pdf

混吃等死 2024-08-18 05:33:45

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

Pi can be calculated as atan(1)*4. You could calculate the value this way and cache it.

疯狂的代价 2024-08-18 05:33:45

相反,请从片上 FPU 单元获取它:

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

double PI = get_PI();

Get it from the FPU unit on chip instead:

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

double PI = get_PI();
悲欢浪云 2024-08-18 05:33:45

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

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

查看 boost 文档 了解更多示例。

You could also use boost, which defines important math constants with maximum accuracy for the requested type (i.e. float vs double).

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

Check out the boost documentation for more examples.

婴鹅 2024-08-18 05:33:45

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

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

I would recommend just typing in pi to the precision you need. This would add no calculation time to your execution, and it would be portable without using any headers or #defines. Calculating acos or atan is always more expensive than using a precalculated value.

const double PI  =3.141592653589793238463;
const float  PI_F=3.14159265358979f;
ㄖ落Θ余辉 2024-08-18 05:33:45

而不是编写,

#define _USE_MATH_DEFINES

我建议使用 -D_USE_MATH_DEFINES/D_US​​E_MATH_DEFINES

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

Rather than writing

#define _USE_MATH_DEFINES

I would recommend using -D_USE_MATH_DEFINES or /D_USE_MATH_DEFINES depending on your compiler.

This way you are assured that even in the event of someone including the header before you do (and without the #define) you will still have the constants instead of an obscure compiler error that you will take ages to track down.

看透却不说透 2024-08-18 05:33:45

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

C++ 允许您编写,

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

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

Since the official standard library doesn't define a constant PI you would have to define it yourself. So the answer to your question "How can I get PI without defining it manually?" is "You don't -- or you rely on some compiler-specific extensions.". If you're not concerned about portability you could check your compiler's manual for this.

C++ allows you to write

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

but the initialization of this constant is not guaranteed to be static. The G++ compiler however handles those math functions as intrinsics and is able to compute this constant expression at compile-time.

空城之時有危險 2024-08-18 05:33:45

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

From the Posix man page of 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
岁吢 2024-08-18 05:33:45

标准 C++ 没有 PI 常量。

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

Standard C++ doesn't have a constant for PI.

Many C++ compilers define M_PI in cmath (or in math.h for C) as a non-standard extension. You may have to #define _USE_MATH_DEFINES before you can see it.

葮薆情 2024-08-18 05:33:45

我会做

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

,或者

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

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

您可能会说:您在说什么? T 将为 floatdoublelong double。所以,只要输入long double的精度,即

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

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

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

并且请不要说初始化时对三角函数的求值是性能损失。

I would do

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

or

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

I would not typing in π to the precision you need. What is that even supposed to mean? The precision you need is the precision of T, but we know nothing about T.

You might say: What are you talking about? T will be float, double or long double. So, just type in the precision of long double, i.e.

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

But do you really know that there won't be a new floating point type in the standard in the future with an even higher precision than long double? You don't.

And that's why the first solution is beautiful. You can be quite sure that the standard would overload the trigonometric functions for a new type.

And please, don't say that the evaluation of a trigonometric function at initialization is a performance penalty.

迷爱 2024-08-18 05:33:45

我在项目中涵盖所有基础的公共标头之一中使用以下内容:

#define _USE_MATH_DEFINES
#include <cmath>

#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif

#ifndef M_PIl
#define M_PIl (3.14159265358979323846264338327950288)
#endif

顺便说一句,如果包含 ,则以下所有编译器都会定义 M_PI 和 M_PIl 常量。不需要添加`#define _USE_MATH_DEFINES,只有VC++才需要。

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

I use following in one of my common header in the project that covers all 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

On a side note, all of below compilers define M_PI and M_PIl constants if you include <cmath>. There is no need to add `#define _USE_MATH_DEFINES which is only required for VC++.

x86 GCC 4.4+
ARM GCC 4.5+
x86 Clang 3.0+
如若梦似彩虹 2024-08-18 05:33:45

在 C++20 标准库中,π 定义为 std::numbers: :pi_v 用于 floatdoublelong doubleeg

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

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

In the C++20 standard library, π is defined as std::numbers::pi_v for float, double and long double, e.g.

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

and may be specialized for user-defined types.

酒中人 2024-08-18 05:33:45

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

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

I generally prefer defining my own: const double PI = 2*acos(0.0); because not all implementations provide it for you.

The question of whether this function gets called at runtime or is static'ed out at compile time is usually not an issue, because it only happens once anyway.

触ぅ动初心 2024-08-18 05:33:45

我刚刚看到这篇文章,作者: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>

I just came across this article by Danny Kalev which has a great tip for C++14 and up.

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

I thought this was pretty cool (though I would use the highest precision PI in there I could), especially because templates can use it based on 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>
情归归情 2024-08-18 05:33:45

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

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

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

Some elegant solutions. I am doubtful that the precision of the trigonometric functions is equal to the precision of the types though. For those that prefer to write a constant value, this works for g++ :-

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

256 decimal digit accuracy should be enough for any future long long long double type. If more are required visit https://www.piday.org/million/.

看海 2024-08-18 05:33:45

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

Values like M_PI, M_PI_2, M_PI_4, etc are not standard C++ so a constexpr seems a better solution. Different const expressions can be formulated that calculate the same pi and it concerns me whether they (all) provide me the full accuracy. The C++ standard does not explicitly mention how to calculate pi. Therefore, I tend to fall back to defining pi manually. I would like to share the solution below which supports all kind of fractions of pi in full accuracy.

#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;
}
谜泪 2024-08-18 05:33:45

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

On windows (cygwin + g++), I've found it necessary to add the flag -D_XOPEN_SOURCE=500 for the preprocessor to process the definition of M_PI in math.h.

爱她像谁 2024-08-18 05:33:45

您可以这样做:

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

You can do this:

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

If M_PI is already defined in cmath, this won't do anything else than include cmath. If M_PI isn't defined (which is the case for example in Visual Studio), it will define it. In both cases, you can use M_PI to get the value of pi.

This value of pi comes from Qt Creator's qmath.h.

神经暖 2024-08-18 05:33:45

您可以使用它:

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

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

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

You can use that:

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

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

Math Constants are not defined in Standard C/C++. To use them, you must first define _USE_MATH_DEFINES and then include cmath or math.h.

攀登最高峰 2024-08-18 05:33:45
#include <cmath>
const long double pi = acos(-1.L);
#include <cmath>
const long double pi = acos(-1.L);
够运 2024-08-18 05:33:45

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

#ifndef PI
#define PI 3.14159265359
#endif

I've memorized pi to 11 digits since college (maybe high school), so this is always my preferred approach:

#ifndef PI
#define PI 3.14159265359
#endif
葬花如无物 2024-08-18 05:33:45

我不喜欢#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++ 不支持),并且 trig 函数是 constexpr 的 C++ 等效项。
例如,

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

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

I don't like #defines since they are simple textual substitutions with zero type safety. They can also cause problems using expressions if brackets are omitted e.g.

#define T_PI 2*PI

should really be

#define T_PI (2*PI)

My current solution to this problem is to use hard-coded values for constants, e.g. in my_constants.hxx

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

However I do not hard-code the values (since I don't like that approach either), instead I use a separate Fortran program to write this file. I use Fortran because it fully supports quad precision (C++ on VisualStudio doesn't) and trig functions are the C++ equivalent of constexpr.
E.g.

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

No doubt other languages can be used to do the same thing.

触ぅ动初心 2024-08-18 05:33:45

C++14 允许您执行static constexpr auto pi = acos(-1);

C++14 lets you do static constexpr auto pi = acos(-1);

淡看悲欢离合 2024-08-18 05:33:45

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

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

15 decimal places got man to the lunar surface and back. Anything beyond this is astronomical in scale. Would you be able to measure this, practically, on a smaller scale? Others have spent months calculating to trillions of digits. This isn't useful beyond getting into the record books.

Know that you can calculate pi to an arbitrary length, but keep is practical.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文