当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何在C++中使用PI常量》经验,为你挑选了14个好方法。

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

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



1> Ferenc Deak..:

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

#define _USE_MATH_DEFINES

然后包含必要的头文件:

#include 

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_DEFINES

    在(最近的)Linux平台上,还有long double作为GNU扩展提供的值:

    # define M_PIl          3.141592653589793238462643383279502884L /* pi */
    


`#define _USE_MATH_DEFINES`后跟`#include `在visual c ++中定义`M_PI`.谢谢.
你总是可以包含`cmath`而不是`math.h`.
即使在定义了`_USE_MATH_DEFINES`之后,如果GCC抱怨是因为`__STRICT_ANSI__`被定义(也许你通过`-pedantic`或`-std = c ++ 11`),它不允许定义`M_PI`,因此用` - 取消定义它 - D__STRICT_ANSI__`.当你自己定义它时,因为它是C++,而不是宏,你应该`constexpr auto M_PI = 3.14159265358979323846;`.
也适用于cygwin标头.

2> Konamiman..:

Pi可以计算为atan(1)*4.你可以用这种方式计算值并缓存它.


对于c ++ 11用户:`constexpr double pi(){return std :: atan(1)*4; }`
请尝试`acos(-1)`,不需要`atan2`.
@matiu`atan`不是'constexpr`.
-1:仅当`atan(1)*4 == 3.141592653589793238462643383279502884`(粗略地说)时才有效.我不打赌它.正常并使用原始文字来定义常量.为什么在不需要时会失去精确度?
可以使用`atan2(0,-1);`来避免乘法运算.
在人们开始厌倦C++ 11之前,`const auto Pi = atan(1.0)*4.0;`是什么问题?新功能有它们的位置,但前提是它们可以改进已有的功能.
@ThomasEding - 我的`math.h`文件读取`#define M_PI 3.14159265358979323846`(如果是严格的ANSI).
@ThomasEding它真的应该.特别是acos(-1)应该给pi最接近的值,因为-1是acos的特例.有趣的事实:让M_PI = pi-delta,(即delta是舍入误差),然后库调用sin(M_PI)应返回delta,精度为double.即罪(M_PI)+ M_PI,两者恰当地使用合适的方法加在一起,应该给你带有100+有效位的pi - 如果'sin'正确完成的话.我用glibc尝试了这个并且它有效.
使用Visual Studio社区,我使用constexpr收到错误.
@Pharap几乎没有:唯一的区别是使用`constexpr`强制在编译时计算值,而旧`const`在程序初始化时执行.

3> BuschnicK..:

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

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

查看增强文档以获取更多示例.


提升:自1999年以来提升已经不必要的C++复杂性!
@DanMoulding:嗯.C是你知道的唯一其他语言吗?因为除了C之外,我所知道的所有其他语言都有一个比C++更大的标准库(例如Python,Haskell,C#,PHP,Delphi,Erlang,Java ......).从个人经验来看,精英主义者"不会使用libs" - 意见是一种害虫,可能是用C++编写的糟糕软件的首要原因.
Catchy和部分真实.另一方面,提升有时可以非常有用......
我相信他说*复杂性*不是*尺寸*.大概是指a)3个嵌套的命名空间,以及b)将pi定义为模板化函数而不仅仅是常规常量.
@Gracchus:是的.没有库(或没有新的C++ 11库)的C++,就像我喜欢那种语言一样,我想自己编写所有内容,而不是非常高效.
@phresnel非常认真,提升是c ++可以像php一样容易编写的唯一原因,它具有相当大的相对性能提升,更不用说它的子代:json-spirit和websocket ++.
为什么几乎每个C++问题都有一个提升答案?Boost应该是另一种语言,否则它会污染C++

4> 小智..:

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

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

double PI = get_PI();


:-)可能不是那个平台独立,但一个很好的额外的异国情调解决方案!
我喜欢你在开箱即用的方式;)

5> 小智..:

