C ++ 11、14、17或20是否为pi引入标准常数?


170

在C和C ++中,数字pi存在一个相当愚蠢的问题。我所知道的M_PImath.h,任何标准都不要求定义。

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

是否有任何“新”标准为pi引入常数?如果没有-为什么?没有它,所有这些复杂的数学如何工作?

我知道有关C ++中pi的类似问题(它们已有好几年历史了,并且已经成为标准)。我想知道问题的当前状态。

我也对为什么 C ++仍然没有pi常量但具有很多更复杂的数学的原因非常感兴趣。

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

UPD2:根据这个在科隆在2019年7月C ++委员会会议之行报告,建议P0631(数学常数)被接纳进入C ++ 20。这样看来,终于在标准库中有了数字pi了!


您注意到是否存在诸如最佳平台独立pi常数之类的旧问题。如果您担心它们已经过时,则可以总是对其​​中一个设置赏金,以基于C ++ 17等寻求答案。然后所有答案都将放在一个地方。为什么仍然是一个好问题,但也许这应该集中在为何原因上,并要求提供最新消息应该是对现有问题的一种恩赐。
Shafik Yaghmour

我认为可能值得增加新的答案,因为据我所知,C ++ 20添加了一个pi常数
Guillaume Racicot

@GuillaumeRacicot我更新了问题。由于尚未正式发布C ++ 20,因此不确定是否应该解决。
砂纸

@GuillaumeRacicot:现在添加一个有点晚了
戴维斯·鲱鱼

Answers:


101

直到C ++ 17 pi为止(包括C ++ 17 pi),它都不是常数,它是一个令人头疼的问题。

我很幸运,因为我使用boost,它们为pi定义了足够大的小数位数,甚至是128位long double

如果您不使用Boost,请自己对其进行硬编码。用三角函数定义它是诱人的,但如果这样做,则不能将其设为constexpr。三角函数的精度也没有(任何标准我知道,保证CFstd::sqrt),所以真正你在危险的地面确实依赖于这样的功能。

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


来自C ++ 20的一些好消息。有一个defininition PI。C ++ 20在中添加了一些数学常数<numbers>。例如std::numbers::pi是一种double类型。

参考:https//en.cppreference.com/w/cpp/numeric/constants


9
@Lundin:但这不是一个constexpr不幸的原因,这就是为什么我说“用三角函数定义它是一种痛苦”
Bathsheba

9
为什么这有关系?Pi是一个常数,不受更改或任何特定于实现的约束。只需将值写出(如果您喜欢,可以在const对象中)到有意义的位数double(如果您关心假设的很长的long double值,则写一些荒谬的数字)。
R .. GitHub停止帮助ICE

10
@R ..我的问题是,现在看来可笑的东西可以在20年左右的时间内变得完全理智。(比尔·盖茨的640k浮现在脑海)。我相信Boost能够跟上架构的发展。
Bathsheba


10
@KonradRudolph:如果实现缩小范围,则高精度pi很重要。例如,x86 / x87的内部Pi常数(完整的64位尾数)会导致最坏情况的错误,这是因为fsin指令 较小的输入“最后放置约1.37亿五千万个单位,而正确的位数少于四位”,这是对于范围缩小约数倍的大型输入而言,情况甚至更糟。这long double与C ++中使用的常量有些相切,但无论如何都是整洁的。
彼得·科德斯

31

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

constexpr double pi = std::acos(-1);

假定您的C ++实现从中产生正确舍入的PI值acos(-1.0)这是很常见的,但不能保证

不是constexpr,但是在实践中,优化gcc和clang之类的编译器会在编译时对其进行评估。不过,声明const优化器要做好是很重要的。


2
这很危险,因为acos()函数在处具有无限的斜率x = -1。因此,此方法依赖于acos()实现来基本上显式捕获精确-1参数的情况,并直接返回正确的常量。最好使用4*atan(1)在数学上更健壮的类(在x = 1浮点数学运算中,斜率良好且乘以4总是精确的)。
cmaster-恢复莫妮卡

1
我们不允许std::acos在常量表达式中使用。clang将其报告为错误。请注意,这是不合格的扩展,最终应在gcc中修复。请参阅此答案以获取更多详细信息。
badola

31

在C ++ 20之前,没有,没有一个标准引入表示数字pi(π)的常数。您可以在代码中近似数字:

constexpr double pi = 3.14159265358979323846;

如C#等语言不断的在自己的音乐库声明。

更新: 从C ++ 20开始,确实pi<numbers>标头中声明了一个常量。可以通过访问std::numbers::pi


6
您可能要inline为C ++ 17 + 添加。
Deduplicator

8
助教。赞一下,但请注意,使用定义不同的平台,您的定义仍然容易受到不精确的影响double。由于double类型是固定的,因此C#很容易。如果我是C ++标准委员会的成员,我会提出类似的建议std::constants<double>::pi
Bathsheba,

11
@Deduplicator也不是constexpr隐式内联...吗?
WHN

