- Add function equalsByUlp to test for spacing between floating point numbers.

- Allow difference of 1 ULP in fast_atof tests (as that is still correct). Note that this only fixes part of the fast_atof test, the whole tests still fails on 64-bit because test_strtol still fails (that looks more like a real bug).


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@4179 dfc29bdd-3216-0410-991c-e03cc46cb475
master
cutealien 2012-06-05 11:46:37 +00:00
parent 366c0e48b5
commit 833ad991dd
6 changed files with 43 additions and 7 deletions

View File

@ -1,5 +1,7 @@
Changes in 1.8 (??.??.2011) Changes in 1.8 (??.??.2011)
- new function equalsByUlp to test for spacing between floating point numbers.
- speedup for collada writing. - speedup for collada writing.
- speedup for xml-writing. - speedup for xml-writing.

View File

@ -303,8 +303,7 @@ inline f32 strtof10(const char* in, const char** out = 0)
*/ */
inline const char* fast_atof_move(const char* in, f32& result) inline const char* fast_atof_move(const char* in, f32& result)
{ {
// Please run this regression test when making any modifications to this function: // Please run the regression test when making any modifications to this function.
// https://sourceforge.net/tracker/download.php?group_id=74339&atid=540676&file_id=298968&aid=1865300
result = 0.f; result = 0.f;
if (!in) if (!in)

View File

@ -188,6 +188,36 @@ namespace core
{ {
return (a + tolerance >= b) && (a - tolerance <= b); return (a + tolerance >= b) && (a - tolerance <= b);
} }
//! We compare the difference in ULP's (spacing between floating-point numbers, aka ULP=1 means there exists no float between).
//\result true when numbers have a ULP <= maxUlpDiff AND have the same sign.
inline bool equalsByUlp(f32 a, f32 b, int maxUlpDiff)
{
// Based on the ideas from Bruce Dawson on
// http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/
// When floats are interpreted as integers the two nearest possible float numbers differ just
// by one integer number. Also works the other way round, an integer of 1 interpreted as float
// is for example the smallest possible float number.
int ia = *reinterpret_cast<int*>(&a);
int ib = *reinterpret_cast<int*>(&b);
// Different signs, we could maybe get difference to 0, but so close to 0 using epsilons is better.
if ( (ia >> 31 != 0) != (ib >> 31 != 0) )
{
// Check for equality to make sure +0==-0
if (a == b)
return true;
return false;
}
// Find the difference in ULPs.
int ulpsDiff = abs_(ia - ib);
if (ulpsDiff <= maxUlpDiff)
return true;
return false;
}
#if 0 #if 0
//! returns if a equals b, not using any rounding tolerance //! returns if a equals b, not using any rounding tolerance
inline bool equals(const s32 a, const s32 b) inline bool equals(const s32 a, const s32 b)

View File

@ -90,7 +90,9 @@ static bool testCalculation_atof(const char * valueString)
logTestString("\n String '%s'\n New fast %.40f\n Old fast %.40f\n atof %.40f\n", logTestString("\n String '%s'\n New fast %.40f\n Old fast %.40f\n atof %.40f\n",
valueString, newFastValue, oldFastValue, atofValue); valueString, newFastValue, oldFastValue, atofValue);
bool accurate = fabs(newFastValue - atofValue) <= fabs(oldFastValue - atofValue); const f32 diffNew = fabs(newFastValue - atofValue) ;
const f32 diffOld = fabs(newFastValue - atofValue) ;
bool accurate = diffNew <= diffOld || equalsByUlp(diffNew, diffOld, 1);
if(!accurate) if(!accurate)
logTestString("*** ERROR - less accurate than old method ***\n\n"); logTestString("*** ERROR - less accurate than old method ***\n\n");
@ -275,5 +277,8 @@ bool test_strtol(void)
bool fast_atof(void) bool fast_atof(void)
{ {
return test_fast_atof() && test_strtol(); bool ok = true;
ok &= test_fast_atof() ;
ok &= test_strtol();
return ok;
} }

View File

@ -1,4 +1,4 @@
Tests finished. 1 test of 1 passed. Tests finished. 1 test of 1 passed.
Compiled as DEBUG Compiled as DEBUG
Test suite pass at GMT Sun Jun 3 18:56:35 2012 Test suite pass at GMT Sun Jun 3 20:56:51 2012

View File

@ -56,10 +56,10 @@ bool octree()
if (q3levelmesh) if (q3levelmesh)
{ {
scene::ISceneNode* q3node = smgr->addOctreeSceneNode(q3levelmesh->getMesh(0)); scene::ISceneNode* q3node = smgr->addOctreeSceneNode(q3levelmesh->getMesh(0));
q3node->setPosition(core::vector3df(-1350,-130,-1400)); q3node->setPosition(core::vector3df(-1350,-130,-1400));
scene::ITriangleSelector * selector = scene::ITriangleSelector * selector =
smgr->createOctreeTriangleSelector(q3levelmesh->getMesh(0), q3node, 128); smgr->createOctreeTriangleSelector(q3levelmesh->getMesh(0), q3node, 128);
meta->addTriangleSelector(selector); meta->addTriangleSelector(selector);
selector->drop(); selector->drop();