summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2024-07-10 02:37:55 +0200
committerPaul Eggert <eggert@cs.ucla.edu>2024-07-11 16:01:41 +0200
commit6ef052d9b23aef3f34d19e5d93d97884215d1465 (patch)
tree0de5e670df5d238a0dde0b49559a23f705a29ae0 /src
parent5e8a38ecb2a78c0e318892683dc0195084197c57 (diff)
Reduce size of integer product in timefns
* 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.
Diffstat (limited to 'src')
-rw-r--r--src/timefns.c30
1 files 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);