Help requested tracking down weird bug

JamesWildJamesWild USMember
edited May 2014 in General

I've been working on a vector maths library this weekend to get more experience working with T4 templates. Part of it involves generating vector types of different numbers of dimensions/base types/etc. so these don't have to be created by hand. It seems to work and I have passable test coverage.

Then began experimenting with implementing raytraceable convexes. To make it more generic, the vector types implement an interface so you can add/subtract/multiply/divide/get the sum of components without needing to know exactly what types you're dealing with, and from there things like dot product are implemented with generic extension methods using only this interface. These raytraceable convex classes also use this interface alone.

While writing tests for a particular convex in Xamarin Studio using NUnit, one test kept failing and I dug down into the implementation itself and got very, very confused. A particular sequence is evaluating in a way which is just wrong mathematically:
<br /> var closest = ray.Start.Add( ray.Normal.Multiply( along ) );<br /> Where:<br /> ray.Start is: Vector3{ X: 8, Y: 10, Z: 6 }<br /> ray.Normal is: Vector3{ X: -0.5828235, Y: -0.7082412, Z: -0.3983857 }<br /> along is: 14.13531<br /> The result is: Vector3{ X: -8.821217, Y: -10.71945, Z: -6.029692 }<br />

This is quite clearly wrong; 8 + 14 * -0.58 is nowhere near -8.8, but I cannot see why it is evaluating like this. The mathematical operations themselves have test coverage, if I extract the values and the calculation out into a separate test, it comes out as the expected value, so I have no idea how to reproduce this bug, so there's no point in putting it on the tracker yet.

This test passes on Visual Studio 2013. (Result: Vector3{ X: -0.2383909, Y: -0.01120949, Z: 0.3686943 })

There are no external dependencies.

I've branched specifically for this:

The test is SUNRUSE.Geometry.RoundTests.EntryButStopsBeforeOrigin.

To run on Visual Studio, comment out the reference to NUnit.Framework in the source code file for the test and uncomment the using directives which map NUnit's attributes to MSTEST's.

Can anyone please try reproducing this bug and hopefully post some pointers on what might be causing it?

Thank you.


  • JamesWildJamesWild USMember
    edited May 2014

    Just came back to this and I can fix it by splitting the line going wrong into two statements, which should be equivalent but are not under Mono:

    <br /> var closest = ray.Start.Add( ray.Normal.Multiply( along ) );<br />
    <br /> var offset = ray.Normal.Multiply( along );<br /> var closest = ray.Start.Add( offset );<br />
    Looks like a Mono bug to me, but I still can't pin down exactly why this is so.

  • JamesWildJamesWild USMember

    According to DotPeek, the difference when compiled (optimizations are off) is as follows:

    <br /> float multiply1 = VectorExtensions.Dot<TVector>(new TVector().Subtract(ray.Start), ray.Difference) / ray.Length;<br /> TVector vector1 = ray.Start;<br /> // ISSUE: explicit reference operation<br /> // ISSUE: variable of a reference type<br /> TVector&amp; local1 = @vector1;<br /> vector1 = ray.Normal;<br /> TVector to = vector1.Multiply(multiply1);<br /> // ISSUE: explicit reference operation<br /> float num1 = VectorExtensions.Magnitude<TVector>((^local1).Add(to));<br />
    <br /> float multiply1 = VectorExtensions.Dot<TVector>(new TVector().Subtract(ray.Start), ray.Difference) / ray.Length;<br /> TVector to1 = ray.Normal.Multiply(multiply1);<br /> float num1 = VectorExtensions.Magnitude<TVector>(ray.Start.Add(to1));<br />

    Looks to me as though the CIL which doesn't work is assigning vector1, getting a reference to it, overwriting vector1, and then using the reference as though vector1 hasn't changed.

  • JasonAwbreyJasonAwbrey USInsider, University, Developer Group Leader mod

    file a bug -

Sign In or Register to comment.