为什么std :: pow(double,int)从C ++ 11中删除? [英] Why was std::pow(double, int) removed from C++11?

查看:241
本文介绍了为什么std :: pow(double,int)从C ++ 11中删除?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在查看有效的方式计算p ^ q(指数)时,其中q是整数,并查看C ++ 98和C ++ 11标准我注意到,显然在C ++ 11中删除了 std :: pow(double,int) overload。



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



在C ++ 11 26.8,我可以发现是重载,取一对 float double long double ,并且明确注意到在混合使用参数类型integral& double的情况下, pow )重载应该被选中。



这只是一个澄清的以前的意图,是他们不正确地添加到C ++ 98,实际上是在C ++ 11中删除的,还是别的什么?



显然 pow(double,int)一个很好的优化机会,所以它似乎奇怪,他们会被删除。编译器仍然是符合提供这种优化的过载的标准吗?

解决方案

  (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,
    ,那么对应于
    double参数的所有参数都有效地转换为
    到long double。


  2. 否则,如果对应于double参数
    的任何参数具有类型double或整数类型
    ,则对应于
    double参数的所有参数都有效

    li>


此段落意味着一整套重载,包括:

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

等。



重载,或者可以用受限模板来实现。



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

b
$ b

允许实现优化任何重载。但请记住,优化应仅为 。优化版本应该返回相同的答案。从pow的功能的实现者的经验是,当你去麻烦,以确保您的实现采取整数指数给出相同的答案与实现采取浮点指数,优化通常较慢。作为示例,以下程序打印出 pow(.1,20)两次,一次使用std :: pow,并且第二次使用利用整数指数的优化的算法:

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

int main()
{
std :: cout< std :: setprecision(17)<< std :: pow(.1,20)<< '\\\
';
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 < '\\\
';
}



在我的系统上打印输出:

  1.0000000000000011e-20 
1.0000000000000022e-20


b $ b

或以十六进制表示法:

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

是的,pow的实现者确实担心低端的所有这些位。 p>

因此,尽管自由可以将 pow(double,int) m知道放弃了那个策略,可能的例外是检查非常小的整数指数。在这种情况下,通常有利的是用浮点指数来执行该检查,以便获得最大的爆炸以进行优化。


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.

In C++98 26.5/6 it has the 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.

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?

Obviously the pow(double, int) version provides a nice opportunity for optimization so it seems odd that they would be removed. 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. How it is computed is an implementation detail. The only C++03 signature that has changed is:

float pow(float, int);

This now returns double:

double pow(float, int);

And this change was done for C compatibility.

Clarification:

26.8 [cmath] / p11 says:

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.

  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.

  3. Otherwise, all arguments corresponding to double parameters are effectively cast to 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.

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:

#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.

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. 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.

这篇关于为什么std :: pow(double,int)从C ++ 11中删除?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