dd option of doing fuzzy equality tests.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@27958 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2009-02-23 08:57:49 +00:00
parent 26789c7a45
commit 8be39f3677
3 changed files with 123 additions and 29 deletions

View file

@ -36,6 +36,7 @@
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include "GNUstepBase/preface.h"
#include "Foundation/NSString.h"
#include "Foundation/NSGeometry.h"
@ -388,3 +389,109 @@ NSRectFromString(NSString* string)
}
}
/* Tests for equality of floats/doubles.
* WARNING assumes the values are in the standard IEEE format ...
* this may not be true on all systems, though afaik it is the case
* on all systems we target.
*
* We use integer arithmetic for speed, assigning the float/double
* to an integer of the same size and then converting any negative
* values to twos-complement integer values so that a simple integer
* comparison can be done.
*
* MAX_ULP specified the number of Units in the Last Place by which
* the two values may differ and still be considered equal. A value
* of zero means that the two numbers must be identical.
*
* The way that infinity is represented means that it will be considered
* equal to MAX_FLT (or MAX_DBL) unless we are doing an exact comparison
* with MAX_ULP set to zero.
*
* The implementation will also treat two NaN values as being equal, which
* is technically wrong ... but is it worth adding a check for that?
*/
#define MAX_ULP 0
static inline BOOL
almostEqual(CGFloat A, CGFloat B)
{
#if MAX_ULP == 0
return (A == B) ? YES : NO;
#else /* MAX_UPL == 0 */
#if defined(CGFLOAT_IS_DBL)
union {int64_t i; double d;} valA, valB;
valA.d = A;
valB.d = B;
#if GS_SIZEOF_LONG == 8
if (valA.i < 0)
{
valA.i = 0x8000000000000000L - valA.i;
}
if (valB.i < 0)
{
valB.i = 0x8000000000000000L - valB.i;
}
if (labs(valA.i - valB.i) <= MAX_ULP)
{
return YES;
}
#else /* GS_SIZEOF_LONG == 8 */
if (valA.i < 0)
{
valA.i = 0x8000000000000000LL - valA.i;
}
if (valB.i < 0)
{
valB.i = 0x8000000000000000LL - valB.i;
}
if (llabs(valA.i - valB.i) <= MAX_ULP)
{
return YES;
}
#endif /* GS_SIZEOF_LONG == 8 */
return NO;
#else /* DEFINED(CGFLOAT_IS_DBL) */
union {int32_t i; float f;} valA, valB;
valA.f = A;
if (valA.i < 0)
{
valA.i = 0x80000000 - valA.i;
}
valB.f = B;
if (valB.i < 0)
{
valB.i = 0x80000000 - valB.i;
}
if (abs(valA.i - valB.i) <= MAX_ULP)
{
return YES;
}
return NO;
#endif /* DEFINED(CGFLOAT_IS_DBL) */
#endif /* MAX_UPL == 0 */
}
BOOL
NSEqualRects(NSRect aRect, NSRect bRect)
{
return (almostEqual(NSMinX(aRect), NSMinX(bRect))
&& almostEqual(NSMinY(aRect), NSMinY(bRect))
&& almostEqual(NSWidth(aRect), NSWidth(bRect))
&& almostEqual(NSHeight(aRect), NSHeight(bRect))) ? YES : NO;
}
BOOL
NSEqualSizes(NSSize aSize, NSSize bSize)
{
return (almostEqual(aSize.width, bSize.width)
&& almostEqual(aSize.height, bSize.height)) ? YES : NO;
}
BOOL
NSEqualPoints(NSPoint aPoint, NSPoint bPoint)
{
return (almostEqual(aPoint.x, bPoint.x)
&& almostEqual(aPoint.y, bPoint.y)) ? YES : NO;
}