Biggest integer that can be stored in a double

Viewed 249401

What is the biggest "no-floating" integer that can be stored in an IEEE 754 double type without losing precision?

In other words, at would the follow code fragment return:

UInt64 i = 0;
Double d = 0;

while (i == d)
{
        i += 1; 
        d += 1;
}
Console.WriteLine("Largest Integer: {0}", i-1);
9 Answers

The largest integer that can be represented in IEEE 754 double (64-bit) is the same as the largest value that the type can represent, since that value is itself an integer.

This is represented as 0x7FEFFFFFFFFFFFFF, which is made up of:

  • The sign bit 0 (positive) rather than 1 (negative)
  • The maximum exponent 0x7FE (2046 which represents 1023 after the bias is subtracted) rather than 0x7FF (2047 which indicates a NaN or infinity).
  • The maximum mantissa 0xFFFFFFFFFFFFF which is 52 bits all 1.

In binary, the value is the implicit 1 followed by another 52 ones from the mantissa, then 971 zeros (1023 - 52 = 971) from the exponent.

The exact decimal value is:

179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368

This is approximately 1.8 x 10308.

It is true that, for 64-bit IEEE754 double, all integers up to 9007199254740992 == 2^53 can be exactly represented.

However, it is also worth mentioning that all representable numbers beyond 4503599627370496 == 2^52 are integers. Beyond 2^52 it becomes meaningless to test whether or not they are integers, because they are all implicitly rounded to a nearby representable value.

In the range 2^51 to 2^52, the only non-integer values are the midpoints ending with ".5", meaning any integer test after a calculation must be expected to yield at least 50% false answers.

Below 2^51 we also have ".25" and ".75", so comparing a number with its rounded counterpart in order to determine if it may be integer or not starts making some sense.

TLDR: If you want to test whether a calculated result may be integer, avoid numbers larger than 2251799813685248 == 2^51

depends on how flexible you are with the definition of "represented" and "representable" -

Despite what typical literature says, the integer that's actually "largest" in IEEE 754 double precision, without any bigint library or external function call, with a completely full mantissa, that is computable, storable, and printable is actually :

9,007,199,254,740,991 * 5 ^ 1074 (~2546.750773909... bits)

  4450147717014402272114819593418263951869639092703291
  2960468522194496444440421538910330590478162701758282
  9831782607924221374017287738918929105531441481564124
  3486759976282126534658507104573762744298025962244902
  9037796981144446145705102663115100318287949527959668
  2360399864792509657803421416370138126133331198987655
  1545144031526125381326665295130600018491776632866075
  5595837392240989947807556594098101021612198814605258
  7425791790000716759993441450860872056815779154359230
  1891033496486942061405218289243144579760516365090360
  6514140377217442262561590244668525767372446430075513
  3324500796506867194913776884780053099639677097589658
  4413789443379662199396731693628045708486661320679701
  7728916080020698679408551343728867675409720757232455
  434770912461317493580281734466552734375

I used xxhash to compare this with gnu-bc and confirmed it's indeed identical and no precision lost. There's nothing "denormalized" about this number at all, despite the exponent range being labeled as such.

Try it on ur own system if u don't believe me. (I got this print out via off-the-shelf mawk) - and you can get to it fairly easily too :

  1. one(1) exponentiation/power (^ aka **) op,
  2. one(1) multiplication (*) op,
  3. one (1) sprintf() call, and
  4. either one(1) of — substr() or regex-gsub() to perform the cleanup necessary

Just like the 1.79…E309 number frequently mentioned,

  • both are mantissa limited
  • both are exponent limited
  • both have ridiculously large ULPs (unit in last place)
  • and both are exactly 1 step from "overwhelming" the floating point unit with either an overflow or underflow to give you back a usable answer

Negate the binary exponents of the workflow, and you can have the ops done entirely in this space, then just invert it once more at tail end of workflow to get back to the side what we typically consider "larger",

but keep in mind that in the inverted 
exponent realm, there's no "gradual overflow"

— The 4Chan Teller

As others has noted, I will assume that the OP asked for the largest floating-point value such that all whole numbers less than itself is precisely representable.

You can use FLT_MANT_DIG and DBL_MANT_DIG defined in float.h to not rely on the explicit values (e.g., 53):

#include <stdio.h>
#include <float.h>

int main(void)
{
    printf("%d, %.1f\n", FLT_MANT_DIG, (float)(1L << FLT_MANT_DIG));
    printf("%d, %.1lf\n", DBL_MANT_DIG, (double)(1L << DBL_MANT_DIG));
}

outputs:

24, 16777216.0
53, 9007199254740992.0
Related