Reputation: 313
there is one little thing making me puzzle in c# :)
Here is my variables & results:
decimal a1 = 0.2M;
decimal a2 = 1.0M;
a1 - a2 = -0.8
float b1 = 0.2F;
float b2 = 1.0F;
b1 - b2 = -0.8
double c1 = 0.2;
double c2 = 1.0;
c1 - c2 = -0.8
double x1 = 0.2F;
double x2 = 1.0F;
x1 - x2 = -0.799999997019768
Decimal - result is as expected for me, knowing that they work in base 10 notations.
Float - Surprised me, knowing it works on base 2 notation it actually shows result as if it worked as base 10 notation with out loosing precision.
Double c - Same thing as for Float.
Double x - shows result that I would expect for Float to take place.
The Question is what's going on with Float, Double 'c' and 'x' groups? Why Double 'x' group lost its precision while Float group actually calculated in base 10 notation giving so to speak "expected" result from calculation? Wondering why declaring number types of Double x group as F so drastically changed its out come?
for what it worth I would only expect Decimal group give me '-0.8' result and all others some thing to '-0.799999997019768'.
looks like I'm missing some link of understanding that takes place in how calculation was taking care of.
Upvotes: 1
Views: 929
Reputation: 272
There is a longstanding source of programmer confusion in C# that the language spec allows most intermediate operations on floating-point values to be carried out with extra precision. Compilers often do this in order to speed things up, because many processors are faster that way. I don't know the specific details well (someone who does can feel free to correct me if I'm wrong), but it seems likely that the calculations in the b
section are using this extra precision.
In the x
group, the double
variables already have the extra precision, but putting a float
-type constant into them may well be causing the compiler to behave subtly differently, leading to the less-precise results. Since the doubles are already slightly off from where they should be, the full double
precision is simply carrying the error forward.
Ultimately, floating-point precision in C# is very much not something to be explicitly relied upon, as the compiler has a lot of leeway to adjust things slightly as it chooses, however it thinks will optimize best, as long as it provides the minimum amount of precision spelled out in the spec.
Oh, and none of this has anything to do with base 2.
Upvotes: 0
Reputation: 564403
First off - this has nothing to do with base 2 vs. base 10. All of your values are represented using base 10. Base 2 is not used whatsoever in this code.
looks like I'm missing some link of understanding that takes place in how calculation was taking care of.
Both float
and double
using a floating point representation for numbers, which is not 100% accurate. When you display the value, there is rounding taking place. Since float
has inherently less precision, it's rounded to fewer decimal points, which can make it "appear" more accurate in some cases (even though it's actually less precise).
In your case, the reason the "x" group and the "c" group display differently is that you're declaring your x1 and x2 variables like so:
double x1 = 0.2F;
double x2 = 1.0F;
This is, effectively, the same as doing:
float temp = 0.2f;
double x1 = temp; // Convert from float to double, which has a loss of precision
temp = 1f;
double x2 = temp; // Convert from float to double, which has a loss of precision
As such, x1
and x2
do not have exactly the same values as c1
and c2
. This is causing even more loss of precision, which later, when the subtraction occurs, is enough that the printing doesn't round anymore.
A good article to read if you want to truly understand this is What Every Computer Scientist Should Know About Floating-Point Arithmetic. Most common programming languages use similar representations for floating point numbers, so the issues are fairly universal.
Upvotes: 5