-3

Please explain why pow() doesn't work for the big number such as 2^63?(if you write a pow function with the prototype of pow(long long int a, long long int b) instead of pow(double a, double b) it works fine.)

here is the code:

#include <stdio.h>
#include <math.h>
int main()
{
    printf("%.0lf\n" ,pow((double)2,63));
}

output:

9223372036854775800

true answer:

9223372036854775808

thanks.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
Fatemeh Karimi
  • 914
  • 2
  • 16
  • 23
  • Please include a [mcve] as part of your question. – Paul R Mar 23 '17 at 16:39
  • 3
    Define "does not work correctly", ideally with the REAL output – fvu Mar 23 '17 at 16:39
  • Do you know what different types mean? – Eugene Sh. Mar 23 '17 at 16:43
  • What was the _return type_ of your `pow(long long int a, long long int b)` example? – chux - Reinstate Monica Mar 23 '17 at 17:06
  • @chux it is also long long int – Fatemeh Karimi Mar 23 '17 at 17:07
  • See Wikipedia on [IEEE 754 double precision floating point](https://en.wikipedia.org/wiki/Double-precision_floating-point_format). The `double` type normally uses 12 bits for the sign and exponent, leaving 52 (effectively 53) bits to store the mantissa. While 2^63 only has 1 binary bit set, as you divide by 10 repeatedly to create the binary representation, you gradually use more bits, and you can start to run into problems, needing more bits to represent the value left over accurately. I'm not certain that's the cause, but there are limits to the accuracy of all these things. – Jonathan Leffler Mar 24 '17 at 04:25

2 Answers2

4

printf("%.0lf\n", x); is not required to print the exact value of (double) x.

A compliant C compiler/standard C library will generate code that will print about DBL_DECIMAL_DIG (typically 17), correct significant decimal digits. Other may print more digits correctly. (Mine printed 9223372036854775808). See <float.h>

// 45678901234567
9223372036854775800 // answer
9223372036854775808 // true answer:

Extreme example

DBL_MAX may have the exact value of

179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368

Yet many results of printf("%.0lf\n" ,DBL_MAX); will report zeros after a certain point

179769313486231570814527423731704356798070600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

OP later added that the reference pow() function was long long int pow(long long int a, long long int b). pow_ll_version(2,63) would be expected to result in 9223372036854775808, which is 1 passed many LLONG_MAX - certainly undefined behavior. Let us assume it wrapped to -9223372036854775808, and was printed with printf("%llu\n" , long_long_int_result); (more UB as mis-matched specifier and type). This may have given 9223372036854775808 to OP.

printf() output of integers is exact, not so with floating point values.

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

pow works fine. MSVC's printf is buggy and truncates the output for floating point.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • Why the downvote? `9223372036854775800` is not a possible value that can be represented in a `double`, so it's obviously not what `pow` returned. The only way it could have appeared is by `printf` printing it wrong, and the only implementation I know with this bug is MSVC's. – R.. GitHub STOP HELPING ICE Mar 23 '17 at 16:47
  • @R..I didn't give you downvote!! – Fatemeh Karimi Mar 23 '17 at 16:50
  • @FatemehKarimi I didn't downvote either but you could be more helpful than that by updating what compiler/library you are using (whether or not it's MSVC; if so, the version you're using) and how you are compiling, etc. – P.P Mar 23 '17 at 16:59
  • NMDV, but printing "...75800" is not buggy, (it is compliant C IMO), as it is weak. Only rare implementations do not resort to truncation at some point for large values. – chux - Reinstate Monica Mar 23 '17 at 17:10
  • @chux: While it's not forbidden (although POSIX has some fairly restrictive rules on what value must be printed; I don't recall if plain C does too), it still amounts to a quality-of-implementation "bug" in my book. There are multiple good implementations capable of printing the exact value or the correctly-rounded value to the requested precision. Printing zeros after `DECIMAL_DIG` places is just lazy and poor-quality, and MSVC is something of an outlier in doing it that way. – R.. GitHub STOP HELPING ICE Mar 23 '17 at 17:45