C++ 11,14,17或20是否为pi引入了标准常量?

Amo*_*mum 161 c++ language-lawyer c++11 c++14 c++17

C和C++中的数字pi存在一个相当愚蠢的问题.据我知道M_PI的定义math.h是没有任何标准要求.

新的C++标准在标准库中引入了许多复杂的数学 - 双曲函数,std::hermite以及std::cyl_bessel_i不同的随机数生成器等等.

是否有任何"新"标准为pi带来了一个常数?如果没有 - 为什么?没有它,所有这些复杂的数学如何运作?

我知道关于C++中pi的类似问题(它们已经有几年了,而且标准已经很久了); 我想知道问题的当前状态.

我也非常感兴趣为什么 C++仍然没有pi常量,但有很多更复杂的数学.

UPD:我知道我可以将自己定义为4*atan(1)或acos(1)或double pi = 3.14.当然.但为什么在2018年我仍然必须这样做?没有pi,标准数学函数如何工作?

Bat*_*eba 94

不,pi仍然没有引入语言,这是一个痛苦的问题.

我很幸运,因为我使用了Boost(www.boost.org),他们定义的pi具有足够大的小数位数,即使是128位也是如此long double.

如果您不使用Boost,请自行进行硬编码.用三角函数定义它很有吸引力,但如果你这样做,你就不能把它变成一个constexpr.三角函数的精度也不会被我知道(任何标准保证的比照.std::sqrt),所以真正你在危险的地面确实依赖于这样的功能.

