3

I have noticed that the conversion from double to long changes the value when the number to be converted is large, even if it is well below the max value of a long. For example, does someone can explain me why this conversion does not work as expected:

Convert.ToInt64(600000000000040000d)
// Return => 600000000000039936
Convert.ToInt64(600000000000040000L)
// Return => 600000000000040000

This cause some trouble in my formulas... Thanks.

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Corabox
  • 157
  • 10
  • 1
    From [the documentation for `double`](https://learn.microsoft.com/en-us/dotnet/api/system.double?view=netframework-4.8): " A Double value has up to 15 decimal digits of precision". You are using 19 digits. – Matthew Watson Oct 08 '19 at 09:59

3 Answers3

5

Well, double has mantissa of 52 bits only (see https://en.wikipedia.org/wiki/Double-precision_floating-point_format for details); that's why double can represent precise integer values up to 2**53 - 1 == 9007199254740991. However,

 600000000000040000 > 9007199254740991

that's why rounding errors are inevitable:

  double d = 600000000000040000d;

  long l = (long)d;

  double d2 = l;

  Console.WriteLine($"{d:r} : {l} : ({d == d2 ? "Equal" : "Different"})");

Outcome:

  6.0000000000004E+17 : 600000000000039936 : Equal

You can try decimal instead of double (esp. if you are working with financial data):

  decimal d = 600000000000040000m; // m suffix

  long l = (long)d;

  decimal d2 = l;

  Console.WriteLine($"{d} : {l} : ({d == d2 ? "Equal" : "Different"})");

Outcome:

  600000000000040000 : 600000000000040000 : Equal
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • That's exactly what I was looking for. Decimal resolved my problem but, more important, I understand the reason of this behavior. Thanks. – Corabox Oct 08 '19 at 11:55
1

I hope this helps :

When you convert a double or float value to an integral type, this value is rounded towards zero to the nearest integral value. If the resulting integral value is outside the range of the destination type, the result depends on the overflow checking context. In a checked context, an OverflowException is thrown, while in an unchecked context, the result is an unspecified value of the destination type.

Source : https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/explicit-numeric-conversions-table

Note: Long is an integral type it is Int64: In C# What's the difference between Int64 and long?

Additionally, float and double are types with floating-point. They are stored in memory differently How are floating point numbers stored in memory?

Wikipedia: https://en.wikipedia.org/wiki/Single-precision_floating-point_format

Sergii Zhuravskyi
  • 4,006
  • 5
  • 18
  • 26
1

I hope this helps you more.

// Double to long
           double av = 600000000000040000L;
            long lg = (long)av;
            long g1 = Convert.ToInt64(av);
// long to Double
            double dbl = (double)g1;
            double d = Convert.ToDouble(g1);
Inam Abbas
  • 468
  • 3
  • 8