aboutsummaryrefslogtreecommitdiffstats
path: root/src/floatfns.c
diff options
context:
space:
mode:
authorPaul Eggert2018-09-03 18:37:40 -0700
committerPaul Eggert2018-09-03 18:50:34 -0700
commitfe042e9d15da7863b5beb4c2cc326a62d2c7fccb (patch)
tree84fac8f99c678667e01d69d5e2ef17f4c8e8e275 /src/floatfns.c
parent40f8ade7c81ab6f99537691ae00d2d42069bdb20 (diff)
downloademacs-fe042e9d15da7863b5beb4c2cc326a62d2c7fccb.tar.gz
emacs-fe042e9d15da7863b5beb4c2cc326a62d2c7fccb.zip
Speed up (+ 2 2) by a factor of 10
Improve arithmetic performance by avoiding bignums until needed. Also, simplify bignum memory management, fixing some unlikely leaks. This patch improved the performance of (+ 2 2) by a factor of ten on a simple microbenchmark computing (+ x 2), byte-compiled, with x a local variable initialized to 2 via means the byte compiler could not predict: performance improved from 135 to 13 ns. The platform was Fedora 28 x86-64, AMD Phenom II X4 910e. Performance also improved 0.6% on ‘make compile-always’. * src/bignum.c (init_bignum_once): New function. * src/emacs.c (main): Use it. * src/bignum.c (mpz): New global var. (make_integer_mpz): Rename from make_integer. All uses changed. * src/bignum.c (double_to_bignum, make_bignum_bits) (make_bignum, make_bigint, make_biguint, make_integer_mpz): * src/data.c (bignum_arith_driver, Frem, Flogcount, Fash) (expt_integer, Fadd1, Fsub1, Flognot): * src/floatfns.c (Fabs, rounding_driver, rounddiv_q): * src/fns.c (Fnthcdr): Use mpz rather than mpz_initting and mpz_clearing private temporaries. * src/bignum.h (bignum_integer): New function. * src/data.c (Frem, Fmod, Fash, expt_integer): * src/floatfns.c (rounding_driver): Use it to simplify code. * src/data.c (FIXNUMS_FIT_IN_LONG, free_mpz_value): Remove. All uses removed. (floating_point_op): New function. (floatop_arith_driver): New function, with much of the guts of the old float_arith_driver. (float_arith_driver): Use it. (floatop_arith_driver, arith_driver): Simplify by assuming NARGS is at least 2. All callers changed. (float_arith_driver): New arg, containing the partly converted value of the next arg. Reorder args for consistency. All uses changed. (bignum_arith_driver): New function. (arith_driver): Use it. Do fixnum-only integer calculations in intmax_t instead of mpz_t, when they fit. Break out mpz_t calculations into bignum_arith_driver. (Fquo): Use floatop_arith_driver instead of float_arith_driver, since the op is known to be valid. (Flogcount, Fash): Simplify by coalescing bignum and fixnum code. (Fadd1, Fsub1): Simplify by using make_int.
Diffstat (limited to 'src/floatfns.c')
-rw-r--r--src/floatfns.c44
1 files changed, 13 insertions, 31 deletions
diff --git a/src/floatfns.c b/src/floatfns.c
index 77e20d5640b..2f33b8652b2 100644
--- a/src/floatfns.c
+++ b/src/floatfns.c
@@ -270,11 +270,8 @@ DEFUN ("abs", Fabs, Sabs, 1, 1, 0,
270 { 270 {
271 if (mpz_sgn (XBIGNUM (arg)->value) < 0) 271 if (mpz_sgn (XBIGNUM (arg)->value) < 0)
272 { 272 {
273 mpz_t val; 273 mpz_neg (mpz[0], XBIGNUM (arg)->value);
274 mpz_init (val); 274 arg = make_integer_mpz ();
275 mpz_neg (val, XBIGNUM (arg)->value);
276 arg = make_integer (val);
277 mpz_clear (val);
278 } 275 }
279 } 276 }
280 277
@@ -360,20 +357,10 @@ rounding_driver (Lisp_Object arg, Lisp_Object divisor,
360 { 357 {
361 if (EQ (divisor, make_fixnum (0))) 358 if (EQ (divisor, make_fixnum (0)))
362 xsignal0 (Qarith_error); 359 xsignal0 (Qarith_error);
363 mpz_t d, q; 360 int_divide (mpz[0],
364 mpz_init (d); 361 *bignum_integer (&mpz[0], arg),
365 mpz_init (q); 362 *bignum_integer (&mpz[1], divisor));
366 int_divide (q, 363 return make_integer_mpz ();
367 (FIXNUMP (arg)
368 ? (mpz_set_intmax (q, XFIXNUM (arg)), q)
369 : XBIGNUM (arg)->value),
370 (FIXNUMP (divisor)
371 ? (mpz_set_intmax (d, XFIXNUM (divisor)), d)
372 : XBIGNUM (divisor)->value));
373 Lisp_Object result = make_integer (q);
374 mpz_clear (d);
375 mpz_clear (q);
376 return result;
377 } 364 }
378 365
379 double f1 = FLOATP (arg) ? XFLOAT_DATA (arg) : XFIXNUM (arg); 366 double f1 = FLOATP (arg) ? XFLOAT_DATA (arg) : XFIXNUM (arg);
@@ -417,20 +404,15 @@ rounddiv_q (mpz_t q, mpz_t const n, mpz_t const d)
417 if (abs_r1 < abs_r + (q & 1)) 404 if (abs_r1 < abs_r + (q & 1))
418 q += neg_d == neg_r ? 1 : -1; */ 405 q += neg_d == neg_r ? 1 : -1; */
419 406
420 mpz_t r, abs_r1; 407 mpz_t *r = &mpz[2], *abs_r = r, *abs_r1 = &mpz[3];
421 mpz_init (r); 408 mpz_tdiv_qr (q, *r, n, d);
422 mpz_init (abs_r1);
423 mpz_tdiv_qr (q, r, n, d);
424 bool neg_d = mpz_sgn (d) < 0; 409 bool neg_d = mpz_sgn (d) < 0;
425 bool neg_r = mpz_sgn (r) < 0; 410 bool neg_r = mpz_sgn (*r) < 0;
426 mpz_t *abs_r = &r; 411 mpz_abs (*abs_r, *r);
427 mpz_abs (*abs_r, r); 412 mpz_abs (*abs_r1, d);
428 mpz_abs (abs_r1, d); 413 mpz_sub (*abs_r1, *abs_r1, *abs_r);
429 mpz_sub (abs_r1, abs_r1, *abs_r); 414 if (mpz_cmp (*abs_r1, *abs_r) < (mpz_odd_p (q) != 0))
430 if (mpz_cmp (abs_r1, *abs_r) < (mpz_odd_p (q) != 0))
431 (neg_d == neg_r ? mpz_add_ui : mpz_sub_ui) (q, q, 1); 415 (neg_d == neg_r ? mpz_add_ui : mpz_sub_ui) (q, q, 1);
432 mpz_clear (r);
433 mpz_clear (abs_r1);
434} 416}
435 417
436/* The code uses emacs_rint, so that it works to undefine HAVE_RINT 418/* The code uses emacs_rint, so that it works to undefine HAVE_RINT