我建议只需输入pi即可获得所需的精度.这将不会为您的执行增加计算时间,并且它可以在不使用任何标头或#defines的情况下移植.计算acos或atan总是比使用预先计算的值更昂贵.

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


这是一个很好的例子,为什么我们不应该采用这种方法,我们人们会犯错误,四舍五入,复制和粘贴等等.我认为使用M_PI是正确的方法.
如果一个人在C++ 11中这样做,那就把`const`变为`constexpr`.
@ nacho4d我也更喜欢M_PI(如果有),但是并非所有系统都符合POSIX。对于无法使用M_PI的情况,我认为这种方法比4 * atan(1)方法更好。
"计算acos或atan总是更贵"并非如此.任何现代优化编译器都知道有关标准数学函数的所有信息并且可以通过它们进行常量传 参见例如https://goo.gl/BvdJyr
@Nemo,反例:https://godbolt.org/g/DsAern正如其他地方所说,目前只有GCC这样做,这很可能是因为它已将基本数学函数声明为“ constexpr”。

6> Matthieu M...:

而不是写作

#define _USE_MATH_DEFINES

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

通过这种方式,您可以确保即使在您执行之前包含标题的人(并且没有#define),您仍将拥有常量,而不是一个模糊的编译器错误,您需要花费很长时间才能跟踪.


实际上即使"你"是一个编译单元......根据标题的顺序是维护噩梦的最短途径......

7> sellibitze..:

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

C++允许你写

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

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


我通常使用acos(-1),正如你所说,它们是编译时评估的.当我测试M_PI,acos(-1)和atan(1)*4时,我得到了相同的值.

8> 小智..:

从math.h的Posix手册页:

   The    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



9> RichieHindle..:

标准C++没有PI的常量.

许多C++编译器定义M_PIcmath(或在math.h为C)作为非标准扩展.您可能必须#define _USE_MATH_DEFINES先看到它.



10> 0xbadf00d..:

我会做

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

要么

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

不会 输入π到你需要的精度.那甚至应该是什么意思?在你需要的精度是精度T,但我们并不知道T.

你可能会说:你在什么?T将是float,doublelong double.所以,只需键入精度long double,即

template
T const pi = static_cast(/* long double precision ? */);

但是你真的知道未来标准中不会有新的浮点类型,其精度甚至高于long double?你没有.

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

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



11> Ciro Santill..:

C ++ 20 std::numbers::pi

最后,它到达了:http : //eel.is/c++draft/numbers

我希望用法是这样的:

#include 
#include 

int main() {
    std::cout << std::numbers::pi << std::endl;
}

当GCC支持到达时,我会尝试一下,GCC 9.1.0 g++-9 -std=c++2a仍然不支持它。

接受的提案描述:

5.0。“标题” [headers]在表[tab:cpp.library.headers]中,需要添加新的标题。

[...]

namespace std {
namespace math { 
  template inline constexpr T pi_v = unspecified;
    inline 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



12> Sumudu Ferna..:

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

是否在运行时调用此函数或在编译时静态调出此函数的问题通常不是问题,因为它只会发生一次.


acos(-1)也是pi.
加载立即数操作数通常比从内存位置读取操作数更少的CPU指令和/或更少的延迟.此外,只能预编译在编译时已知的表达式(我的意思是`double x = pi*1.5;`等等).如果您打算在紧密循环中使用紧凑数学中的PI,则最好确保编译器知道该值.

13> Shital Shah..:

我在项目中的一个常见标题中使用了以下内容:

#define _USE_MATH_DEFINES
#include 

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



14> 小智..:

我刚刚看到Danny Kalev 撰写的这篇文章,它对C++ 14及以上版本提出了很好的建议.

template
constexpr T pi = T(3.1415926535897932385);

我觉得这很酷(虽然我会尽可能使用最高精度的PI),特别是因为模板可以根据类型使用它.

template
T circular_area(T r) {
  return pi * r * r;
}
double darea= circular_area(5.5);//uses pi
float farea= circular_area(5.5f);//uses pi

推荐阅读
手机用户2502852037
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有