1

Does anybody knows why this code prints 1000000000000000000 and not 1000000000000000001 as expected?

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

int main(void){
   long long n = (pow(10,18) + 1);
   printf("%lld ", n);
}
Gendozz
  • 83
  • 5

1 Answers1

1

pow(10, 18) returns a floating point double. The result of that, and adding 1, is indistinguishable in floating point space to the number you get back. For IEEE754, the closest double to 1000000000000000001 is 1000000000000000000, which more than likely accounts for your result.

(long long)pow(10, 18) + 1

might work (and probably will with a modern C toolset): you are still at the mercy of pow returning the algebraically correct result, of which there is no guarantee, although it's becoming increasingly fashionable to regard a C implementation of pow that doesn't return the best possible result when given integral arguments as defective - the days of pow(x, y) being implemented as simply exp(y * log(x)) are surely over?

So two options really. Either hope all your target platforms are up to it, or use a mathematics library that has a power function for integral arguments, using a technique such as exponentation by squaring.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • are you sure `exp(y * log(x))` should work? – Gendozz Oct 15 '21 at 08:50
  • @Gendozz: It's reasonable but doesn't work well in whole-number applications. It's a nice idea because it's quick. `exp` is trivial for chips to calculate. Natural log is trickier but modern chips can bang it out in a handful of clock cycles. – Bathsheba Oct 15 '21 at 08:57
  • I mean i just put those values to my calculator and got different answer: `e^(18×log 10) = 65659969.1373` – Gendozz Oct 15 '21 at 09:06
  • 1
    You need to use the *natural* logarithm. – Bathsheba Oct 15 '21 at 09:11