Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why double can store bigger numbers than unsigned long long?

The question is, I don't quite get why double can store bigger numbers than unsigned long long. Since both of them are 8 bytes long, so 64 bits.

Where in unsigned long long, all 64 bits are used in order to store a value, on the other hand double has 1 for sign, 11 for exponent and 52 for mantissa. Even if 52 bits, which are used for mantissa, will be used in order to store decimal numbers without floating point, it still has 63 bits ...

BUT LLONG_MAX is significantly smaller than DBL_MAX ...

Why?

like image 206
denis631 Avatar asked May 05 '15 12:05

denis631


2 Answers

The reason is that unsigned long long will store exact integers whereas double stores a mantissa (with limited 52-bit precision) and an exponent.

This allows double to store very large numbers (around 10308) but not exactly. You have about 15 (almost 16) valid decimal digits in a double, and the rest of the 308 possible decimals are zeroes (actually undefined, but you can assume "zero" for better understanding).
An unsigned long long only has 19 digits, but every single of them is exactly defined.

EDIT:
In reply to below comment "how does this exactly work", you have 1 bit for the sign, 11 bits for the exponent, and 52 bits for the mantissa. The mantissa has an implied "1" bit at the beginning, which is not stored, so effectively you have 53 mantissa bits. 253 is 9.007E15, so you have 15, almost 16 decimal digits to work with.
The exponent has a sign bit, and can range from -1022 to +1023, which is used to scale (binary shift left or right) the mantissa (21023 is around 10307, hence the limits on range), so very small and very large numbers are equally possible with this format.
But, of course, all numbers that you can represent only have as much precision as will fit into the matissa.

All in all, floating point numbers are not very intuitive, since "easy" decimal numbers are not necessarily representable as floating point numbers at all. This is due to the fact that the mantissa is binary. For example, it is possible (and easy) to represent any positive integer up to a few billion, or numbers like 0.5 or 0.25 or 0.0125, with perfect precision.
On the other hand, it is also possible to represent a number like 10250, but only approximately. In fact, you will find that 10250 and 10250+1 are the same number (wait, what???). That is because although you can easily have 250 digits, you do not have that many significant digits (read "significant" as "known" or "defined").
Also, representing something seemingly simple like 0.3 is also only possible approximately, even though 0.3 isn't even a "big" number. However, you can't represent 0.3 in binary, and no matter what binary exponent you attach to it, you will not find any binary number that results in exactly 0.3 (but you can get very close).

Some "special values" are reserved for "infinity" (both positive and negative) as well as "not a number", so you have very slightly less than the total theoretical range.

unsigned long long on the other hand, does not interprete the bit pattern in any way. All numbers that you can represent are simply the exact number that is represented by the bit pattern. Every digit of every number is exactly defined, no scaling happens.

like image 80
Damon Avatar answered Oct 22 '22 11:10

Damon


IEEE754 floating point values can store a larger range of numbers simply because they sacrifice precision.

By that, I mean that a 64-bit integral type can represent every single value in its range but a 64-bit double cannot.

For example, trying to store 0.1 into a double won't actually give you 0.1, it'll give you something like:

0.100000001490116119384765625

(that's actually the nearest single precision value but the same effect will apply for double precision).


But, if the question is "how do you get a larger range with fewer bits available to you?", it's simply that some of those bits are used to scale the value.

Classic example, let's say you have four decimal digits to store a value. With an integer, you can represent the numbers 0000 through 9999 inclusive. The precision within that range is perfect, you can represent every integral value.

However, let's go floating point and use the last digit as a scale so that the digits 1234 actually represent the number 123 x 104.

So now your range is from 0 (represented by 0000 through 0009) through 999,000,000,000 (represented by 9999 being 999 x 109).

But you cannot represent every number within that range. For example, 123,456 cannot be represented, the closet you can get is with the digits 1233 which give you 123,000. And, in fact, where the integer values had a precision of four digits, now you only have three.

That's basically how IEEE754 works, sacrificing precision for range.

like image 37
paxdiablo Avatar answered Oct 22 '22 10:10

paxdiablo