2

I am trying to write some operation overloading and assertion routine. I have a struct named Degree, and following is my code;

public struct Degree
{
    public float InnerValue;
    public Degree(float value)
    {
        InnerValue = value;
    }

    public static Degree operator +(Degree a, Degree b)
    {
        return new Degree(a.InnerValue + b.InnerValue);
    }
    public static void UnitTest()
    {
        Random rd = new Random();
        Degree lhs = rd.NextDegree(-(Degree)360, (Degree)360);
        Degree rhs = rd.NextDegree(-(Degree)360, (Degree)360);
        float f = rd.NextFloat(-100, 100);

        float temp = lhs.InnerValue + rhs.InnerValue;
        Debug.Assert((lhs + rhs).InnerValue == temp);
        Debug.Assert((lhs + rhs).InnerValue == lhs.InnerValue + rhs.InnerValue);
    }
}

my code seems looks very well for operator overloading, but assertion fails. The problem is only second Assert fails. I am unable to understand the reason for the same. Any help would be appreciated.

bhupendra patel
  • 3,139
  • 1
  • 25
  • 29
K eV
  • 21
  • 2
  • 6
    Where are `NextDegree` and the `-` operator? – Wai Ha Lee Jan 11 '16 at 16:49
  • Debug or Release? Try `lhs.InnerValue + rhs.InnerValue` -> `(float)(lhs.InnerValue + rhs.InnerValue)`. – user4003407 Jan 11 '16 at 16:51
  • 1
    Make sure to provide [MCVE] and check out issues with comparing cloat values like http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html, http://stackoverflow.com/questions/3874627/floating-point-comparison-functions-for-c-sharp – Alexei Levenkov Jan 11 '16 at 16:51
  • 3
    Check for `float` precision problems... Using `==` with floating points is risky. Use `Math.Abs(a - b) < min_float_value` instead of `a==b` for a quick test. – Vlad Jan 11 '16 at 16:52
  • @WaiHaLee - operator is also overloaded. i just skipped to writing that – K eV Jan 11 '16 at 16:56
  • 1
    @Vlad it just adds same two float variables. does floating point error can make some bugs in this code? – K eV Jan 11 '16 at 16:58
  • It's not connected to your problem, but maybe you write `Degree lhs = (Degree)rd.NextDouble(-360,360);` ? You will have only one Degree instance creation instead of 3 – Andrey Ischencko Jan 11 '16 at 16:58
  • 2
    I just ran the code and it *sometimes* passes the assertion. You can log the values e.g. with `Debug.WriteLine(string.Format("Left Side: {0} Right side: {1}", (lhs + rhs).InnerValue, (lhs.InnerValue + rhs.InnerValue)));` before the assert. This is definetly a `float`-precision / comparison problem. You should define an `epsilon` for the maximum error derivation and check if `Math.Abs( left_side - right_side) < epsilon`. – Maximilian Gerhardt Jan 11 '16 at 16:58
  • @PetSerAl Debug build. and what is different between two code? I think casting float variable to float variable has no meaning – K eV Jan 11 '16 at 16:59
  • @AndreyIschencko Extension method is defined in another class, and I just skipped to writing that class. – K eV Jan 11 '16 at 17:02
  • @KeV I have seen that before. Explicit cast `float` to `float` have their meaning. [link](http://community.sharpdevelop.net/forums/t/16465.aspx) – user4003407 Jan 11 '16 at 17:04
  • Woah okay, I take my comment back. If you print the absolute difference between them the difference is not negligable. (Log with `Debug.WriteLine(Math.Abs((lhs + rhs).InnerValue - (lhs.InnerValue + rhs.InnerValue)).ToString("F9"));` , e.g. outputs a difference as big as `0.000003815`) This seems far too big to be a small floating-point inaccuracy. – Maximilian Gerhardt Jan 11 '16 at 17:05
  • @PetSerAl That's interesting.... I'll try it. – K eV Jan 11 '16 at 17:05
  • @KeV It's not floating point "error" - it's a lack of absolute precision when dealing with binary floating point numbers. Although with whole numbers you _should_ not see any imprecision. To be safe, though, you should be comparing the difference to some arbitrarily low value (5 decimals?) rather than comparing absolute equality. – D Stanley Jan 11 '16 at 17:06
  • @MaximilianGerhardt Yes I know that comparing between two floating point variable is very dangerous, but it's just adding two same variables! can the result of adding two variable nondeterministic? – K eV Jan 11 '16 at 17:10
  • @PetSerAl Thanks it works. do you know why this happens? – K eV Jan 11 '16 at 17:10
  • @KeV yeah,i got it. Look, you firstly twice convert two ints to float and then create two Degree structs from these floats. One you negate, and then pass them to NextDegree method in which, as i assumed, you get two floats from two Degree methods , call random.nextdouble(float1,float2) and result put to new Degree. You do excessive conversions, as Degrees that you pass to nextDegree used only for passing value. Yes, it is more OOP way, but structs located on the stack and you should try to decrease number of their instances(and unnecessary calls as well). – Andrey Ischencko Jan 11 '16 at 17:11
  • @KeV I can only guess. Mathematical co-processor have higher precision than `float`. If you does not do explicit cast, then C# do calculation (addition and following comparison) entirely in co-processor without any intermediate truncating to `float` precision. Cast force truncating to `float` precision after addition. – user4003407 Jan 11 '16 at 17:35
  • @KeV [That](http://stackoverflow.com/q/8795550) seems related to your case. – user4003407 Jan 26 '16 at 17:39

0 Answers0