149

In our code we have a double that we need to convert to an int.

double score = 8.6;
int i1 = Convert.ToInt32(score);
int i2 = (int)score;

Can anyone explain me why i1 != i2?

The result that I get is that: i1 = 9 and i2 = 8.

Wouter Dorgelo
  • 11,770
  • 11
  • 62
  • 80

5 Answers5

231

Because Convert.ToInt32 rounds:

Return Value: rounded to the nearest 32-bit signed integer. If value is halfway between two whole numbers, the even number is returned; that is, 4.5 is converted to 4, and 5.5 is converted to 6.

...while the cast truncates:

When you convert from a double or float value to an integral type, the value is truncated.

Update: See Jeppe Stig Nielsen's comment below for additional differences (which however do not come into play if score is a real number as is the case here).

Jon
  • 428,835
  • 81
  • 738
  • 806
  • 7
    Your link actually explains it best, and its not as simple as round vs truncate: Type: System.Int32 value, rounded to the nearest 32-bit signed integer. If value is halfway between two whole numbers, the even number is returned; that is, 4.5 is converted to 4, and 5.5 is converted to 6. – ericosg May 25 '12 at 12:18
  • @ericosg: Yeah, that would mask the difference if `score` were `8.5` instead of `8.6`. I updated the answer to include the quotes. Thanks for the input. – Jon May 25 '12 at 12:21
  • 9
    And if `score` is `NaN` or an infinity or finite but outside the range of `Int32`, then `Convert.ToInt32` will throw an exception. Cast will return an `int`, but you won'y know which one (in my implementation it's `Int32.MinValue`) because you're in `unchecked` context. (Should you be in `checked` context, the cast will throw an exception as well in these cases.) – Jeppe Stig Nielsen May 25 '12 at 12:41
  • @JeppeStigNielsen: Thanks for the input, I updated the answer to mention this too. – Jon May 25 '12 at 12:45
  • Nice. But I think the `Double` type number `10000000000.6` (ten billion point six) is a "real" number. Using a cast to `int` on that will give a strange result (unless you're in `checked` context, but you probably aren't). – Jeppe Stig Nielsen May 25 '12 at 13:15
19

Casting will ignore anything after the decimal point, so 8.6 becomes 8.

Convert.ToInt32(8.6) is the safe way to ensure your double gets rounded to the nearest integer, in this case 9.

neilgmacy
  • 549
  • 5
  • 13
  • 1
    Bonus question - what happens of if the value of the *double* is too large to push into the *int*? I.e. if it's higher than *int.MAX_VAL*? – Konrad Viltersten Sep 12 '16 at 12:47
  • 1
    @KonradViltersten Throws an exception _Value was either too large or too small for an Int32._ – Vamsi Jun 15 '17 at 05:52
12

you can round your double and cast ist:

(int)Math.Round(myDouble);
David
  • 4,027
  • 10
  • 50
  • 102
  • 6
    the question was now **how** to make `i1 == i2`. The question was about **why** they are not equal. Downvoted. – Adam Jun 13 '12 at 12:52
7

In the provided example your decimal is 8.6. Had it been 8.5 or 9.5, the statement i1 == i2 might have been true. Infact it would have been true for 8.5, and false for 9.5.

Explanation:

Regardless of the decimal part, the second statement, int i2 = (int)score will discard the decimal part and simply return you the integer part. Quite dangerous thing to do, as data loss might occur.

Now, for the first statement, two things can happen. If the decimal part is 5, that is, it is half way through, a decision is to be made. Do we round up or down? In C#, the Convert class implements banker's rounding. See this answer for deeper explanation. Simply put, if the number is even, round down, if the number is odd, round up.

E.g. Consider:

        double score = 8.5;
        int i1 = Convert.ToInt32(score); // 8
        int i2 = (int)score;             // 8

        score += 1;
        i1 = Convert.ToInt32(score);     // 10
        i2 = (int)score;                 // 9
Evdzhan Mustafa
  • 3,645
  • 1
  • 24
  • 40
1

ToInt32 rounds. Casting to int just throws away the non-integer component.