[PATCH 2/3] math: Optimize dbl-64 remainder implementation
Wilco Dijkstra
Wilco.Dijkstra@arm.com
Thu Sep 11 21:02:32 GMT 2025
Hi Adhemerval,
+ uint64_t hx = asuint64 (x);
+ uint64_t hy = asuint64 (y);
+ uint64_t sx = hx & UINT64_C (0x8000000000000000);
We below change, could become sign = hx >> 63;
+ hx &= UINT64_C (0x7FFFFFFFFFFFFFFF);
+ hy &= UINT64_C (0x7FFFFFFFFFFFFFFF);
+
+ /* |y| == 0 or |x| not finite or |y| is NaN */
+ if (hy == 0
+ || (hx >= EXPONENT_MASK || hy > EXPONENT_MASK))
Surely (hy - 1) >= EXPONENT_MASK to remove the hy == 0 check.
+ return NAN;
Since NAN returns a float NaN, wouldn't C99 nan("") be better?
+ /* |y| < DBL/MAX / 2 ? */
+ if (hy < UINT64_C (0x7fdfffffffffffff))
+ x = __ieee754_fmod (x, y + y);
Can use hy <=, but hy < UINT64_C (0x7fe0000000000000) is a simpler constant
on various targets.
+ if ((hx - hy) == 0)
+ return 0.0 * x;
Is this strictly required? I think the code below will also return 0.0 with sign of
original x, or does the correction for rounding mode make it fail? Does
remainder (x, x) return a different sign of zero than remainder (x + x , x)?
If it is needed, placing if (hx == hy) before the fmod call would be better.
+ x = fabs (x);
+ y = fabs (y);
+
+ /* |y| < 2 * DBL_MIN */
+ if (hy < UINT64_C (0x20000000000000))
{
+ if (x + x > y)
{
+ x -= y;
+ if (x + x >= y)
+ x -= y;
}
}
+ else
+ {
+ double y_half = y * 0.5;
+ if (x > y_half)
+ {
+ x -= y;
+ if (x >= y_half)
+ x -= y;
+ }
+ }
Since these branches may be fairly hard to predict, it's worth checking whether
this works out better:
x = (x >= y) ? x - y : x;
x = ((x + x) >= y) ? x - y : x;
You can always start with x >= y and only use (x + x) or y * 0.5 for the 2nd part.
In either case, we can remove the if (hy < UINT64_C (0x20000000000000)) by adding
an else after the fmod to handle the case of large y.
+ hx = asuint64 (x);
+ /* Make sure x is not -0. This can occur only when x = p and rounding
+ direction is towards negative infinity. */
+ if (hx == UINT64_C (0x8000000000000000))
+ hx = 0;
+ return asdouble (hx ^ sx);
Isn't this equivalent to:
if (__glibc_unlikely (x == 0.0))
x = 0.0;
return sx ? -x : x;
That avoids the float-int-float roundtrip and large constants, so that might be faster
overall.
Cheers,
Wilco
More information about the Libc-alpha
mailing list