[cairo] Patch for comparing doubles against exact values
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).
"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