[PATCH v2 3/4] math: Optimize dbl-64 remainder implementation

Wilco Dijkstra Wilco.Dijkstra@arm.com
Mon Sep 29 18:26:14 GMT 2025


Hi Adhemerval,

+  uint64_t hx = asuint64 (x);
+  uint64_t hy = asuint64 (y);
+  uint64_t sx = hx >> 63;
+
+  hx &= UINT64_C (0x7FFFFFFFFFFFFFFF);
+  hy &= UINT64_C (0x7FFFFFFFFFFFFFFF);

hx &= ~SIGN_MASK?

+  /* |x| not finite or |y| is NaN or 0 */
+  if ((hx >= EXPONENT_MASK || (hy - 1) >= EXPONENT_MASK))
+    return (x * y) / ( x * y);

We can move this into the else below and just check hx:

+  /* |y| < DBL_MAX / 2 ? */
+  y = fabs (y);
+  if (__glibc_likely (hy < UINT64_C (0x7fe0000000000000)))

We can add hx < EXPONENT_MASK here to skip the NaN checks above
(the y == 0.0 case is handled correctly by fmod call).

+  /* Make sure x is not -0. This can occur only when x = p  and rounding
+     direction is towards negative infinity.  */
+  if (__glibc_unlikely (x == -0.0))
+    x = 0.0;

This still seems to work out badly - I did some experiments, this moves the
zero check to the case that requires it (after the first x - y):

          x -= y;
          if (x + x >= y)
            x -= y;
          else if (x == 0.0)
            x = 0.0;

This gives 5-15% improvements to throughput and latency for the
denormal and close exponent cases.

This is probably as good as it gets without merging fmod and remainder
into a shared implementation.

Cheers,
Wilco
 


More information about the Libc-alpha mailing list