550. What should the return type of pow(float,int) be?

Section: 29.9 [c.math] Status: CD1 Submitter: Howard Hinnant Opened: 2006-01-12 Last modified: 2016-02-10

Priority: Not Prioritized

View all other issues in [c.math].

View all issues with CD1 status.

Discussion:

Assuming we adopt the C compatibility package from C99 what should be the return type of the following signature be:

?  pow(float, int);

C++03 says that the return type should be float. TR1 and C90/99 say the return type should be double. This can put clients into a situation where C++03 provides answers that are not as high quality as C90/C99/TR1. For example:

#include <math.h>

int main()
{
    float x = 2080703.375F;
    double y = pow(x, 2);
}

Assuming an IEEE 32 bit float and IEEE 64 bit double, C90/C99/TR1 all suggest:

y = 4329326534736.390625

which is exactly right. While C++98/C++03 demands:

y = 4329326510080.

which is only approximately right.

I recommend that C++0X adopt the mixed mode arithmetic already adopted by Fortran, C and TR1 and make the return type of pow(float,int) be double.

[ Kona (2007): Other functions that are affected by this issue include ldexp, scalbln, and scalbn. We also believe that there is a typo in 26.7/10: float nexttoward(float, long double); [sic] should be float nexttoward(float, float); Proposed Disposition: Review (the proposed resolution appears above, rather than below, the heading "Proposed resolution") ]

[Howard, post Kona:]

Unfortunately I strongly disagree with a part of the resolution from Kona. I am moving from New to Open instead of to Review because I do not believe we have consensus on the intent of the resolution.

This issue does not include ldexp, scalbln, and scalbn because the second integral parameter in each of these signatures (from C99) is not a generic parameter according to C99 7.22p2. The corresponding C++ overloads are intended (as far as I know) to correspond directly to C99's definition of generic parameter.

For similar reasons, I do not believe that the second long double parameter of nexttoward, nor the return type of this function, is in error. I believe the correct signature is:

float nexttoward(float, long double);

which is what both the C++0X working paper and C99 state (as far as I currently understand).

This is really only about pow(float, int). And this is because C++98 took one route (with pow only) and C99 took another (with many math functions in <tgmath.h>. The proposed resolution basically says: C++98 got it wrong and C99 got it right; let's go with C99.

[ Bellevue: ]

This signature was not picked up from C99. Instead, if one types pow(2.0f,2), the promotion rules will invoke "double pow(double, double)", which generally gives special treatment for integral exponents, preserving full accuracy of the result. New proposed wording provided.

Proposed resolution:

Change 29.9 [c.math] p10:

The added signatures are:

...
float pow(float, int);
...
double pow(double, int);
...
long double pow(long double, int);