How do you debug math functions in your code???

Started by
6 comments, last by oliii 18 years, 4 months ago
Especially those w complicated formulaes... I HATE maths because it just made me lose about 2-3 months to find out that my math function was the problem. I'm pretty sure some of you are just looking at the result on the screen (like me) and if it's what they expected then fine my math function is full-proof. But problem I had was intersecting 3 planes. At a certain position it worked fine. At others I had weird results, but I never blamed my math function because it worked fine first. So I spend time looking at the wrong places in my code. I didn't test my math function because the values where saying nothing for me, there was no way I could validate my results. If I wwant to avoid this next time so If anyone got ideas.. I mean are you really taking the time to test your math functions ? How do you validate them ? Are you like me and are just hoping to use the good formulae for the task you must accomplish ?
Advertisement
Test it against a reference function. Somebody somewhere has already written code to find the intersection of 3 planes (probably lots of people). Find someone else that's done it, then test a few thousand random cases of theirs vs. yours and make sure they're the same.

But then, why not just use someone else's code that's already debugged? :-)



~BenDilts( void );
I use CPPUnit to test my math library. I even found several bugs as a result.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
A Good practice is to make a program that uses this math function but that generates diffrent planes and then tries to solve it.. Using random you could do this.

And then you could see for your self the errors that arise!
----------------------------

http://djoubert.co.uk
Thanks for your replies.

"test a few thousand random cases of theirs vs. yours and make sure they're the same"
Often when dealing with maths people will just say "find the intersection of 3 planes" and will not give away their code. Searching on google I just find math related sites, so I get a formulae or sometimes old C code.
In my case I wasn't able to find some code so I "translated" a big math formulae in code. Guess i'm not a good translator..

"But then, why not just use someone else's code that's already debugged? "
I would like this but often it will not work because of the configuration of their engine vs mine. For example, this guy may have used a right handed coordinate system, while yours is left-handed.


"I use CPPUnit to test my math library"
I don't know this.. is it included in VC++ ?

"make a program that uses this math function"
I guess debugging maths requires more time than what I thought

"Using random you could do this.And then you could see for your self the errors that arise!"
I agree, I'll be able to see errors like div. by 0. But how can I tell if the result of the formulae is good ? I need a reference.

My problem : lack of math reference. At least when doing math exercices in a school book you have the answers at the end. I would like the same here.
Write a test suite. I.e. a set of routines to test all your math routines. The best way I've found to do this is to write code that uses each of your routines, i.e. that calls each to generate results, then do something to test the results. But the test should be different, so you don't have the same mistake cancelling it out.

In simple cases it's a sinple test: to test a square root take the result and square it. To test sin calculate inverse sin. It's sometimes better to combine results to produse simpler tests. E.g. if you have both sin and cos functions to test you can do

bool TestSinCos(float angle)
{
float s = MySin(angle);
float c = MyCos(angle);
float d = s*s + c*c;
return abs(d - 1) < 0.0001;
}

This relies on the identity sin^2(t) + cost^(t) == 1 to verify both at once, using only multiply and add which are almost certain to be right (or if they're not you're in big trouble).

For more complex function involving e.g. vectors you need more complext tests, but the same principle applies - use tests that work differently from the functions so they're not going ot give false results. E.g. to test a normalisation function

v1 = Normalise(v);

You can vertify not only that length(v1) == 1 but also CrossProduct(v1, v) == 0, as this implies the vectors are parallel, and DotProduct(v1, v) > 0 that implies they're in the same direction.

Once your written your test functions write code to generate random numbers, vectors, etc. and call the test functions hundreds or thousands of times, logging errors (with inputs, in case errors only occur in rare cases).
John BlackburneProgrammer, The Pitbull Syndicate
I work developing fluid dynamics codes, coupling them with structural simulations to model the effects of fluids on structures and vice versa. I have had numerous occaisions where weeks were spent tracking down bugs which good testing would have found, that worked properly in most cases but failed in a select few.

I have a couple suggestions:

first of all, thoroughly testing your base functions is a must, but simply testing against other people's code has caused me problems before, since sometimes they exhibit the same type of errors as mine.

furthermore, testing several things together is a sure way to stack your errors up, particularly for the simple cases people usually test. your tests cases should be as robust as possible against generating false positives, since you will have to trust the result.

for example, in one of the previous posts, the example of sin(x)^2 + cos(x)^2 is used. this test does not descriminate between x being positive or negative, due to the squaring. Consequently, if your sin() function were to incorrectly generate the negative answer, it would still pass the test. The error might then show up in your matrix transformations, where rotations were appearing incorrectly (as transposes in this case). this would in turn lead you to change your (correct) matrix stuff because the sin test checked out, and suddenly all sorts of stuff breaks in other spots.

your tests should have analytical or experimental solutions and should cover the full range of cases where possible. furthermore, there should be variation in your test cases, so that special cases are not admitted accidentally. I had a problem with a ray-triangle intersection function that was incorrect. It passed many test cases, but failed in a few very specialized cases. to determine that it was at fault, i generated hundreds of thousands of random cases that I knew to be true, and hundreds of thousands of cases that i knew to be false and then made sure they all passed correctly (or failed within the limits of numerical precision).

so basically, always test, only test one thing at a time, only test cases you already know the answer for, and make sure your cases span the set of possible inputs.

james
do small increments of code. test. do more small increments of code. test.....

Which can be a pain building console games. Takes ages to debug crash bugs. Stop execution, change code, relaunch the application, go through menus, launch the game, hit breakpoints, test... With MSVC, edit and continue is a timesaver. So make sure you have a fast setup to test your code, in small portions, and introducing values that will likely break the function, no matter how improbable they are, like negative numbers in a square root. Make sure the case is handled gracefully, and the what would be the consequence of that event.

Never assume your code is bug free. Think hard of special cases before they happen. Think of div-by-zero, negative numbers, deviation due to FP innacuracies, infinities, and things like that. Check if you'll need a tolerance, and how big before it becomes a problem. When you hit the tolerance, it will probably trigger a special case, which you'll obviously need to test.

Everything is better with Metal.

This topic is closed to new replies.

Advertisement