views:

205

answers:

5

I have a double value that equals 1.212E+25

When I throw it out to text I do myVar.ToString("0000000000000000000000")

The problem is even if I do myVar++ 3 or 4 times the value seems to stay the same.

Why is that?

+3  A: 

That is because the precision of a double is not sufficient. It simply can't hold that many significant digits.

It will not fit into a long, but probably into a Decimal.

But... do you really need this level of precision?

norheim.se
Making it a long would do it then?
Jon
A `long` is a 64 bit signed integer, and the value 1.2E25 is to large to fit in it. (the maximum value is 9,223,372,036,854,775,807 = 2^63 - 1)
Andreas Brinck
isnt the size of a double 1.7E +/- 308 (15 digits) http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx
Dimitar
@Dimitar: Yes, the *range* allows up to 10^308... but with a precision of only 15 digits, how is a 25-digit number incremented by 1 going to make a difference?
Jon Skeet
@Dimitar No one has claimed otherwise
Andreas Brinck
@Jon: Ahh I see, I misunderstood the problem. Thanks!
Dimitar
+1  A: 

You may want to read the Floating-Point Guide to understand how doubles work.

Basically, a double only has about 16 decimal digits of precision. At a magnitude of 10^25, an increase of 1.0 is below the threshold of precision and gets lost. Due to the binary representation, this may not be obvious.

Michael Borgwardt
+2  A: 

To expand on the other answer the smallest increase you can make to a double is one Unit in the Last Place, or ULP, as double is a floating point type then the size of an ULP changes, at 1E+25 it will be about 1E+10.

as you can see compared to 1E+10 incrementing by 1 really might as well be adding nothing. which is exactly what double will do, so it wouldnt matter if you tried it 10^25 times it still won't increase unless you try to increase by at least 1 ULP

if incrementing by an ULP is useful you can do this by casting the bits to long and back here is a quick extension method to do that

  public static double UlpChange(this double val, int ulp)
  {
    if (!double.IsInfinity(val) && !double.IsNaN(val))
    {
      //should probably do something if we are at max or min values 
      //but its not clear what
      long bits = BitConverter.DoubleToInt64Bits(val);
      return BitConverter.Int64BitsToDouble(bits + ulp);
    }
    return val;
  }
jk
A: 

The smallest increment that'll work is 2^30+1 which will actually increment the double by 2^31. You can test this kind of thing easily enough with LINQPad:

double inc = 1.0;
double num = 1.212e25;
while(num+inc == num) inc*=2;

inc.Dump(); //2147483648 == 2^31
(num+inc == num).Dump(); //false due to loop invariant
(num+(inc/2.0) == num).Dump();//true due to loop invariant
(num+(inc/2.0+1.0) == num).Dump();//false - 2^30+1 suffices to change the number
(num+(inc/2.0+1.0) == num + inc).Dump();//true - 2^30+1 and 2^31 are equiv. increments
((num+(inc/2.0+1.0)) - num == inc ).Dump();//true - the effective increment is 2^31

Since a double is essentially a binary number with limited precision, that means that the smallest possible increment will itself always be a power of two (this increment can be determined directly from the bit-pattern of the double, but it's probably clearer to do so with a loop as above since that's portable across float, double and other floating point representations (which don't exist in .NET).

Eamon Nerbonne
+1  A: 

double (Double) holds about 16 digits of precision and long (Int64) about 18 digits.

Neither of these appear to have sufficient precision for your needs.

However decimal (Decimal) holds up to 30 digits of precision. Although this appears to be great enough for your needs I'd recommend caution in case your requirement grows even larger. In that case you may need a third party numeric library.

Related StackOverflow entries are:
http://stackoverflow.com/questions/25375/how-can-i-represent-a-very-large-integer-in-net
http://stackoverflow.com/questions/176775/big-integers-in-c

WooWaaBob