[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