[cairo] Patch for comparing doubles against exact values

Behdad Esfahbod behdad at behdad.org
Fri Feb 8 13:16:41 PST 2008

On Fri, 2008-02-01 at 21:56 -0500, Antoine Azar wrote:
> Hey all,
> here's a patch that fixes a "bug" where we'd compare double values 
> with == 0. or == 1.

Many of those cases are not bugs.  And definitely a single NEARLY_ZERO
definition doesn't work for them all.  Each individual case needs
justification and reasoning, and finally, there's some non-negligible
overhead to NEARLY_ZERO that needs justification as well.

> We already had a macro NEARLY_ZERO that compared a value with +/- 
> 1/65536, I renamed it to IS_NEARLY_ZERO and added another one 
> IS_EQUAL_TO to compare to any value.

So, we use a double-width float, but we ignore anything more granular
than 1/65536?  Sounds stupid to me.

There are two different things involved here.  One case can use
NEARLY_ZERO, the other can't.  And those two are:

  - Values with an absolute scale.  Most values in device space fall
into this category.  A line with width < 1e-4 in device units is most
probably negligible.  Or our rasterizer will ignore it anyway.

  - Values with arbitrary scale.  Most values in user space fall into
this category.  A line width of 1e-8 is quite significant if the user
has a scale of 1e+10...

The first change in your patch is wrong because of the above
distinction.  Ignoring all rotations smaller than 1/65536 is plain
wrong.  Because error (displacement) caused by that ignorance can be
arbitrarily large, depending on the ctm.

When comparing two numbers, things get a bit more delicate.  It's almost
always Ok to use a NEARLY_EQUAL() macro like this:

#define NEARLY_EQUAL(a,b) (fabs((a)-(b)) < MIN(fabs(a),fabs(b))/65536)

What this is doing, is that by dividing the different by the smaller
magnitude, it's making the error a value with an absolute scale.
However, the above check is often too expensive to be useful.

One always has to consider what they are gaining by the check passing.

> I encountered this bug when out of laziness, I scaled my 
> transformation matrix by 10, then reset it by scaling by 1/10 
> (instead of using get/set functions). That resulted in 0.99999 values 
> in the matrix instead of 1, and made the difference between going the 
> pixman route or the win32 route (and a 3x performance difference).

> Best,
> Antoine


"Those who would give up Essential Liberty to purchase a little
 Temporary Safety, deserve neither Liberty nor Safety."
        -- Benjamin Franklin, 1759

More information about the cairo mailing list