[cairo] _cairo_color_compute_shorts fails with FPU set to single precision

Behdad Esfahbod behdad at behdad.org
Wed Aug 30 00:45:41 PDT 2006

On Wed, 2006-08-30 at 02:00 -0400, Carl Worth wrote:
> So we need to tweak the computation very slightly in order to ensure
> that 1.0 maps correctly. The current implementation of
> _cairo_color_compute_shorts attempts a tweak by using the following
> computation instead:
> 	i = floor (f * (N+1-epsilon))
> In this particular case, we're mapping to a 16-bit integer so N is
> 65535. And in the current implementation the value for epsilon is
> 1e-5, (chosen as something near 1/65535 I suppose).

Not really.  1e-5 is actually a (1e-5/65536) epsilon.  It's just as you
said, very small yet representable in doubles.

> Behdad has cooked up some patches that attempt to address this by
> using a slightly different approach of:
> 	i = floor (f * ((N+1) * (1.0 - epsilon)))
> Where the code actually uses DBL_EPSILON as defined by float.h for its
> epsilon value, (or 1e-7 if DBL_EPSILON is not found in a system
> header). This seems like an improvement at first, but it won't
> actually help with the original bug report which was triggered by
> setting the FPU to single-precision mode at run time. So getting a
> compile-time constant based on what float.h advertises won't help I
> think.

Good point.  I ignored the question of how FPU was set to
single-precision in the first place.  In the back of my mind I assumed
that someone's using 32bit types as doubles on some weird platform.

> I'm open to suggestions on how to correctly fix this bug.
> One idea I have is to simply special case the one value we know is
> problematic:
> 	if (f == 1.0)
> 	    i = N;
> 	else
> 	    i = floor (f * (N+1));

I think this is way better than the current code and my proposal.

> The branch is certainly not lovely, but I'm hoping that this

Or better yet, use what Ali suggests.  Or even without a branch:

        int32_t i;
        i = f * 65536.0;
        i -= i == 65536;

> floating-to-fixed conversion for colors won't be a hot spot, (unlike
> the floating-to-fixed conversion of _cairo_fixed_from_double which is
> used much more often and is already a known hot spot for some
> architectures).
> Meanwhile, since we know we're dealing with non-negative values here,
> can't we just drop the floor() and rely on the rounding-toward-zero
> truncation mandated by the C specification?

I think we can.

> -Carl


"Commandment Three says Do Not Kill, Amendment Two says Blood Will Spill"
        -- Dan Bern, "New American Language"

More information about the cairo mailing list