[cairo] Patch for comparing doubles against exact values
John Ellson
john.ellson at comcast.net
Fri Feb 8 14:08:30 PST 2008
Behdad Esfahbod wrote:
> 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.
>
Another scenario I've seen frequently in our code is where the variable
is initialiazed
to a floating point value, then compared later against that value to see
if it
has been changed. So rather than an arithmetic comparison we are
really doing a
logical one. The exact value isn't important, whats important is the
bit-wise equality.
It would be nice if it was possible to hint to the compiler that this
was our intent.
John
>
>
>> 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
>>
>
>
More information about the cairo
mailing list