5

I have the following code:

#include <iostream>
#include <limits>

int main()
{
   std::cout << std::numeric_limits<unsigned long long>::digits10 << std::endl;
   return 0;
}
  • GCC 4.4 returns 19
  • MS VS 9.0 returns 18

Can someone please explain Why is there a difference between the two? I would have expected such a constant would be the same regardless of the compiler.

Rikardo Koder
  • 672
  • 9
  • 16
  • I no longer have an installation of VC9 but VC10 prints `19`, which is the expected value since `unsigned long long` is represented by 64 bits and thus its maximum value is `18,446,744,073,709,551,615`. – James McNellis May 08 '11 at 06:41
  • @James, that's where I'm lost: there are *20* digits in `18,446,744,073,709,551,615`, not 19. So why does `limit10` return 19 (or 18)? – Frédéric Hamidi May 08 '11 at 06:44
  • @James: http://msdn.microsoft.com/en-us/library/af6x78h6%28v=vs.80%29.aspx So in this situation msvc is at fault? – Rikardo Koder May 08 '11 at 06:44
  • @Frederic: Thats exactly what i'm getting stuck on, why not 20 digits? – Rikardo Koder May 08 '11 at 06:45
  • 1
    @Rikardo, maybe `limit10` is only meaningful for floating-point types? – Frédéric Hamidi May 08 '11 at 06:47
  • @Rikardo: The example on that page uses `__int64` (i.e. `signed long long`), so `18` is correct there (its range is –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807). – James McNellis May 08 '11 at 06:51
  • @James: still returns 19 for unsigned long long - what happens to the "1" ? – Rikardo Koder May 08 '11 at 06:53
  • 8
    @Frederic: `unsigned long long` can represent `9,999,999,999,999,999,999` (19 digits) but not `99,999,999,999,999,999,999` (20 digits). It can represent every 19 digit number but not every 20 digit number. [Sorry, I had commented earlier but I realized it was not entirely correct so I removed that comment.] – James McNellis May 08 '11 at 06:53

3 Answers3

10

If Visual C++ 2008 returns 18 for std::numeric_limits<unsigned long long>::digits10, it is a bug (I don't have Visual C++ 2008 installed to verify the described behavior).

In Visual C++ (at least for 32-bit and 64-bit Windows), unsigned long long is a 64-bit unsigned integer type and is capable of representing all of the integers between zero and 18,446,744,073,709,551,615 (264 - 1).

Therefore, the correct value for digits10 here is 19 because an unsigned long long can represent 9,999,999,999,999,999,999 (19 digits) but cannot represent 99,999,999,999,999,999,999 (20 digits). That is, it can represent every 19 digit number but not every 20 digit number.

When compiled with Visual C++ 2010, your program prints the expected 19.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 1
    why not 20 digits? 19 seems to miss 1 digit. how does one represent 18446744073709551615 with 19 digits? – Rikardo Koder May 08 '11 at 06:51
  • 1
    @Rikardo: `unsigned long long` can represent `9,999,999,999,999,999,999` (19 digits) but not `99,999,999,999,999,999,999` (20 digits). It can represent every 19 digit number but not every 20 digit number. – James McNellis May 08 '11 at 06:52
  • 5
    oooooooh. I see, so its an issue of infimum and supremum. Thanks! – Rikardo Koder May 08 '11 at 06:55
0

In general, the statement

I would have expected such a constant would be the same regardless of the compiler.

is not correct because the size of a type in C isn't fixed. The standard only mandates a minimum limit and compilers are free to use wider types. For example some weird compilers on a 32 or 64-bit computer may have CHAR_BIT = 9 and unsigned long long wouldn't be 64 bit any more, or it may use different 1's complement or some other number encodings. In short, the result may vary between compilers.

However in case that unsigned long long is a 64-bit type then it's definitely a bug. I've just checked and saw that the bug has been fixed in VS 2008. The correct value of 19 is returned

phuclv
  • 37,963
  • 15
  • 156
  • 475
0

numeric_limits::digits10 specifies the number of decimal digits to the left of the decimal point that can be represented without a loss of precision. So, I guess it will differ from compiler to compiler depending on their implementation detail.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 1
    You've just quoted the msdn docs, you have NOT provided an answer to the question, only added unrelated supposition. – Rikardo Koder May 08 '11 at 06:30
  • @Rikardo Koder: Well, If its a implementation detail of compiler it will differ for each compiler and well as you know floating point number are evil, you never can be sure of what accuracy each compiler is going to provide you. I guess this supposition is a reasoning enough for me to consider it as an answer. – Alok Save May 08 '11 at 06:33
  • 5
    unsigned long long is an integral type, not a floating point type. – Drew Hall May 08 '11 at 06:36