4
@R。足够公平,尽管std::numeric_limits<double>::is_iec559;在这种情况下您应该静态断言。我承认,这就是我的“主标头”中的内容。请注意,形式上您需要单独检查所有浮点类型。仅仅因为一个是IEEE754并不意味着它们都是。
Bathsheba '18年

2
@DanielSchepler那么,那个“数字”应该是什么?我不知道有双底数为16的数字。
BЈовић

29

M_PI是由“标准”(如果不是语言标准)定义的:具有X / Open System Interfaces扩展的POSIX(官方UNIX品牌非常普遍地支持和必需)。

(仍然)不确定C ++ 20中会是什么,但是自从您问到:它可能会有这样的常量。该文件已合并到最后一轮C ++ 20功能中(针对2019年8月的委员会草案)。

具体来说,如果您要使用其他浮点类型(例如),则将同时使用std::numbers::pi(类型double)和变量模板std::numbers::pi_v<float>。常量的完整列表可以在[numbers.syn]中看到。


您可以根据自己的喜好随意修改我的编辑文字-我只想在此添加新常量的实际拼写,以供后代参考。
巴里(Barry)

12

这显然不是一个好主意,因为没有明显的类型可以定义pi,而pi在整个域中普遍适用。

Pi当然是一个无理数,所以它不能用任何 C ++类型正确表示。您可能会争辩说,自然的方法是在可用的最大浮点类型中对其进行定义。但是,最大的标准浮点类型的long double大小不是由C ++标准定义的,因此常量的值在系统之间会有所不同。更糟糕的是,对于任何工作类型不是最大类型的程序,pi的定义将是不合适的,因为这会给每次使用pi带来性能上的损失。

对于任何程序员来说,找到pi的值并定义自己适合使用的常量也是很简单的,因此将其包括在maths标头中并没有太大的优势。


10
C ++ 14给了我们变量模板。这不是他们的目的吗?
Amomum

21
像一位真正的委员会成员一样说话,谈论尽管提出了明确的前进道路,但仍然无法做到的所有方式。 参见相关示例变量模板。我不认为您的回答是不好的,但是我敢肯定,对于将C ++的未来控制权交给一个举棋不定的委员会的遗憾,Bjarne Stroustrup永远的沮丧无济于事。
WHN

4
@snb我同意pi在使用Hindley-Milner类型推断的语言中,实现多态常数是前进的明确道路。在Haskell中,我们一直有pi :: Floating a => a,所以pi会自动具有价值3.1415927Float情况下,3.141592653589793在一个Double范围内,并π在象征性的,计算环境。但是人们真的想要显式地实例化template参数吗?似乎有点尴尬,尤其是如果固定long double实现在大多数应用程序中会产生相同的结果。
leftaboutabout

2
@leftaroundabout我相信写作auto a = pi<float>;是完全可以的,当然比臭名昭著的可读性更高4*atan(1)
Amomum

1
gh,我因点击不当而投票否决,现在我无法撤消它。抱歉。即使我个人认为推理从根本上是有缺陷的(因为人们已经指出的原因),也应该对该+1进行很好的解释,以解释委员会为什么未添加它。
Fund Monica的诉讼

-1

编辑-删除必要的术语,因为它引起了争议。这绝对是一个绝对名词。

C ++是一种庞大而复杂的语言,因此,标准委员会仅包含了一些非常需要的内容。尽可能多地留给非语言标准库...如Boost。
boost :: math :: constants


29
当然,std::hermite并且std::cyl_bessel_iand std::coshstd::mersenne_twister_engineand std::ranlux48std::cauchy_distributionand std::assoc_laguerreand std::beta所有都是绝对必要的,我们每天都在使用它们!
Amomum

2
我敢肯定,您甚至连委员会本身都无法批准他们投票的一切“绝对必要”的想法。这不是关于必要性,而是关于增加语言的价值- 在标准库中编写程序几乎不需要任何东西,因此大多数核心语言也可以被抛弃(如果您不介意在Java语言中工作)图灵tarpit,就是这样。可以为pi包含一个常量的值可以争论,但是因为它不是必需的而不在其中的想法不能成立。
Jeroen Mostert

不要抱怨我,我只是引用标准委员会的话。关于C ++ 11标准应包含多少增强功能,已经进行了长时间的公开讨论。之所以这么小的子集,是因为编译器作者抱怨涉及多少测试。因此,如果某些东西在标准中,那是因为有人认为有必要对其进行标准化。仅仅因为您不知道为什么,并不意味着没有理由。
Tiger4Hire

1
@ Tiger4Hire我确定所有事情都是有原因的,我只是不明白为什么当许多更复杂的事情出现时,为什么没有为pi添加常量。使用变量模板可以很容易地编写常量,并且不需要编译器编写者的大量测试。
Amomum '18

@Amomum:是的,添加pi似乎是一笔小小的开销,但可以赢得很大的胜利。介意,个人而言,我更喜欢在std :: math :: constant之前查看std :: network。
Tiger4Hire
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.