Reputation: 3285
I'm working in C++ with Visual Studio.
I got a strange case. There is my code (simplified version) :
Point GetPoint(/*parameters*/)
{
float Ax = 149; //Value depending on parameters
float Ay = 20;
float Bx = 29;
float By = 19;
double pAB = (Ay - By) / (Ax - Bx);
double Sx = Cx;
double Sy = pAB * (Cx - Ax) + Ay;
// Sy = (20 - 19) / (149 - 29) * (29 - 149) + 20.0
// => Sy = 1 / 120 * -120 + 20
// => Sy = -1 + 20
return new Point(static_cast<int>(Sx), static_cast<int>(Sy));
}
I expected that Sy = 19 but instead my point value is 18. I started the debugger to understand and I found this :
(Ay - By) / (Ax - Bx) = 0.00833333284
(20.0 - 19.0) / (149.0 - 29.0) = 0.0083333333333333332
pAB = 0.0083333337679505348
And :
(20.0 - 19.0) / (149.0 - 29.0) * (29.0 - 149.0) + 20.0 = 19
Sy = 18.999999947845936
Final cast set my point to 18 (sy < 19). But the same code in C# give me a 19. Why theses difference ? And how can I get a 19 ?
Upvotes: 1
Views: 111
Reputation: 171167
C++ and C# are different languages, with different rules and different compilers. Since floating point is inexact by definition, any subtle difference can result in the different values you see.
I don't know the C# rules at all, but in C++, notice that while you have typed pAB
as double
, you're actually computing its value in float
(because Ax
, Ay
, Bx
, By
are all float
s) and only after that is the value promoted to a double
. In other words, you do not gain any precision here by using double
. Maybe the C# rules are different here, no idea.
Anyway, if you make sure pAB
is computed in double
, you get exact values with these particular numbers: [live example], compared to [the unchanged code].
Making sure the double
value is actually computed in double
is probably the correct solution here. Nevertheless, since floating point is inexact and could "fail" for you with other values, I suggest using std::round
instead of casting to int
if you want rounding behaviour.
Upvotes: 1