From 3c0cdb365ae2bb9a21948c081de69356263112eb Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 10 Jul 2024 02:37:55 +0200 Subject: [PATCH 08/17] Reduce size of integer product in timefns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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. --- src/timefns.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/timefns.c b/src/timefns.c index 0c5f3bf3ff1..0a34bda28c7 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -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); -- 2.34.1