pow
After an upgrade of Visual Studio 2017 to 2019 it was noticed that regression
tests were failing with the new version. There were multiple causes; one of
them was that (yet again) the implementation of std::pow
had changed.
The Visual Studio 2017 implementation uses a different code path for the
common power 2 (square) case: it issues a simple multiplication. The
implementation is something like this:
_Check_return_ inline double pow(_In_ double _Xx, _In_ int _Yx) noexcept
{
if (_Yx == 2)
return (_Xx * _Xx);
return (_CSTD pow(_Xx, static_cast<double>(_Yx)));
}
The Visual Studio 2019 implementation isn't available in source code
form but the exceptional code path for calculating the square seems not present anymore.
This gives (small) differences with some numbers, e.g. the square of
'0.10000000055703842' gives a different result.
Alternative
Luckily boost offers an alternative for
calculating squared and other integer powers known at compile time in its math
library:
#include <boost/math/special_functions/pow.hpp>
constexpr double d = 0.10000000055703842;
const double d2 = boost::math::pow<2>(d);
Using this function should give stable result for the coming upgrades of
Visual Studio. It has also the extra benefit of better performance. Results of
a test case with running many power calculations:
Function |
Time (s) |
boost::math::pow<2> |
0.241 |
std::pow |
9.395 |
Note that instead of using a power function direct multiplication is ofc also possible. Often though these power functions are fed with another calculated value which otherwise has to be duplicated or write down explicitly:
const double d = std::sqrt(boost::math::pow<2>(pt.x - x) + boost::math::pow<2>(pt.y - y));
Boost's math::pow has the extra benefit of doing the least amount of multiplications in case the power is larger than 3.