Let's start with a simple quiz: 7/2 = ... . Of course is 3.5 but is this also true for code?

If you somehow use a non-fractional data type for storing the result, you will always get the result 3. And that should not surprise you.

int result = 7/2; //expression is 3

However, if you choose to use a fractional data type, things will change ...

double result = 7/2;

... or not. The value stored in the variable result is still 3 (actually 3.0 or something really close to 3.0 - since floating point data types store the approximation of a number).

Why is this happening?

Let's take a look at the expression, result = 7/2. There are two operators: / and =. Based on their precedence, the first evaluated is the division operator; it is a binary operator so, it has two operands. The general definition of the / operator in C# is:

public static TYPE1 operator /(TYPE2 op1, TYPE3 op2)<br />

In our case 7 and 2 need to be matched to TYPE2 and TYPE3. In most languages, the operators for primitive types are defined only for the same type of operands (TYPE2 = TYPE3). In this way, for n types n operator overloads have to be defined, otherwise it could go up to n2 overloads.

The compiler will try to match the operands with one of the operator signatures. In our case, both operands are integer so, it will call operator / (int, int) which returns int (!!). The expression on the right hand side (RHS) of = is evaluated as an int.

After that, the = operator will be evaluated. Because its RHS operand is an int, a conversion will be performed to double, in order to match the type of the left hand side of the operator. At this point, is to late to get the fractional part because it was already disposed. The final result will be an integer represented as a double.

The following drawing shows the abstract syntax tree and its evaluation for the previously mentioned expression.

In order to fix the problem, you need to explicitly state that a certain part of the expression must be evaluated as double. The best way to do this is to make one of the operands double. For example:

double r1 = 7.0/2;
double r2 = 7/2.0;
double r3 = 7.0/2.0;
double r4 = 7d/2d;
double r5 = ((double)5)/2; //This is not recommended but will work

In this above cases, the conversion node will be evaluated sooner, before any precision is lost, hence allowing you to get the expected result. The next image shows the AST for the expression double result = 7 / 3.0.

Understanding how an expression is evaluated is very important because non trivial statement can make your life harder. Take a look at the following examples and try to guess the results (r4 is similar to a bug we encountered).

double r1 = 7 / 2;
double r2 = 6.0 + 7 / 2;
double r3 = 5 / 2 + 7 / 2;
double r4 = DateTime.Now.Millisecond * (1000 / 3600);
double r5 = 6.5 / (1 / 2);
double r6 = 10.0 * (1 / 2);
double r7 = 11.0 * 1 / 2;