Double.MaxValue for the whole is negative?

Why Double.MaxValue to an integral type result in a negative value, the smallest value of this type?

 double maxDouble = double.MaxValue; // 1.7976931348623157E+308 long maxDoubleLong = (long) maxDouble; // -9223372036854775808 

I would understand a compiler error if it is too large or an OverflowException at runtime, or if I use unchecked , that the conversion may not throw an exception, but the result becomes undefined and incorrect (negative).

It is also strange that the value of long.MinValue :

 bool sameAsLongMin = maxDoubleLong == long.MinValue; // true 

By the way, the same thing happens if I drop it to int :

 int maxDoubleInt = (int)maxDouble; // -2147483648 bool sameAsIntMin = maxDoubleInt == int.MinValue; // true 

If it tries to pass it to decimal , I get an OverflowException at runtime

 decimal maxDoubleDec = (decimal)maxDouble; // nope 

Update : it seems that Michael and Barr's answers hit a nail on the head, if I use checked explicitly, I get an OverflowException :

 checked { double maxDouble = double.MaxValue; // 1.7976931348623157E+308 long maxDoubleLong = (long) maxDouble; // nope } 
+21
casting c # type-conversion
Mar 31 '14 at 8:48
source share
3 answers

The C # language specification (version 5.0) states the following in 6.2.1 "Explicit Numeric Conversions" (emphasis added):

  • To convert from a float or double to an integral type, the processing depends on the context of the overflow check (§7.6.12) in which the conversion occurs:

    • In the tested context, the conversion is as follows:

      • If the operand value is NaN or infinite, a System.OverflowException is thrown.
      • Otherwise, the source operand is rounded to zero to the nearest integer value. If this integer value is within the destination type, then this value is the result of the conversion.
      • Otherwise, a System.OverflowException is thrown.
    • In an uncontrolled context, the conversion is always successful and is performed as follows.

      • If the operand value is NaN or infinite, the result of the conversion is an undefined value of the destination type.
      • Otherwise, the source operand is rounded to zero to the nearest integer value. If this integer value is within the destination type, then this value is the result of the conversion.
      • Otherwise, the result of the conversion is an undefined value of the destination type.

And in 7.6.12 "Verified and Unverified Operators"

For non-constant expressions (expressions that are evaluated at runtime) that are not included by any verified or unverified statements or statements, the overflow check context is not set by default if external factors (such as switches and compiler execution are environment configurations). Call the test score.

For conversions from double to decimal : "If the original value is NaN, infinity or too large to represent as a decimal number, a System.OverflowException is thrown." checked vs unchecked does not enter the game (only for integral operations).

+13
Mar 31 '14 at 8:59
source share

Perhaps not a complete answer, but the C # language specification (§6.2.1) says the following:

In an uncontrolled context, the conversion is always successful, and proceeds as follows.

• If the value of the operand is NaN or infinite, the result of the conversion is an unspecified value of the destination type.

• Otherwise, the source operand is rounded in the direction from zero to the nearest integer value. If this integer value is within the range of the destination type, then this value is the result of the conversion.

• Otherwise, the conversion result is an undefined value for the destination type.

(a main attention).

(Michael Burr answered at the same time as I did, and he also included information on the standard checked / unchecked context in C #, see comments below, so this answer is pretty much redundant.)

Edit 1: Note that if the conversion performed compile time (constant expression conversion), the rules are slightly different. Try changing the maxDouble variable with the const modifier. Then the C # compiler will be able to see the values, and for this you will need to explicitly specify unchecked .

Edit 2: In my version of the runtime (.NET 4.5 for Windows 8.1), the following code:

 double d1 = double.PositiveInfinity; double d2 = double.MaxValue; double d3 = 2.3e23; double d4 = double.NaN; double d5 = -2.3e23; double d6 = double.MinValue; double d7 = double.NegativeInfinity; Console.WriteLine((long)d1); Console.WriteLine((long)d2); Console.WriteLine((long)d3); Console.WriteLine((long)d4); Console.WriteLine((long)d5); Console.WriteLine((long)d6); Console.WriteLine((long)d7); 

gives:

  -9223372036854775808
 -9223372036854775808
 -9223372036854775808
 -9223372036854775808
 -9223372036854775808
 -9223372036854775808
 -9223372036854775808 

therefore, it turns out that the “unspecified value” is actually “always” MinValue for the destination type in this implementation.

+8
Mar 31 '14 at 8:59
source share

It seems that the default behavior here is unchecked , namely: if you did not explicitly specify checked , the overflow will not be detected:

  double maxDouble = double.MaxValue; // 1.7976931348623157E+308 long uncheckedMaxDoubleLong = (long)maxDouble; // -9223372036854775808 long checkedMaxDoubleLong = checked((long)maxDouble); // ** Overflow Exception 

In retrospect, trying to directly convert from double to long without checking or restricting input is not recommended at first because of two aspects:

  • numerical mismatch ranges / overflow potential
  • rounding considerations

So, it would be better to use Convert.ToInt64 here:

  var convertedDouble = Convert.ToInt64(maxDouble); // ** OverflowException 

Since this internally checks you checked and expresses an opinion on rounding, namely:

  return checked((long)Math.Round(value)); 
+2
Mar 31 '14 at 9:03
source share



All Articles