有一种方法可以使用元编程constexpr获得pi的值:请参阅http://timmurphy.org/2013/06/27/template-metaprogramming-in-c/

  • @Bathsheba但这实际上是相关的吗?据我所知,[~~40位数的pi足够精确,并且总是足够精确,任何计算都可以在整个宇宙范围内实现亚原子精度.](https://physics.stackexchange. COM /一个/147分之9631) (22认同)
  • @R ..我遇到的问题就是看起来很荒谬,现在可以在20年左右的时间内完全理智.(比尔盖茨的640k让人想到).我相信Boost能够跟上架构发展的步伐. (10认同)
  • @KonradRudolph:如果实现范围缩小,高精度*pi*很重要.例如,x86/x87的内部Pi常量(完整的64位尾数)导致[fsin]指令的小输入的最坏情况错误["最后一个地方大约1.37个数字单位,留下少于4位正确"](https://randomascii.wordpress.com/2014/10/09/intel-underestimates-error-bounds-by-1-3-quintillion/),对于大范围输入而言,范围缩小的情况更糟糕多次.这与C++中用于"long double"的常量有些相似,但无论如何都要整齐. (10认同)
  • @Lundin:不幸的是,这不可能是一个'constexpr`,这就是为什么我说"用trig函数定义它是一种痛苦" (9认同)
  • 为什么这有关系?Pi是一个常数,不受更改或任何特定于实现的限制.只需将值(在const对象中,如果你愿意的话)写出为"double"重要的位数(如果你关心假设的真正长的双打,那么就是一些荒谬的数字). (9认同)
  • @Bathsheba我不认为很多物理学(或*任何*,实际上)需要在子质子和宏观(宇宙)尺度上同时精确.换句话说,对于所有实际目的,已经夸大了(肯定地,写得不好)答案的动态范围.也就是说,我很乐意被告知. (5认同)
  • @KonradRudolph:你是绝对正确的,但C++以自己的通用语言而自豪,所以如果你需要不寻常的浮点精度,那么它应该能够提供它.很多物理学都陷入了困境,因为牛顿的G被认为是可悲的精确度. (3认同)
  • 如果标准库包含一组以2pi弧度为单位的三角函数测量角度,那么pi需要多少?虽然有一些涉及导数,积分和微分方程的目的,对于弧度是有用的,对于涉及实际角度的大多数目的,它们只是可以想象的最差单位. (3认同)
  • @supercat:它遍布整个地方.概率,金融数学,使用复数库的解决方案是一些应用程序.C++是一种通用语言,因此,恕我直言应该在其标准中使用pi. (3认同)
  • @Bathsheba:是的,我认为由于欧拉的相等性,弧度最终成为复数上某些运算的自然单位,但它仍然让我觉得没有任何与实际*角度一起使用的触发函数*.有一个图形"旋转"变换使用弧度,例如,打击我只是简单的愚蠢,因为可能不是角度将是pi/4的一些倍数,但旋转四次pi/4不会产生很大的影响原来的方向. (3认同)
  • @KonradRudolph - 确实是一个可怜的答案:大量的物理学发生在子质子尺度上.现在我的普朗克长度立方体论证成立,SO答案的质量明显优于fizzix网站上的质量. (2认同)
  • @supercat无论如何你应该使用四元数进行旋转. (2认同)
  • @KonradRudolph:PSQL算法使用了需要5000个十进制数字的函数和常数的数值计算,以推断出对理论物理的见解,并将多维积分的评估降低到编译时常数.请参阅David Bailey关于此的工作.Boost.math动态计算pi,除非它在预先计算的类型列表中; 这将是pi的任何C++标准值的要求. (2认同)
  • Boost中π的精度实际上处于一个有趣的情况:一方面我们有这个常数你引用,另一方面我们有[this](/sf/answers/2152875091/),这是到期的到[7岁的小虫](https://svn.boost.org/trac10/ticket/6893). (2认同)

Ron*_*Ron 31

不,没有一个标准引入代表数字pi(π)的常数.您可以在代码中估算数字:

constexpr double pi = 3.14159265358979323846;
Run Code Online (Sandbox Code Playgroud)

如C#等语言在自己的音乐库中声明的常数.C++没有.

  • @Deduplicator也不是constexpr隐式内联......? (10认同)
  • 助教.有一个upvote,但请注意,您的定义仍然容易受到具有不同"double"定义的平台的不精确性的影响.由于`double`类型是固定的,所以C#很容易.如果我在C++标准委员会,我会提出类似`std :: constants <double> :: pi`的东西 (7认同)
  • 你可能想为C++ 17 +添加`inline`. (6认同)
  • @R.很公平,虽然你应该在`std :: numeric_limits <double> :: is_iec559;`上静态断言.我承认,这就是我在"主标题"中所拥有的内容.请注意,您需要单独检查所有浮点类型.仅仅因为一个是IEEE754并不意味着它们都是. (3认同)
  • @DanielSchepler那么,"数字"应该是什么?我不知道有16个基数的双数. (2认同)

0x4*_*16e 29

正如其他人所说,没有,std::pi但如果你想要精确的PI价值,你可以使用:

constexpr double pi = std::acos(-1);
Run Code Online (Sandbox Code Playgroud)

这假设您的C++实现产生了一个正确舍入的PI值acos(-1.0),这是常见但不保证.

constexpr事实并非如此,但在实践中,优化编译器(如gcc和clang)会在编译时对其进行评估.然而,声明const对优化器做好工作很重要.

  • 这是危险的,因为“acos()”函数在“x = -1”处具有无限斜率。因此,此方法依赖于“acos()”实现来基本上显式捕获精确的“-1”参数的情况,并直接返回正确的常量。最好使用像“4*atan(1)”这样的东西,它在数学上更加稳健(“x = 1”处的斜率表现良好,并且使用浮点数学乘以 4 总是精确的)。 (3认同)
  • 我们不允许在常量表达式中使用“std::acos”。clang 将此报告为错误。请注意,这是一个**不合格的扩展**,最终应该在 gcc 中修复。请参阅此[答案](/sf/ask/2297027491/)了解更多详细信息。 (2认同)

Dav*_*ing 25

M_PI由"标准"定义,如果不是语言标准:带有X/Open System Interfaces扩展的POSIX(官方UNIX品牌非常普遍支持和需要).

它(仍然)不确定C++ 20中会有什么,但是因为你问:它可能会有这样的常量.图书馆进化在2018年11月批准了以前的版本文件(带有名称空间和可变模板),它可能出现在2019年8月的委员会草案中.


Jac*_*ley 13

这显然不是一个好主意,因为没有明显的类型可以定义跨域通用的pi.

当然,Pi是一个无理数,所以它不能被任何 C++类型正确表示.您可能会争辩说,自然方法是将其定义为可用的最大浮点类型.但是,最大标准浮点类型的long double大小不是由C++标准定义的,因此常量的值会因系统而异.更糟糕的是,对于任何工作类型不是这种最大类型的程序,pi的定义是不合适的,因为它会对每次使用pi施加性能成本.

对于任何程序员来说,找到pi的值并定义适合使用的常量也是微不足道的,因此将它包含在maths头中并没有任何好处.

  • 像一个真正的委员会成员一样,谈论尽管提出了明确的前进道路但无法做到的所有方式.[参见令人惊讶的相关示例变量模板](http://en.cppreference.com/w/cpp/language/variable_template).我不认为你的答案很糟糕,但我相信,对于将C++的未来控制权转移到一个非常优柔寡断的委员会而言遗憾的是,这对Bjarne Stroustrup的永恒抑郁无济于事. (18认同)
  • C++ 14为我们提供了可变模板.这不是它们的用途吗? (9认同)
  • @snb我同意将'pi`变成多态常数是明确的前进道路 - 用Hindley-Milner型推断的语言.在Haskell中,我们总是有'pi :: Floating a => a`,因此`pi`会在`Float`上下文中自动获得值`3.1415927`,在`Double`上下文中自动获得`3.141592653589793`,并且符号计算环境中的`π`.但人们真的想要显式实例化模板参数吗?看起来有点尴尬,特别是如果一个固定的`long double`实现在大多数应用程序中会给出相同的结果. (4认同)
  • @leftaroundabout我相信写'auto a = pi <float>;`是完全没问题的,当然比臭名昭着的`4*atan(1)更具可读性 (2认同)