1

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 ?

Community
  • 1
  • 1
A.Pissicat
  • 3,023
  • 4
  • 38
  • 93
  • "But the same code in C# give me a 19" did you step through the code in c# and write down the same results? – UKMonkey Oct 27 '17 at 10:39
  • 4
    Possible duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – user0042 Oct 27 '17 at 10:40
  • 3
    Casting a float to an int will get rid of anything after the decimal value, therefor, `18.999999947845936` will simply become `18`. You can use `std::round' to get proper rounding – xEric_xD Oct 27 '17 at 10:40
  • @xEric_xD in C# if you cast to an int it rounds down too... but doesn't touch on the difference between c++ & c# – UKMonkey Oct 27 '17 at 10:58
  • @user0042 the problem is close to the other topic, but is doesn't explain me why the same code in C++ and C# don't give same results – A.Pissicat Oct 27 '17 at 10:59
  • @A.Pissicat It might just be floating point rounding differences, have you checked the values of the floats before casting in both C# and C++? – xEric_xD Oct 27 '17 at 11:01
  • Which _same code_? Is there `static_cast` in C#? Use `std::round` and type `double` instead. – Ron Oct 27 '17 at 11:03
  • Indeed, do not perform a static cast from a floating point value without at least adding a bias to account for rounding errors. The compiler may choose to reorder your operations, so the error can even vary. – Ext3h Oct 27 '17 at 11:53

1 Answers1

1

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 floats) 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.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455