63

在研究计算 p^q(求幂)的有效方法时,其中 q 是一个整数并查看 C++98 和 C++11 标准,我注意到显然std::pow(double, int)在 C++11 中删除了重载。

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

在 C++11 26.8 中,我只能找到采用一对 , 或 , 的重载floatdoublelong double明确指出,如果参数类型为 integer&double 的混合,pow(double, double)则应选择重载。

这只是对先前意图的澄清,它们是在 C++98 中错误地添加的,是在 C++11 中实际删除的,还是其他什么?

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

4

1 回答 1

84
double pow(double, int);

尚未从规范中删除。它只是被改写了。它现在位于 [c.math]/p11 中。它的计算方式是一个实现细节。唯一改变的 C++03 签名是:

float pow(float, int);

现在返回双倍:

double pow(float, int);

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

澄清

26.8 [cmath] / p11 说:

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

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

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

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

本段暗示了大量的重载,包括:

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 的实现者确实担心低端的所有这些位。

因此,尽管可以自由地改组pow(double, int)为单独的算法,但我所知道的大多数实现者已经放弃了该策略,可能除了检查非常小的整数指数之外。在这种情况下,使用浮点指数将该检查放入实现中通常是有利的,以便为您的优化降压获得最大的收益。

于 2011-04-11T20:39:06.677 回答