Debug vs Release Mode Nightmare [solved]

Started by
5 comments, last by JohnHurt 17 years, 5 months ago
Hi guys, This problem has got me tearing my hair out. Can anyone tell why this code (win32 console app) will work correctly in Debug mode, but not in Release mode in Visual Studio .NET 2003? In Release mode the condition which leads to the app printing "here" does not get met, even though mathematically it should be true. In debug mode it works fine. I've tried deleting all the intermediary files and rebuilding, and I've installed the latest service pack, but to no avail. I'd really appreciate someone shedding some light on this, because I really can't see it myself.

#include <stdlib.h>
#include <stdio.h>

#include <math.h>

///////////////////////////////////////////////////////////////////////////////////////
// gtVector - 3 dimensional vector
class gtVector
{
public:
	float x, y, z;

	// constructors
	gtVector();
	gtVector(const float &x, const float &y, const float &z);
	
	// other operations
	float Magnitude() const;
	gtVector Normalise() const;
};
///////////////////////////////////////////////////////////////////////////////////////

float gtVector::Magnitude() const 
{
	return sqrtf(x * x + y * y + z * z); 
}

gtVector gtVector::Normalise() const 
{
	float len = Magnitude();
	
	if ( len == 0.0f )
		return gtVector();
	return gtVector(x / len, y / len, z / len);
}

gtVector::gtVector() 
{ 
	x = 0.0f; 
	y = 0.0f; 
	z = 0.0f; 
}

gtVector::gtVector(const float &_x, const float &_y, const float &_z) 
{ 
	x = _x; 
	y = _y; 
	z = _z; 
}

int main()
{
	gtVector vNormal = gtVector(0,0,-55);
	vNormal = vNormal.Normalise();
	printf("%f\n", vNormal.z);

	if ( fabs(vNormal.z) == 1 )
	{
		printf("here\n");
	}
	
	system("pause");
	return 0;
}


[Edited by - JohnHurt on November 9, 2006 4:56:44 PM]
Advertisement
Checking a float for equality (len == 0.0f, fabs(vNormal.z) == 1)
won't work because of the limited precision of floats/doubles.
Use a compare with an epsilon instead.

E.g.

#define FLOAT_CMP_EPSILON 0.00000001f

inline bool FloatCmp(const float &a, const float &b)
{
if (a > b - FLOAT_CMP_EPSILON)
{
if (a < b + FLOAT_CMP_EPSILON)
{
return true;
}
}
return false;
}
You're working with floats, and these may be off by a tiny little amount. Don't compare the length to 1, but check if it's within a certain treshold of 1. I don't know how much it could be off, but it's probably not more than one millionth or such. I think. :)

EDIT: Got beaten to it. rating++ for the speed. ;)
Create-ivity - a game development blog Mouseover for more information.
Interesting. Thanks guys. But why does it allow you to do that in Debug, and not Release? Crazy.
Short answer: optimisations can lead to some inaccuracies. This is perfectly normal.

"Long" answer:
There is no accurate floating point representation of 1/55. And optimized version of
gtVector(x / len, y / len, z / len)
usually becomes:
float lenInv = 1 / len;
gtVector(x * len, y * len, z * len)
as multiplication is usually faster than division. That's why you loose precision, even when you theoretically shouldn't. Precission loss is always to be considered. Whole another question is wheater this loss is always the same, or is it more or less random.

Also:
Quote:Original post by deffer
I really recommend this article explaining in detail usage of /fp switch (Specify Floating-Point Behavior).
The correct way is something like this iirc:

inline bool float_equal( float a, float b ){    return fabsf( a - b ) <= std::max( 1.0f, std::max(a,b) ) * FLT_EPSILON;}
Thanks for everyone's quick help, it works now! I still have hair! Ratings++

This topic is closed to new replies.

Advertisement