简体   繁体   English

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

[英]Why was std::pow(double, int) removed from C++11?

While looking into Efficient way to compute p^q (exponentiation), where q is an integer and reviewing the C++98 and C++11 standards I noticed that apparently the std::pow(double, int) overload was removed in C++11. 在研究计算p ^ q(取幂)的有效方法时,其中q是一个整数并且回顾了C ++ 98和C ++ 11标准,我注意到显然std::pow(double, int)重载被删除了C ++ 11。

In C++98 26.5/6 it has the double pow(double, int); 在C ++ 98 26.5 / 6中它有double pow(double, int); signature. 签名。

In C++11 26.8 all I could find was overloads taking a pair of float , double , or long double , and an explicit note that in case of a mixture of parameter types integral&double, that the pow(double, double) overload should be picked. 在C ++ 11 26.8中我所能找到的是重载一对floatdoublelong double ,并且明确指出,如果参数类型为integer和double的混合,则pow(double, double)重载应该是采摘。

Is this just a clarification of the previous intention, were they incorrectly added in C++98, were they actually removed in C++11, or something else? 这只是对前一个意图的澄清,如果它们在C ++ 98中被错误地添加了,它们是否真的在C ++ 11中删除了,还是别的?

Obviously the pow(double, int) version provides a nice opportunity for optimization so it seems odd that they would be removed. 显然pow(double, int)版本提供了一个很好的优化机会,所以它们被删除似乎很奇怪。 Would a compiler still be standards conforming to provide such an optimized overload? 编译器是否仍然符合标准以提供这样的优化过载?

double pow(double, int);

hasn't been removed from the spec. 尚未从规范中删除。 It has simply been reworded. 它简单地被重写了。 It now lives in [c.math]/p11. 它现在住在[c.math] / p11。 How it is computed is an implementation detail. 如何计算是一个实现细节。 The only C++03 signature that has changed is: 唯一改变的C ++ 03签名是:

float pow(float, int);

This now returns double: 现在返回双倍:

double pow(float, int);

And this change was done for C compatibility. 更改是为了C兼容性而完成的。

Clarification : 澄清

26.8 [cmath] / p11 says: 26.8 [cmath] / p11说:

Moreover, there shall be additional overloads sufficient to ensure: 此外,还应有足够的额外过载来确保:

  1. If any argument corresponding to a double parameter has type long double, then all arguments corresponding to double parameters are effectively cast to long double. 如果对应于double参数的任何参数的类型为long double,则对应于double参数的所有参数都有效地转换为long double。

  2. Otherwise, if any argument corresponding to a double parameter has type double or an integer type, then all arguments corresponding to double parameters are effectively cast to double. 否则,如果对应于double参数的任何参数具有double类型或整数类型,则对应于double参数的所有参数都将有效地转换为double。

  3. Otherwise, all arguments corresponding to double parameters are effectively cast to float. 否则,对应于double参数的所有参数都被有效地转换为float。

This paragraph implies a whole host of overloads, including: 本段意味着一大堆重载,包括:

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

etc. 等等

These may be actual overloads, or may be implemented with restricted templates. 这些可能是实际的重载,或者可能使用受限模板实现。 I've personally implemented it both ways and strongly favor the restricted template implementation. 我亲自实现了它,并强烈支持受限制的模板实现。

Second update to address optimization issues: 第二次更新以解决优化问题:

The implementation is allowed to optimize any overload. 允许实现优化任何过载。 But recall that an optimization should be only that. 但请记住,优化应该只是那样。 The optimized version ought to return the same answer. 优化版本应该返回相同的答案。 The experience from implementors of functions like pow is that by the time you go to the trouble to ensure that your implementation taking an integral exponent gives the same answer as the implementation taking a floating point exponent, the "optimization" is often slower. 像pow这样的函数的实现者的经验是,当你遇到麻烦以确保你的实现采用积分指数给出与采用浮点指数的实现相同的答案时,“优化”通常较慢。

As a demonstration the following program prints out pow(.1, 20) twice, once using std::pow, and the second time using an "optimized" algorithm taking advantage of the integral exponent: 作为演示,以下程序打印出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';
}

On my system this prints out: 在我的系统上打印出:

1.0000000000000011e-20
1.0000000000000022e-20

Or in hex notation: 或者以十六进制表示法:

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

And yes, implementors of pow really do worry about all of those bits down at the low end. 是的,pow的实现者真的确实担心所有这些低端的比特。

So while the freedom is there to shuffle pow(double, int) off to a separate algorithm, most implementors I'm aware of have given up on that strategy, with the possible exception of checking for very small integral exponents. 因此,虽然自由是将pow(double, int)改为单独的算法,但我所知道的大多数实现者已经放弃了该策略,可能的例外是检查非常小的积分指数。 And in that event, it is usually advantageous to put that check in the implementation with the floating point exponent so as to get the biggest bang for your optimization buck. 在这种情况下,通常使用浮点指数将检查放入实现中是有利的,以便为您的优化降压获得最大的收益。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM