【问题标题】:Constexpr Math FunctionsConsexpr 数学函数
【发布时间】:2013-06-27 16:00:30
【问题描述】:

从page 中注意到,c++11 中的数学函数似乎都没有使用 constexpr,而我相信它们都可以。所以这给我留下了两个问题,一个是为什么他们选择不制作函数 constexpr。还有两个用于sqrt 之类的函数,我可能会编写自己的 constexpr,但是像 sin 或 cos 这样的函数会更棘手,所以有办法绕过它。

【问题讨论】:

  • 他们没有选择不制作函数 constexpr。他们只是没有做出任何选择(我相信将来会有这样的提议)。
  • @R.MartinhoFernandes - 有一些讨论,但制作复杂函数的问题constexpr 是编译器必须执行运行时计算,这意味着拥有 C++ 解释器内置在编译器中。这是一项艰巨的工作......
  • @PeteBecker 并非所有这些都是复杂的,但我想我说我也是在说为什么不自己做它们
  • 那么编译器应该为constexpr double v = tan(1.570796326)设置v的值呢?
  • 注意,gcc has implemented most of the math function as constexpr 虽然扩展名不符合标准,但这应该会改变。所以绝对可行。

标签: c++ c++11 constexpr cmath


【解决方案1】:

实际上,由于旧的和烦人的遗留问题,几乎没有一个数学函数可以是constexpr,因为它们都有在各种错误条件下设置errno 的副作用,通常是域错误。

【讨论】:

  • 没有。也就是说,我认为没有可用的 constexpr 数学函数库,所以即使这样也行不通。 (当然,C++14 将使它们的实现更加方便和高效。)
  • 一个函数可以是 constexpr,但有时仍会抛出,等等。 double 之和的值可能取决于舍入模式,但会针对 constexpr 情况进行调整。 errno 确实不是个好理由。
  • @MarcGlisse Throwing 和 errno 是两种截然不同的野兽。 C 标准数学函数被指定为修改errno,而不是抛出异常。所以我不明白你的意思。
  • @SebastianRedl 如果结果不准确,则指定添加以设置 FE_INEXACT。但是,仍然允许加法为 constexpr。这看起来更接近您的errno 情况吗?
  • 它很接近,除了在 C99 中找不到这样的规范,更不用说在 C++11 中了。最接近的是 C99 附件 F 中的 ISO 60559 操作参考。但是,C++ 只引用了 C 的库子句,所以这个附件在 C++ 中没有规范作用。我不认为 C++ 有任何要求加法有副作用。请特别注意在 C++11 第 5 节介绍中缺少任何“收缩”浮点操作,这些操作在 C99 的等效部分中。
【解决方案2】:

来自“C++ 编程语言(第 4 版)”,作者 B. Stroustrup,描述了 C++11:

"要在编译时求值,函数必须适当地简单:constexpr 函数必须由单个返回语句组成;不允许循环,也不允许局部变量。此外,constexpr 函数不能有副作用。”

这意味着它必须是内联的,没有 for、while 和 if 语句和局部变量。副作用也被禁止(例如:更改 errno)。另一个问题是大多数数学函数都是 FPU 指令,它们没有用纯 c/c++ 表示(它们是用汇编代码编写的)。这就是为什么非 cmath 函数被声明为 constexpr。

【讨论】:

  • 这在 C++14 中不再适用了。
  • 是的,好点。我给出了为什么这些函数在 c++11 中不能是 constexpr 的答案,因为问题是关于 c++11。
  • @aaronman,正如 Marc Glisse 所说,errno 不是一个好的理由,因为 c++ 标准可以提供那些不会修改 errno 的函数的并行实现。但即便如此,如果没有一些内在的编译器功能,也无法实现 constexpr 。我不想争论,但我认为,我为此指出了几个很好的理由。我当然可能是错的。我目前正在编写一个库,该库将从 constexpr 数学函数中获益良多——这就是我来这里的原因——但我认为问题远不止“errno”。
  • @AdamSzaj constexpr 函数(甚至是 c++11 函数)已经完成,所以我看不到您提出的问题,这里是 contexpr sqrt 的示例我写了一段时间
  • 相当不错,但试试awsome::sqrt(3e13)。您是否尝试过实现 sin、cos、tanh 或类似函数?我知道有这样的功能的算法,但你认为constexpr_sin(x) == sin(x)?
【解决方案3】:

所以从这个页面注意到 c++11 中没有任何数学函数 似乎使用了 constexpr,而我相信它们都可以 是。所以这给我留下了两个问题,一个是他们为什么选择 不要将函数设为 constexpr。

Sebastian Redl 和 Adam Szaj 很好地回答了这部分内容,因此不会添加任何内容。

对于像 sqrt 这样的函数,我可以自己编写两个 constexpr,但是像 sin 或 cos 这样的东西会更棘手,所以有 远离它。

是的,您可以使用这些函数的泰勒级数展开来编写自己的 constexpr sin, cos 版本。看看这个超级酷的 github repo,它实现了几个数学函数作为 constexpr 函数Morwenn/static_math

【讨论】:

  • 不太酷:尝试计算smath::cos(20.)。余弦大于 3...实现一个像样的非constexpr 三角函数已经够难的了,更不用说constexpr 一个了。
  • @Ruslan 感谢您指出这一点。我自己从未尝试过。但是,我创建了自己的库来做一些编译时的事情github.com/lakshayg/compile_time,我很确定它可以很好地处理这种情况。如果您有任何建议,请尝试并告诉我(或打开问题)(这仍在进行中)。
  • 没有看代码,但是你的版本1)没有包含<stdexcept>,因此没有调整就无法编译; 2)似乎只做微不足道的范围缩小,例如compile_time::cos(200.) 与 x86_64 gcc 上的 std::cos(200.) 有很大不同,而对于 2. 的参数,结果或多或少是相同的。更糟糕的是long double。但是,是的,与static_math 不同,它似乎至少尝试缩小范围。
  • @Ruslan 感谢您的反馈,能否请您提供一些有关您的平台的详细信息。在我的机器(linux、x86_64、g++5.4)上,代码编译时没有任何警告/错误,并且错误小于 0.00001%。另外,我们可能应该在 github 上继续讨论。
  • 是的,做了一个问题报告。无论如何,精度的问题不在于它是百分之几,而是它有多少 ULP。在我的测试中,我得到了 2**17 ULP 的错误,这对 IEEE754 64 位 double 没有好处。
猜你喜欢
  • 2021-12-11
  • 2019-01-23
  • 2021-09-20
  • 1970-01-01
  • 2018-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-13
相关资源
最近更新 更多