1

This is my C code for determining that 153 is equal to the sum of the cubes of each digit. However, why is 1 + 5^3 + 3^3 = 152 and not 153?

#include <stdio.h>
#include <math.h>

int main()
{
 int digit, temp, sum = 0, num = 153;
 temp = num;
 while (num > 0)
 {
     digit = num % 10;
     sum += pow(digit,3);
     num /= 10;
 }
 printf("%d \n", sum);
 if (temp == sum)
 {
     printf("153 is a special number");
 }
 else
 {
     printf("153 is not a special number");
 }
}

Edit: I'm using CodeBlocks and I get 152, not 153. If I use double sum instead of int sum however, I get the correct answer. But I'm not sure why using double is correct.

Iris
  • 41
  • 4
  • 1
    For me it output 153. – Eraklon Feb 12 '20 at 12:06
  • @Eraklon I use CodeBlocks and I get 152. – Iris Feb 12 '20 at 12:17
  • [Why does pow(5,2) become 24?](https://stackoverflow.com/q/22264236/995714), [Why does pow(n,2) return 24 when n=5, with my compiler and OS?](https://stackoverflow.com/q/25678481/995714), [Why pow(10,5) = 9,999 in C++](https://stackoverflow.com/q/9704195/995714), [Why does gcc compiler output pow(10,2) as 99 not 100? (duplicate)](https://stackoverflow.com/q/25474351/995714)... – phuclv Feb 12 '20 at 13:04

3 Answers3

3

Your program gets 152 for sum because your C implementation has a sub-par implementation of pow.

The proper return value of pow(5, 3) is 125, but your C implementation returns something like 124.9999999999999857891452847979962825775146484375. In sum += pow(digit,3);, sum has type int, so the result of the addition is converted to an integer, which results in truncation of the fractional part.

This occurs because pow is implemented with floating-point arithmetic, and the implementation does not take care to return a good quality result. pow is generally difficult to implement, but it is feasible to implement pow with an error of less than one unit of least precision (ULP). When this is done, exactly correct results are returned in all cases where the mathematical result is representable.

To avoid this in your program, do not use the floating-point pow function. For this simple program, write your own “integer pow” function.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • In particular OP is almost certainly using Windows/MSVC. Other implementations of `pow` are almost all correct for integer arguments where result is exactly representable. – R.. GitHub STOP HELPING ICE Feb 12 '20 at 15:55
  • @R..GitHubSTOPHELPINGICE: Yes, and I used to call out Microsoft on this. But I think they may have updated their `pow` implementation, so only people using old versions encounter this. I am not sure, as I do not keep any Windows software on hand; I just had second-hand clues. – Eric Postpischil Feb 12 '20 at 15:58
1

The pow function takes a double for each of its arguments and returns a double. Because it works with floating point numbers, the operations are not exact. For example,pow(3,3)` could return 26.999999998 which when assigned to an integer is truncated to 26.

Since you're only raising a number to the 3rd power, get rid of the call to pow and just do the multiplication explicitly.

sum += digit * digit * digit;
dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    The statement “Because it works with floating point numbers, the operations are not exact.” is not logically correct. The fact that `pow` works with floating-point numbers **does not logically prevent it from returning exact results when they are representable**. This is proven by the fact that Apple’s `pow` does return exact results when they are representable. The actual cause that `pow(5, 3)` returns an incorrect result is that the `pow` that the OP is using was poorly implemented. – Eric Postpischil Feb 12 '20 at 12:21
0

It is bad to use floating-point numbers when you do integer calculations. You need to write your own integer functions instead:

unsigned upow(unsigned n, unsigned i)
{
    unsigned result = 1;
    while(i--)
    {
        result *= n;
    }
    return result;
}

https://godbolt.org/z/5h-Mng

0___________
  • 60,014
  • 4
  • 34
  • 74