【问题标题】:Does C++11 enforce pow(double, int) to use the slower pow(double, double)? [duplicate]C++11 是否强制 pow(double, int) 使用较慢的 pow(double, double)? [复制]
【发布时间】:2013-09-18 13:07:42
【问题描述】:

在 C++ 03 中,使用例如std::pow(double_val, 6) 比使用 std::pow(double_val, 6.0) 快得多。

使用 C++11 编译时不再是这种情况。查看 gcc 的 libstdc++-4.8 中的 cmath 标头,可以看到显式 pow(double, int) 不再存在,这种情况由以下模板处理,该模板将 int 提升为 double:

template<typename _Tp, typename _Up>
inline typename __gnu_cxx::__promote_2<_Tp, _Up>::__type
pow(_Tp __x, _Up __y) {
  typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
  return std::pow(__type(__x), __type(__y));
}

这是 C++11 标准中的行为还是未来的 libstdc++ 实现会返回到更快的方法?

其次,如果出于标准或实施原因,更快的行为不再可能,那么再次实现它的最便携的方法是什么?我在 gcc stdlibc++ 中的“ext/numeric”下看到了一个 power(...) 函数,但这被标记为 非标准 SGI(rip) 扩展。

【问题讨论】:

  • Sounds right: "如果任何参数具有整数类型,则将其强制转换为 double"。奇怪的。而且我在标准中找不到参考...
  • @KerrekSB:我想知道有效投射是什么意思。这是否会阻止实现提供其他重载?从数学的角度来看,x^5x^5.0 是一回事……(尽管它们可能不在实现中)。如果两者的结果相同,我不确定标准是否规定不提供额外的重载。
  • @DavidRodríguez-dribeas:我什至不知道网站是从哪里得到的。找不到那个参考...
  • @KerrekSB 在 26.8 第 11 段 [c.math] 中有。我自己已经有了some problems

标签: c++ gcc c++11 c++-standard-library


【解决方案1】:

首先,是的,这种行为符合 C++11 标准(尽管不符合 C++03),在第 26.8 节第 11 段中说:

此外,应有足够的额外重载以确保:

  1. 如果与 double 形参对应的任何实参具有 long double 类型,则与 double 形参对应的所有实参都将有效地转换为 long double。

  2. 否则,如果任何对应于 double 形参的实参具有 double 类型或整数类型,则对应于 double 形参的所有实参都被有效地强制转换为 double。

    李>
  3. 否则,所有对应于双精度参数的参数都会被有效地转换为浮点数。

(除了float-only、double-only 和 long double-only 的重载。)

所以实现实际上将该整数参数转换为double,我认为符合标准的库不可能为整数幂提供更快的std::pow,除了可能检查 double 参数的完整性(这是一个词吗?)并在这种情况下使用特殊路径。

为了提供一种独立于平台的更快方式,我想到的唯一一件事就是编写一个自定义包装器,如果它存在的话,它会委托给这个非标准的power。除此之外,我不知道如何在不编写自己的实现的情况下再次将该行为注入std::pow

编辑:然而,在查看this answer 时,只要它的行为与std::pow(double(x), double(y)) 完全相同,实现仍然可以为整数幂提供优化的重载。因此,有一种实现提供更快版本的可能性,但我不会像您在 C++03 中所做的那样依赖它(恕我直言,它甚至是标准的一部分,但我可能错了) .

【讨论】:

    【解决方案2】:

    C 仅提供double pow(double, double) 重载(请记住,C 无论如何都不允许函数重载)。 C++11 标准 (26.8/9) 表示将以下重载(除了 C 之外)添加到命名空间 std

    float pow(float, float);
    long double pow(long double, long double);
    

    因此,double pow(double, int) 是一个扩展而不是标准函数。因此,实现可能会提供或不提供。

    编辑在 Christian Rau 评论和回答之后。

    现在我相信过载一定存在。因此,应该有一个double pow(double, int) 过载。但是,这种重载必须(正如他在回答中所说)将int 转换为double 并调用double pow(double, double)

    实际上有很多重载。提供它们的最简单方法不是作为普通函数,而是作为模板函数,与 OP 中显示的 libstdc++ 实现完全相同。

    另请参阅 this open issue,其中 Howard Hinnant 解释了详细信息。

    最后,Hulk 提供的 link 非常相关,Howard Hinnant(再次)解释说,几乎没有理由提供一个优化的重载来做任何不同于将 int 转换为 double 的事情。

    【讨论】:

    • 您还需要查看哪些 pow 签名可用。 double pow(double, double) 可能不是扩展名
    • @Hulk:问题是:(1)“这是 C++11 标准中的行为”(我的回答是“是”); (2)“未来的 libstdc++ 实现能否回归到更快的方法?” (我的回答是“可以,但不是必须的)”;和(3)“再次实现它的最便携方式是什么?” (我没有回答,因为我不知道)。为什么它被删除是另一个没有被问到并且我没有答案的问题。
    • @BЈовић:double pow(double, double) 是 C++11 标准中引用的 C 库的一部分。它在标头 &lt;cmath&gt; 中声明(参见 C++11 26.8/3,表 119)。此外,26.8/8 表示“除了&lt;cmath&gt; 中数学函数的double 版本之外,C++ 还添加了floatlong double 这些函数的重载版本”。
    • @CassioNeri 你说得对,我看错了问题。
    • 这并不完全正确。在 26.8 第 11 段中,C++11 标准要求额外的重载,准确地将任何整数转换为 double
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-17
    • 1970-01-01
    • 2014-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多