4

According to http://en.cppreference.com/w/cpp/numeric/math/pow , when std::pow is used with integer parameters, the result is promoted to a double.

My question is then the following:

How safe is to compare an integer type with the result of a std::pow(int1, int2)? For example, can the if below evaluate to true?

std::size_t n = 1024;
if(n != std::pow(2, 10))
    cout << "Roundoff issues..." << endl;

That is, is it possible that the result on the rhs can be something like 1023.99...9 so when converted to size_t becomes 1023?

My guess is that the response in a big NO, but would like to know for sure. I am using these kind of comparisons when checking for dimensions of matrices etc, and I wouldn't like to use a std::round everywhere.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • 2, 10 and 1024 can all be perfectly represented by a `double`. You should be fine as long as the inputs and output will fit into 53 bits (assuming IEEE-754 `double`) – Praetorian Nov 15 '14 at 01:43
  • 1
    @Praetorian You should tell that to user1257. http://stackoverflow.com/questions/15851636/is-this-a-g-bug – Pascal Cuoq Nov 15 '14 at 02:07
  • @PascalCuoq That's interesting, and horrible. I'm not able to reproduce that on gcc4.4.7, 4.8, 4.9 or MinGW gcc4.9; but it's good to be aware of that problem. Thank you. – Praetorian Nov 15 '14 at 02:14
  • So I guess the safest bet is to use `std::lround` before assigning to an integral type. Thanks all for the answers! – vsoftco Nov 15 '14 at 03:01

4 Answers4

5

It is funny you should ask, because someone else on StackOverflow had a question that was caused by the very fact that pow applied to small integers did not compute the obvious result on their platform (see also my writeup).

So yes, when applying pow to small integers, both arguments and ideal mathematical result are exactly representable. This does not force the implementation of exp to return the mathematical result, because no standard specifies that pow cannot be inaccurate by more than one ULP. And at least one very popular platform provides by default a pow function that does not compute pow(10, 2) as 100, but you are free to take you chances with pow(2, N) and perhaps it will happen to always return the integer you are entitled to expect.

Community
  • 1
  • 1
Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
  • 6
    Except you should never use `pow(2, N)`, because `ldexp(1, N)` is better (faster and guaranteed exact result) – Ben Voigt Nov 15 '14 at 02:12
  • @BenVoigt nice to know, thanks, although I gave 2^N as an example. In reality I'm using D^N, where D can be any integer, not just 2. – vsoftco Nov 15 '14 at 03:19
3

pow on integer arguments when the result is exactly-representable should give you the right answer all the time. Problem is, it doesn't. There are modern platforms (lots of Linux distributions, for instance, both old and recent), where it doesn't. It's not too hard to find a bunch of SO questions where people give pow really nice inputs and it returns a horribly wrong answer.

tmyklebu
  • 13,915
  • 3
  • 28
  • 57
0

For that specific example, it should always return false, especially since you are using type int, so that wouldn't have rounding errors.

The places where you would want to be cautious about rounding errors is when you're comparing two different arithmetic functions that return floats or doubles with long decimals. Many times they would return as unequal due to different rounding and different operations occurring.

0

As several answers have pointed out even though for small numbers the result should be exactly representable there are some low quality implementations.

For the case where you are using const expressions such as:

std::pow(2, 10)

many compilers will use builtin functions for example both gcc and clang will use builtin functions which will probably use something like a lookup table or a simpler formula for these trivial cases. We can see for the above case using godbolt that gcc computes the value at compile time:

movl    $1024, %esi     

These results are more likely to be correct as the question C: i got different results with pow(10,2) and pow(10,j), j=2; demonstrates.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740