Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does C++11 enforce pow(double, int) to use the slower pow(double, double)? [duplicate]

In C++ 03, using e.g. std::pow(double_val, 6) was considerably faster than using std::pow(double_val, 6.0).

This is no longer the case when compiling with C++11. Looking at the cmath header from gcc's libstdc++-4.8, one can see an explicit pow(double, int) is no longer present, this case is handled by the following template which promotes the int to a double:

template<typename _Tp, typename _Up>
inline typename __gnu_cxx::__promote_2<_Tp, _Up>::__type
pow(_Tp __x, _Up __y) {
  typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
  return std::pow(__type(__x), __type(__y));
}

Is this behavior in the C++11 standard or could future libstdc++ implementations return to the faster method?

Secondly, if for standard or implementation reasons the faster behavior is no longer possible, what is the most portable way to achieve it again? I see a power(...) function in the gcc stdlibc++ under "ext/numeric", but this is marked as a non-standard SGI(rip) extension.

like image 866
toting Avatar asked Sep 18 '13 13:09

toting


People also ask

Is POW a double or int?

The pow() function takes 'double' as the arguments and returns a 'double' value. This function does not always work for integers.

Is POW function slow?

Without further optimizations from the compiler (like inlining or using built in functions for some special type of powers like integer exponent), pow is almost always much slower.

Does POW work with ints in C?

The pow() function takes values of type double as its arguments and returns a value of type double. But the function does not always work with integers. For example, if the value returned by pow(4, 3) is assigned to an integer variable, the output might be 63 on some compilers and 64 on other compilers.

Does POW return integer?

there is no int based pow. What you are suffering from is floating point truncation.


2 Answers

First of all, yes this behaviour is consistent with the C++11 standard (though not with C++03), which in section 26.8, paragraph 11 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.

(In addition to the overloads for float-only, double-only and long double-only.)

So the implementation actually has to cast that integer argument into a double and I don't think there is a possibility for a conforming library to provide a faster std::pow for integer powers, apart from maybe checking the double argument for integrality (is that a word?) and using a special path in this case.

In order to provide a platform-independent faster way, the only thing that comes to my mind would be to write a custom wrapper that delegates to this non-standard power if it is present. Other than that I don't know how you could infuse that behaviour into std::pow again without writing your own implementation.

EDIT: Yet when looking at this answer it is indeed possible for an implementation to still provide an optimized overload for integer powers as long as it behaves exactly like std::pow(double(x), double(y)). So there is a possiblity for an implementation to provide that faster version, yet I wouldn't count so much on this as you have done in C++03 (where it was IMHO even part of the standard, but I might be wrong).

like image 61
Christian Rau Avatar answered Oct 20 '22 03:10

Christian Rau


C provides just the double pow(double, double) overload (recall that C doesn't allow function overloading anyway). The C++11 standard (26.8/9) says that the following overloads are added (in addition to C's) to namespace std:

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

Hence, double pow(double, int) is an extension rather than a standard function. Therefore an implementation might provide it or not.

Edit After Christian Rau comment and answer.

Now I believe the overload must be there. Hence, there should be a double pow(double, int) overload. However, this overload must (as he says in his answer) cast the int to a double and call double pow(double, double).

Actually there are a lot of overloads. The easiest way to provide them is not as normal functions but as a template function exactly as the libstdc++ implementation shown in the OP.

See also this open issue where Howard Hinnant explains the details.

Finally the link provided by Hulk is very relevant and Howard Hinnant (again) explains that there's almost no reason to provide an optimized overload that does anything different from casting the intto the double.

like image 36
Cassio Neri Avatar answered Oct 20 '22 01:10

Cassio Neri