0

A simple calculation: 3^20%15.
The answer, according to a calculator, is 6.

The following code generates answer 7.

#include <stdio.h>
#include <math.h>
int main() {
        int i = 20;
        printf("%d\n", ((int)pow(3,20)%15));
        return 0;
}

If I replace 20 in the printf statement with the variable i, it gives -8 as output.

Assuming that the calculator is corrent (or not?), what is the problem in the program?

Thank you.

DeiDei
  • 10,205
  • 6
  • 55
  • 80
  • Please shown an [mcve] of the *failing* program. And please read about [how to ask good questions](http://stackoverflow.com/help/how-to-ask), as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Nov 19 '18 at 15:15
  • 1
    The numerical limits of integers are usually addressed in the first chapters of any C programming book. – Lundin Nov 19 '18 at 15:31

2 Answers2

4

The result of pow(3,20) can't fit in an int on your platform (or mine for that matter). Because of that, you're experiencing unexpected results.

Changing to a larger integer type such as long long will do the job.

Moreover, pow works with floating-point numbers which aren't represented exactly in memory (look that up). During conversion to an integer, that can cause certain errors. For example, for printf("%fl\n", (pow(3,20))); I get 3486784401.000000l which is not a precise integer value.

DeiDei
  • 10,205
  • 6
  • 55
  • 80
  • 1
    Additionally, note that poor implementations of `pow` may return inaccurate results for `pow(3, 20)`. They may return 3486784400.999999523162841796875 instead of 3486784401, which would cause the conversion to `int` to produce 3486784400 (before final conversion to 32-bit). – Eric Postpischil Nov 19 '18 at 15:17
  • 1
    Answers to this question should also address why there is a difference between `pow(3, 20)` and `pow(3, i)`, as the question asked. – Eric Postpischil Nov 19 '18 at 15:19
  • Unfortunately, the new statements in this answer about floating-point are not correct. Each floating-point object that is not a NaN represents one number exactly. The rounding errors in floating-point operations occur during operations, not in numbers. And the error I cautioned about occurs in poor implementations of `pow`, not in conversion to an integer. – Eric Postpischil Nov 19 '18 at 15:22
  • @EricPostpischil I don't think there is a difference between `pow(3, 20)` and `pow(3, i)`. The problem the OP is seeing comes from the fact that `int` can't hold such a large value. That's about that. Please post an answer that is more technically correct, this is as far as I can go. – DeiDei Nov 19 '18 at 15:23
  • Likely the compiler evaluated `pow(3, 20)` at compile time and `pow(3, i)` at run time. Sometimes the arithmetic used by a compiler at compile time differs from the arithmetic used at run time. – Eric Postpischil Nov 19 '18 at 15:59
1

What likely happened here is:

  • In your C implementation, int is 32 bits, with a minimum of −2,147,483,648 and a maximum of 2,147,483,647.
  • The result of pow(3, 20) is 3486784401. (See note 1 below.)
  • 3486784401 is too large for an int, so there is an overflow. In case of integer overflow, the C standard permits an implementation to do anything.
  • In (int) pow(3, 20), the conversion to int may have been computed at a compile time by producing the maximum, 2,147,483,647. Then the remainder of that divided by 15 is 7.
  • In (int) pow(3, i), the conversion to int may have been computed at run time by producing the minimum, −2,147,483,648. (Some processors produce such a result for integer overflows.) Then the remainder of that divided by 15 is −8.

In summary:

  • Your code overflows, so the C standard does not define the behavior.
  • The compiler likely behaves differently for pow(3, 20) and pow(3, i) because it evaluates the former at compile time and the latter at execution time.

Note

  1. Good implementations of pow return exactly 3486784401 for pow(3, 20). Unfortunately, poor implementations may return inaccurate values such as 3486784401.000000476837158203125 or 3486784400.999999523162841796875.
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312