如何在C++中使用PI常数
我想在一些 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(25)
在某些(尤其是较旧的)平台上(请参阅下面的评论),您可能需要
然后包含必要的头文件:
并且可以通过以下方式访问 pi 的值:
In my
math.h
(2014)它的定义是:但请检查您的 math.h 以了解更多信息。摘自“旧”
math.h
(2009 年):但是:
在较新的平台上(至少在我的 64 位 Ubuntu 14.04 上)我不需要定义
_USE_MATH_DEFINES
在(最近的)Linux 平台上有
long double
值也作为 GNU 扩展提供:On some (especially older) platforms (see the comments below) you might need to
and then include the necessary header file:
and the value of pi can be accessed via:
In my
math.h
(2014) it is defined as:but check your
math.h
for more. An extract from the "old"math.h
(in 2009):However:
on newer platforms (at least on my 64 bit Ubuntu 14.04) I do not need to define the
_USE_MATH_DEFINES
On (recent) Linux platforms there are
long double
values too provided as a GNU Extension:C++20
std::numbers::pi
终于来了:http://eel.is/c++draft/numbers
main.cpp
,其中精确结果的计算如下:
按照:如何使用 Bash 命令计算 pi
编译并运行:
输出:
在 Ubuntu 20.04 上测试amd64,GCC 10.2.0
已接受的提案描述:
当然还有一个
std::numbers::e
:-) 如何在 C++ 中计算欧拉常数或欧拉幂?这些常数使用 C++14 变量模板功能:C++14 变量模板:它们的用途是什么?有使用示例吗?
在草案的早期版本中,常量位于
std::math::pi
下:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0631r7.pdfC++20
std::numbers::pi
At last, it has arrived: http://eel.is/c++draft/numbers
main.cpp
where the exact result was calculated with:
as per: How can I calculate pi using Bash command
Compile and run:
Output:
Tested on Ubuntu 20.04 amd64, GCC 10.2.0
The accepted proposal describes:
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.pdfPi 的计算公式为
atan(1)*4
。您可以通过这种方式计算该值并将其缓存。Pi can be calculated as
atan(1)*4
. You could calculate the value this way and cache it.相反,请从片上 FPU 单元获取它:
Get it from the FPU unit on chip instead:
您还可以使用 boost,它为请求的类型(即 float 与 double)定义了具有最大精度的重要数学常量。
查看 boost 文档 了解更多示例。
You could also use boost, which defines important math constants with maximum accuracy for the requested type (i.e. float vs double).
Check out the boost documentation for more examples.
我建议只输入 pi 到您需要的精度。这不会增加执行的计算时间,并且无需使用任何标头或#defines即可移植。计算 acos 或 atan 总是比使用预先计算的值更昂贵。
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.
而不是编写,
我建议使用
-D_USE_MATH_DEFINES
或/D_USE_MATH_DEFINES
,具体取决于您的编译器。这样你就可以放心,即使有人在你之前包含了标头(并且没有#define),你仍然会得到常量,而不是一个需要很长时间才能找到的晦涩的编译器错误。
Rather than writing
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.
由于官方标准库没有定义常量 PI,因此您必须自己定义它。因此,您的问题“如何在不手动定义的情况下获取 PI?”的答案是“你不这样做——或者你依赖于一些特定于编译器的扩展。”。如果您不关心可移植性,您可以检查编译器手册。
C++ 允许您编写,
但不保证该常量的初始化是静态的。然而,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
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.
来自 math.h 的 Posix 手册页:
From the Posix man page of math.h:
标准 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
incmath
(or inmath.h
for C) as a non-standard extension. You may have to#define _USE_MATH_DEFINES
before you can see it.我会做
,或者
我会不按照您需要的精度输入 π。这到底是什么意思?您需要的精度是
T
的精度,但我们对T
一无所知。您可能会说:您在说什么?
T
将为float
、double
或long double
。所以,只要输入long double
的精度,即但是你真的知道未来标准中不会出现精度更高的新浮点类型吗比
long double
?你不知道。这就是为什么第一个解决方案很漂亮。您可以非常确定该标准将重载新类型的三角函数。
并且请不要说初始化时对三角函数的求值是性能损失。
I would do
or
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 aboutT
.You might say: What are you talking about?
T
will befloat
,double
orlong double
. So, just type in the precision oflong double
, i.e.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.
我在项目中涵盖所有基础的公共标头之一中使用以下内容:
顺便说一句,如果包含
,则以下所有编译器都会定义 M_PI 和 M_PIl 常量。不需要添加`#define _USE_MATH_DEFINES,只有VC++才需要。I use following in one of my common header in the project that covers all bases:
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++.在 C++20 标准库中,π 定义为
std::numbers: :pi_v
用于float
、double
和long double
、eg并且可能专门用于用户定义的类型。
In the C++20 standard library, π is defined as
std::numbers::pi_v
forfloat
,double
andlong double
, e.g.and may be specialized for user-defined types.
我通常更喜欢定义自己的:
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.
我刚刚看到这篇文章,作者:Danny Kalev 对于 C++14 及更高版本有很好的提示。
我认为这非常酷(尽管我会在那里使用最高精度的 PI),特别是因为模板可以根据类型使用它。
I just came across this article by Danny Kalev which has a great tip for C++14 and up.
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.
一些优雅的解决方案。我怀疑三角函数的精度是否等于类型的精度。对于那些喜欢编写常量值的人来说,这适用于 g++ :-
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++ :-
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/.
M_PI、M_PI_2、M_PI_4 等值不是标准 C++,因此 constexpr 似乎是更好的解决方案。可以制定不同的 const 表达式来计算相同的 pi,这关系到我是否它们(全部)为我提供了完整的准确性。 C++ 标准没有明确提及如何计算 pi。因此,我倾向于手动定义 pi。我想分享下面的解决方案,它完全准确地支持 pi 的所有分数。
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.
在 Windows (cygwin + g++) 上,我发现有必要为预处理器添加标志
-D_XOPEN_SOURCE=500
来处理math 中
。M_PI
的定义.hOn windows (cygwin + g++), I've found it necessary to add the flag
-D_XOPEN_SOURCE=500
for the preprocessor to process the definition ofM_PI
inmath.h
.您可以这样做:
如果
M_PI
已在cmath
中定义,则除了包含cmath
之外,不会执行任何其他操作。如果M_PI
未定义(例如在 Visual Studio 中就是这种情况),它将定义它。在这两种情况下,您都可以使用M_PI
来获取 pi 的值。pi的这个值来自Qt Creator的qmath.h。
You can do this:
If
M_PI
is already defined incmath
, this won't do anything else than includecmath
. IfM_PI
isn't defined (which is the case for example in Visual Studio), it will define it. In both cases, you can useM_PI
to get the value of pi.This value of pi comes from Qt Creator's qmath.h.
您可以使用它:
标准 C/C++ 中未定义数学常量。要使用它们,您必须首先定义
_USE_MATH_DEFINES
,然后包含cmath
或math.h
。You can use that:
Math Constants are not defined in Standard C/C++. To use them, you must first define
_USE_MATH_DEFINES
and then includecmath
ormath.h
.从大学(也许是高中)开始,我就将 pi 记住了 11 位数字,所以这始终是我的首选方法:
I've memorized pi to 11 digits since college (maybe high school), so this is always my preferred approach:
我不喜欢#defines,因为它们是简单的文本替换,类型安全性为零。如果省略括号,它们也可能会导致使用表达式出现问题,例如
应该是
我当前对这个问题的解决方案是对常量使用硬编码值,例如在 my_constants.hxx 中
但是我不会对这些值进行硬编码(因为我不这样做)我也不喜欢这种方法),而是使用单独的 Fortran 程序来编写此文件。我使用 Fortran,因为它完全支持四精度(VisualStudio 上的 C++ 不支持),并且 trig 函数是 constexpr 的 C++ 等效项。
例如,
毫无疑问其他语言也可以用来做同样的事情。
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.
should really be
My current solution to this problem is to use hard-coded values for constants, e.g. in my_constants.hxx
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.
No doubt other languages can be used to do the same thing.
C++14 允许您执行
static constexpr auto pi = acos(-1);
C++14 lets you do
static constexpr auto pi = acos(-1);
小数点后 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.