为什么从C ++ 11中删除了std :: pow(double,int)?

时间:2011-04-11 20:17:14

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

在研究Efficient way to compute p^q (exponentiation), where q is an integer并查看C ++ 98和C ++ 11标准时,我注意到在C ++ 11中显然删除了std::pow(double, int)重载。

在C ++ 98 26.5 / 6中,它具有double pow(double, int);签名。

在C ++ 11 26.8中我所能找到的是重载一对floatdoublelong double,并明确指出,如果参数混合类型为integral& double,应选择pow(double, double)重载。

这只是对前一个意图的澄清,如果它们在C ++ 98中被错误地添加了,它们是否真的在C ++ 11中删除了,还是其他什么?

显然pow(double, int)版本提供了一个很好的优化机会,因此将它们删除似乎很奇怪。编译器是否仍然符合标准以提供这样的优化过载?

1 个答案:

答案 0 :(得分:82)

double pow(double, int);

尚未从规范中删除。它简单地被重写了。它现在住在[c.math] / p11。如何计算是一个实现细节。唯一改变的C ++ 03签名是:

float pow(float, int);

现在返回double:

double pow(float, int);

更改是为了C兼容性而完成的。

<强>澄清

26.8 [cmath] / p11说:

  

此外,还有额外的   超载足以确保:

     
      
  1. 如果对应于double参数的任何参数的类型为long double,   那么所有的论据都对应着   双参数有效投射   加倍。

  2.   
  3. 否则,如果任何参数对应于double参数   有double类型或整数类型,   那么所有的论据都对应着   双参数有效投射   加倍。

  4.   
  5. 否则,所有与double参数对应的参数都是   有效地投下浮动。

  6.   

这一段意味着一大堆重载,包括:

double pow(double, int);
double pow(double, unsigned);
double pow(double, unsigned long long);

这些可能是实际的重载,或者可能是使用受限制的模板实现的。我亲自实现了它,并且非常支持受限制的模板实现。

解决优化问题的第二次更新:

允许实现优化任何过载。但请记住,优化应仅 。优化版本应该返回相同的答案。像pow这样的函数的实现者的经验是,当你遇到麻烦以确保你的实现采用积分指数给出与采用浮点指数的实现相同的答案时,“优化”通常较慢。

作为演示,以下程序打印pow(.1, 20)两次,一次使用std :: pow,第二次使用“优化”算法利用积分指数:

#include <cmath>
#include <iostream>
#include <iomanip>

int main()
{
    std::cout << std::setprecision(17) << std::pow(.1, 20) << '\n';
    double x = .1;
    double x2 = x * x;
    double x4 = x2 * x2;
    double x8 = x4 * x4;
    double x16 = x8 * x8;
    double x20 = x16 * x4;
    std::cout << x20 << '\n';
}

在我的系统上打印出来:

1.0000000000000011e-20
1.0000000000000022e-20

或以十六进制表示法:

0x1.79ca10c92422bp-67
0x1.79ca10c924232p-67

是的,战俘的实施者确实担心所有这些比特都处于低端。

因此,虽然自由是将pow(double, int)移到单独的算法上,但我知道的大多数实现者已经放弃了该策略,可能的例外是检查非常小的积分指数。在这种情况下,通常使用浮点指数将检查放入实现中是有利的,这样可以为您的优化降压获得最大的收益。