adarsh
adarsh

Reputation: 165

How can C print a super-large number?

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

Answers (3)

Solomon Slow
Solomon Slow

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

chux
chux

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

cremno
cremno

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

Related Questions