]> git.eshelyaron.com Git - emacs.git/commitdiff
Reduce size of integer product in timefns
authorPaul Eggert <eggert@cs.ucla.edu>
Wed, 10 Jul 2024 00:37:55 +0000 (02:37 +0200)
committerEshel Yaron <me@eshelyaron.com>
Thu, 11 Jul 2024 14:39:47 +0000 (16:39 +0200)
* src/timefns.c (emacs_gcd): New static function.
(ticks_hz_hz_ticks): Use it to reduce the size of the integer
product in the common case when converting from ns to ps.  For
that, we need to multiply t.ticks only by 10³, not multiply by
10¹² and then divide by 10⁹.  This avoids the need to use bignums
in a significant number of cases.

(cherry picked from commit 6ef052d9b23aef3f34d19e5d93d97884215d1465)

src/timefns.c

index 0c5f3bf3ff1e422fd6169cfdeed0e68e7c2d6fc6..0a34bda28c7bf58abbd39d1efb3b9a814a98bddf 100644 (file)
@@ -748,6 +748,15 @@ timespec_ticks (struct timespec t)
   return make_integer_mpz ();
 }
 
+/* Return greatest common divisor of positive A and B.  */
+static EMACS_INT
+emacs_gcd (EMACS_INT a, EMACS_INT b)
+{
+  for (EMACS_INT r; (r = a % b) != 0; a = b, b = r)
+    continue;
+  return b;
+}
+
 /* Convert T to a Lisp integer counting HZ ticks, taking the floor.
    Assume T is valid, but check HZ.  */
 static Lisp_Object
@@ -766,11 +775,22 @@ ticks_hz_hz_ticks (struct ticks_hz t, Lisp_Object hz)
        invalid_hz (hz);
 
       /* For speed, use intmax_t arithmetic if it will do.  */
-      intmax_t ticks;
-      if (FASTER_TIMEFNS && FIXNUMP (t.ticks) && FIXNUMP (t.hz)
-         && !ckd_mul (&ticks, XFIXNUM (t.ticks), XFIXNUM (hz)))
-       return make_int (ticks / XFIXNUM (t.hz)
-                        - (ticks % XFIXNUM (t.hz) < 0));
+      if (FASTER_TIMEFNS && FIXNUMP (t.ticks) && FIXNUMP (t.hz))
+       {
+         /* Reduce T.hz and HZ by their GCD, to avoid some intmax_t
+            overflows that would occur in T.ticks * HZ.  */
+         EMACS_INT ithz = XFIXNUM (t.hz), ihz = XFIXNUM (hz);
+         EMACS_INT d = emacs_gcd (ithz, ihz);
+         ithz /= d;
+         ihz /= d;
+
+         intmax_t ticks;
+         if (!ckd_mul (&ticks, XFIXNUM (t.ticks), ihz))
+           return make_int (ticks / ithz - (ticks % ithz < 0));
+
+         t.hz = make_fixnum (ithz);
+         hz = make_fixnum (ihz);
+       }
     }
   else if (! (BIGNUMP (hz) && 0 < mpz_sgn (*xbignum_val (hz))))
     invalid_hz (hz);