Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
439 views
Welcome To Ask or Share your Answers For Others

1 Answer

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) << '
';
    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 << '
';
}

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...