ccastinglimit

In C, why can I not cast pow(2,64) to an unsigned long?


I'm trying to print the maximum value for an unsigned long in C (18446744073709551615 on my machine) without using values from limits.h and without bitwise operators (exercise 2-1 from K&R, using only information that has been mentioned in the book up to then). Obviously just as an exercise, not for any real world application. My idea (which worked for all other data types) was

printf("Unsigned long: Max: %lu\n", (unsigned long)(pow(2,sizeof(unsigned long)*8)-1));

But for some reason, casting the output of (pow(2,64)-1) to an unsigned long is displayed as 2^63, even though unsigned long is big enough to show pow(2,64)-1

I have tried

printf("Unsigned long: Max: %lu\n", ULONG_MAX); // works
printf("Unsigned long: Max: %lu\n", 2*(unsigned long)pow(2,63)-1); // works
printf("Unsigned long: Max: %.0f\n", pow(2,64)-1); // sort of works, but displays 18446744073709551616, i.e., 2^64 instead of 2^64-1
printf("Unsigned long: Max: %lu\n", (unsigned long)(pow(2,sizeof(unsigned long)*8)-1)); // does not work
printf("Unsigned long: Max: %lu\n", (unsigned long)pow(2,64)-1); //does not work

I don't understand why the last 2 options do not work. Thanks for your help!


Solution

  • You have two problems here. The expression pow(2,64) can be represented exactly in a double, but when you typecast it with (unsigned long)pow(2, 64), you are effectively attempting to do the same thing as the expression 1 << 64. This number requires at least 65 bits to represent it. But, by the look of it, the unsigned long type on your system is only 64 bits long.

    It is true that the result of the expression (1 << 64) - 1 can be represented in only 64 bits, but it's too late - you have used an intermediate expression that is not representable along the way.

    Your other attempt, which is to use (unsigned long)(pow(2, 64) - 1) fails for a different reason. Although pow(2, 64) can be represented exactly in a double, pow(2, 64) - 1 cannot. This is because a double has only 53 bits of mantissa. Once again, this means that the result when cast to (unsigned long) is guaranteed to be wrong.