I donβt see how you declare your variables, but assigning to static values ββassigned to variables makes these variables of type double , not float . And, as you know, the double type has more precision than the float .
Here is the test:
var x = 0.00023569075; var dx = -0.000235702712; Console.WriteLine(x.GetType());
And, of course, when adding two double and float result is double , so the first condition returns true :
Console.WriteLine(x+dx+1f < 1f); //returns true Console.WriteLine(x+dx+1f); //returns 0.999999988038
But when you throw it on a float , truncation occurs, and the result is no longer correct, so your second condition returns false :
Console.WriteLine((float)(x+dx+1f) < 1f); //returns false Console.WriteLine((float)(x+dx+1f)); //returns 1
UPDATE: When your variables are float , truncation occurs here. Remember that the maximum precision of the float is only 7 digits, and you assign numbers with a much larger number of digits, so truncation occurs and leads to inaccurate results that you observe.
In the original question, here's how the values ββare truncated:
float x = 0.00023569075f; float dx = -0.000235702712f; Console.WriteLine(x); //0.0002356907 last digit lost Console.WriteLine(dx); //-0.0002357027 last two digits lost Console.WriteLine((x + dx)); //-1.196167E-08 Console.WriteLine((x + dx + 1f)); //1
The reason why the last result 1 should be obvious. The result of adding x and dx is -1.196167E-08 ( -0.00000001196167 ), which has 7 digits and can fit into a float . Now adding 1 makes it 0.99999998803833 , which has 14 digits and cannot fit in a float , so it is truncated and rounded to 1 when stored in a float .
The same thing happens in your update 2. The value -2.98023224E-08f has 9 digits, so it is truncated to -2.980232E-08 ( -0.00000002980232 ). Again adding 1 to the fact that it is 0.99999997019768 , which is truncated and rounded to 1 :
float a = -2.98023224E-08f; Console.WriteLine(a);
UPDATE 2 . Chris commented that the calculation is performed with higher accuracy, which is absolutely correct, but this does not explain the results, which should not be affected. Yes a + 1f calculation is performed with greater accuracy, but since both operands are float , the result of the calculation is then automatically discarded to float . Manually the result of the result float should be redundant and should not change the result. More importantly, this does not force the calculation to be performed with float precision. Yes, we still get the following results:
Console.WriteLine(a + 1f);
Thanks to a good discussion with Chris and a lot of tests on different machines, I think I better understand what is happening.
When we read:
Floating point operations can be performed with greater precision than the type of operation result.
Here we are talking not only about calculations (addition in our example), but also about comparison (less than in our example). Thus, in the second line above, all a + 1f < 1f is performed with greater accuracy: adding the value -2.98023224E-08f ( -0.0000000298023224 ) to 1 leads to 0.9999999701976776 , which then compares with 1f and, obviously, returns true :
Console.WriteLine(a + 1f < 1f);
At no time does casting on float happen, because the result of the comparison is bool .
In the first line, we simply print the result of calculating a+1f , and since both operands are float , the result is automatically discarded to float , which truncates it and is rounded to 1 :
Console.WriteLine(a + 1f);
Now the big question is the third line. This time, an excellent drop causes the result of the calculation to be reset to a float, which truncates and rounds it to 1 , and then compares it with 1f . The comparison is still performed with greater accuracy, but now it does not matter, since the casting has already changed the calculation result:
Console.WriteLine((float)(a + 1f) < 1f);
Thus, the actuation leads to the fact that two operations (addition and comparison) are performed separately. Without casting, the following steps: add, compare, print. With casting, steps: add, cast, compare, print. Both operations are still performed with greater accuracy, because casting cannot affect this.
Perhaps Visual Studio says casting is redundant because it does not take into account whether operations will be performed with greater precision or not.