Reputation: 165
How can this code print such a large number? I have tried it on Ubuntu 14.04 (gcc 4.8.2). It does not work the same on MS Windows with any compiler (even MinGW, which is called "gcc for Windows"). Why?
#include <stdio.h>
#include <math.h>
int main()
{
printf("%.0f\n",pow(2,500));
}
Ubuntu output:
3273390607896141870013189696827599152216642046043064789483291368096133796404
674554883270092325904157150886684127560071009217256545885393053328527589376
Windows output:
3273390607896141900000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
(The line break is added for clarity only.)
Upvotes: 4
Views: 356
Reputation: 27115
This is not a new answer, but a slightly different spin on what others have already said:
The difference is not in the pow()
function: The difference is in the printf()
function. Ubuntu printf() is printing the exact decimal value of pow(2,500)
. The Windows printf() is printing an approximation that is correct to 17 decimal digits.
Both implementations are, in some sense, correct; but I would say that the Windows printf() is more correct. Here's why:
If you care about more than 17 digits of precision, then you should not be using double
.
In general, the result of most double computations is only correct in the first 17 digits. (pow(2, n)
is a very special case where the answer is exactly correct for any n in range.) By printing the exact decimal value of very large doubles, the Ubuntu library is fooling you; Suppose you have
double a = ...;
double b = ...;
double c = a*b;
printf("%f", c);
You don't want to know the exact value of c
because, for most a
and b
, c
is not equal to a*b
: It's only an approximation of a*b--an approximation that's accurate to about 17 significant digits.
If you need more than 17 digits of precision, then you should be using an extended-precision math library like GMP (https://gmplib.org/)
Upvotes: 0
Reputation: 153367
As hinted by OP and commented by @user300234, 2^500
is a 501 bit number, but that is not the issue here.
pow(2,500)
returns a double
, about 3.27e150
, which is typically a binary64. This type supports about 15 - 17 decimal digits of precision. So for numbers near 3.27e150
, printing more that 17 digits of significance is usually not important. It is well smaller than DBL_MAX
which may be about 1.798e308
.
The trick here is that pow(2,500)
is exactly representable as a floating point double
(binary64). This may give the illusion that a double
has hundreds of bits of precision - it does not.
The 2 different compilations handle conversion of double
to text in different ways, once 17 or so digits are printed - this is allowable by the C spec. The minimum number of correct digits is DBL_DECIMAL_DIG
- likely 17 on both systems.
Consider printing the next greater double
. Although the next double could be printed with 150 or so digits, typically these additional digits way pass DBL_DECIMAL_DIG
are simply noise for many applications.
// 2 ^ 500
327339060789614 187001318969682759915221664...
// next
327339060789614 259685191399243448970154045...
Upvotes: 7
Reputation: 4927
The Microsoft Visual C Run-Time Library (msvcrt.dll
), also used by MinGW, only supports up to 17 digits of precision, since this is enough to uniquely identify a (IEEE 754) double
.
But good news: your code compiled with VS2015 CTP4 produces the same output as your Ubuntu example. And if you're using MinGW-w64, you can define __USE_MINGW_ANSI_STDIO
as 1
before including <stdio.h>
or via -D
compiler option for the same output.
Upvotes: 4