JCarter
JCarter

Reputation: 267

Precise whole number calculation with double

Consider following:

double x = 87974894654657d;
double y = 76216354532345d;
double a = x * y;
Console.WriteLine(a.ToString("n0"));

BigInteger x1 = new BigInteger(87974894654657);
BigInteger y1 = new BigInteger(76216354532345);
BigInteger a1 = x1 * y1;
Console.WriteLine(a1.ToString("n0"));

Output:

6.705.125.760.945.040.000.000.000.000
6.705.125.760.945.040.955.511.380.665

Is there a way to let double calculate the result properly? BigIntegers work fine, but are much slower than the floating point types. I'm using double instead of long because I'm working with extremely large numbers.

Upvotes: 1

Views: 174

Answers (4)

Christoph Wider
Christoph Wider

Reputation: 66

It seems the decimal type is a little bit faster than the BigInteger type.

        Stopwatch stopwatch = new Stopwatch();

        stopwatch.Restart();
        double x = 87974894654657d;
        double y = 76216354532345d;
        double a = x * y;
        stopwatch.Stop();
        Console.WriteLine(a.ToString("n0") + " (" + stopwatch.Elapsed.TotalMilliseconds.ToString("0.000") + "ms)");

        stopwatch.Restart();
        BigInteger x1 = new BigInteger(87974894654657);
        BigInteger y1 = new BigInteger(76216354532345);
        BigInteger a1 = x1 * y1;
        stopwatch.Stop();
        Console.WriteLine(a1.ToString("n0") + " (" + stopwatch.Elapsed.TotalMilliseconds.ToString("0.000") + "ms)");

        stopwatch.Restart();
        decimal x2 = 87974894654657M;
        decimal y2 = 76216354532345M;
        decimal a2 = x2 * y2;
        stopwatch.Stop();
        Console.WriteLine(a2.ToString("n0") + " (" + stopwatch.Elapsed.TotalMilliseconds.ToString("0.000") + "ms)");

And here the output:

6.705.125.760.945.040.000.000.000.000 (0,002ms)

6.705.125.760.945.040.955.511.380.665 (0,044ms)

6.705.125.760.945.040.955.511.380.665 (0,030ms)

UPDATE:

With an iteration of 10 million the performance between the data types is even better seen:

double: 6.705.125.760.945.040.000.000.000.000 (24,558ms)

BigInteger: 6.705.125.760.945.040.955.511.380.665 (1623,420ms)

decimal: 6.705.125.760.945.040.955.511.380.665 (478,333ms)

Upvotes: 0

amit dayama
amit dayama

Reputation: 3326

Just executed

     Console.WriteLine(DateTime.Now.Second+" "+DateTime.Now.Millisecond+"");
     BigInteger x1 = new BigInteger(87974894654657);
   BigInteger y1 = new BigInteger(76216354532345);
   BigInteger a1 = x1 * y1;
  Console.WriteLine(a1.ToString("n0"));
    Console.WriteLine(DateTime.Now.Second+" "+DateTime.Now.Millisecond+"");

    Console.WriteLine(DateTime.Now.Second+" "+DateTime.Now.Millisecond+"");
    double x = 87974894654657d;
  double y = 76216354532345d;
  double a = x * y;
   Console.WriteLine(a.ToString("n0"));
    Console.WriteLine(DateTime.Now.Second+" "+DateTime.Now.Millisecond+"");

and got this result:

4 216

6,705,125,760,945,040,955,511,380,665

4 216

4 216

6,705,125,760,945,040,000,000,000,000

4 216

There wasn't a delay of even 1 millisecond.

Upvotes: 0

user1793963
user1793963

Reputation: 1335

Try this code:

        double d = 6705125760945040955511380665d;
        Console.WriteLine(d.ToString("n0"));

The output will be 6.705.125.760.945.040.000.000.000.000. A double can represent very large values, but it cannot do it precisely. That's because it uses an exponent, a bit like adding 10^n. If you used decimals instead of binary numbers and used 4 digits you could store the number 5000000 like this: 05|06 => 5*10^6. The largest number you can store this way is 99|99 => 99 * 10 ^ 99, which is a huge number. But you cannot accurately store the number 123456, you can only approximate it: 12|04 => 120000.

If you want precision, don't use floating point numbers like float or double, use decimal or BigInteger instead.

Upvotes: 1

Thane Plummer
Thane Plummer

Reputation: 10208

For the output you are looking for (with "extremely large numbers") you will be constrained to use either BigInteger or decimal types.

double x = 87974894654657d;
double y = 76216354532345d;
double a = x * y;
a.Dump();


decimal xd = 87974894654657m;
decimal yd = 76216354532345m;
decimal b = xd * yd;
b.Dump();

Output:

6.70512576094504E+27
6705125760945040955511380665

Upvotes: 1

Related Questions