Tuesday 4 October 2011

Equality Among Floats

Well the Gladius Math library is coming along swimmingly and is taking shape very quickly now that we have the API outline almost complete.  (https://github.com/alankligman/gladius.math) Check out the wiki section.

After implementing the functions for 2 dimensional vectors [x,y] an interesting issue presented itself in the form of one glaring logic error and a unit test case issue.
  1. In our library we have a function, normalize(v1, result); which returns a unit vector with same direction as the given vector v1.  Result is the optional parameter in which we store the resulting vector.  Our code for this function was as follows:
// Return a Vector(result) with same direction as v having unit length
normalize: function( v, result ) {
   for( var i = 0, len = v.length; i < len; ++ i ) {
     result[i] = v[i] / len;
   }

   return result;
}
 Normalizing a vector is done by calculating its length and dividing each component by the length.  At first glance this code looks to be correct but we will quickly see how a small flaw ruins any results this function returns.
The problem caused by len = v.length. When we use v.length it is in fact returning the length of the array holding our vector, in this case [x,y] which would cause the function to just divide components by 2.
By changing the code to  len = vector.length(v); we open up the next set of problems.  Vector lengths (http://en.wikipedia.org/wiki/Euclidean_vector#Length)
  • By calculating the absolute length of vectors, some pretty unpleasant numbers can be returned as a result.  For example, when we call normalize() for the vector v1 = [12,-5] the resulting vector is expressed as v2 = [(12/13), (-5/13)].  This would not be a problem if a computer were able to show the results as the above expression but of course it can not and it will return a float with a set number of decimals.
  • This problem is compounded when you start to add other operations on the resulting vector which will continue to use the float representation of the result.  This is very evident in the unit tests:
 You can see above that the expected results and the computed results are identical up until the sixth digit after the decimal.  For all intensive purposes this is "equal", we now have to add an equal(v1, v2, e) function which will compare 2 vectors up to a set number of decimals for use to call them equal.

And that is what i'm working on now, as well as figuring out how to compare only a set number of decimals in the Qunit tests.

Saturday 1 October 2011

Unit Tests, Love Hate

Today I decided to try and get some unit tests created for the matrix functions which I implemented in yesterdays push (https://github.com/saecob/gladius.math/tree/Matrix2).

After spending some time identifying how unit tests are launched (index.html),


I created my own test script with the name Math.Matrix2.js which tests 2 x 2 matrices.

When I first ran the newly created test, I noticed that none of the coded implementations of any size matrix had been tested.  After further inspection, the matrix functions seem to be direct logic and code copies of all the implemented vector functions.

At first glance this doesn't seem to be such a big problem but I don't think that they correlate exactly.

The second issue which came about from these discoveries is, that at the moment I feel like I am implementing and adding functions arbitrarily not knowing if they will even be useful to someone using the library.

For example, we have a function rotate() which creates a rotation matrix given a Quaternion(http://en.wikipedia.org/wiki/Quaternion). This function is implemented under matrix4 functions, i.e 4x4 matrices.

The question is: Do we need this function for 2x2 and 3x3 matrices as well?

        // Construct a 2x2 rotation matrix from a Quaternion.
        rotate: function() {
            if( 0 === arguments.length ) {
                return Matrix( 4, that.matrix2.identity );
            } else if( 1 === arguments.length ) {
                var v = arguments[0];
                var r = v[0];
//              return Matrix( 4, [] );
            // Todo (Quaternion = w + xi + yj + zk)
            } else {
                return Matrix( 4, arguments );
            }
        }
    };


It seems like it would be a good idea to collaborate with the different areas of the project (Physics, Rendering, etc.) and come up with an interface with a list of functions, parameters, and return types/values so that everything put in Gladius.Math is useful as a library.