aboutsummaryrefslogtreecommitdiffstats
path: root/src/data.c
diff options
context:
space:
mode:
authorPaul Eggert2019-08-24 15:46:31 -0700
committerPaul Eggert2019-08-24 15:55:09 -0700
commita050cf80f38e6b9b33745bc62b50dab43cac7a3a (patch)
tree163b1d1fb3b78db8672527d42c3afbd66a9313f3 /src/data.c
parent2f7ca4020e4f1e30b263758439dba55551f0675d (diff)
downloademacs-a050cf80f38e6b9b33745bc62b50dab43cac7a3a.tar.gz
emacs-a050cf80f38e6b9b33745bc62b50dab43cac7a3a.zip
Speed up % and mod with fixnum denom
* src/data.c (integer_remainder): New function. When the numerator is a bignum and the denominator is small, this function uses mpz_tdiv_ui, which should be faster than mpz_tdiv_r. (Frem, Fmod): Use it.
Diffstat (limited to 'src/data.c')
-rw-r--r--src/data.c100
1 files changed, 52 insertions, 48 deletions
diff --git a/src/data.c b/src/data.c
index cb25fce014a..1d9222e75a7 100644
--- a/src/data.c
+++ b/src/data.c
@@ -3055,58 +3055,67 @@ usage: (/ NUMBER &rest DIVISORS) */)
3055 return arith_driver (Adiv, nargs, args, a); 3055 return arith_driver (Adiv, nargs, args, a);
3056} 3056}
3057 3057
3058DEFUN ("%", Frem, Srem, 2, 2, 0, 3058/* Return NUM % DEN (or NUM mod DEN, if MODULO). NUM and DEN must be
3059 doc: /* Return remainder of X divided by Y. 3059 integers. */
3060Both must be integers or markers. */)
3061 (register Lisp_Object x, Lisp_Object y)
3062{
3063 CHECK_INTEGER_COERCE_MARKER (x);
3064 CHECK_INTEGER_COERCE_MARKER (y);
3065
3066 /* A bignum can never be 0, so don't check that case. */
3067 if (EQ (y, make_fixnum (0)))
3068 xsignal0 (Qarith_error);
3069
3070 if (FIXNUMP (x) && FIXNUMP (y))
3071 return make_fixnum (XFIXNUM (x) % XFIXNUM (y));
3072 else
3073 {
3074 mpz_tdiv_r (mpz[0],
3075 *bignum_integer (&mpz[0], x),
3076 *bignum_integer (&mpz[1], y));
3077 return make_integer_mpz ();
3078 }
3079}
3080
3081/* Return X mod Y. Both must be integers and Y must be nonzero. */
3082static Lisp_Object 3060static Lisp_Object
3083integer_mod (Lisp_Object x, Lisp_Object y) 3061integer_remainder (Lisp_Object num, Lisp_Object den, bool modulo)
3084{ 3062{
3085 if (FIXNUMP (x) && FIXNUMP (y)) 3063 if (FIXNUMP (den))
3086 { 3064 {
3087 EMACS_INT i1 = XFIXNUM (x), i2 = XFIXNUM (y); 3065 EMACS_INT d = XFIXNUM (den);
3066 if (d == 0)
3067 xsignal0 (Qarith_error);
3088 3068
3089 i1 %= i2; 3069 EMACS_INT r;
3070 bool have_r = false;
3071 if (FIXNUMP (num))
3072 {
3073 r = XFIXNUM (num) % d;
3074 have_r = true;
3075 }
3076 else if (eabs (d) <= ULONG_MAX)
3077 {
3078 mpz_t const *n = xbignum_val (num);
3079 bool neg_n = mpz_sgn (*n) < 0;
3080 r = mpz_tdiv_ui (*n, eabs (d));
3081 if (neg_n)
3082 r = -r;
3083 have_r = true;
3084 }
3090 3085
3091 /* If the "remainder" comes out with the wrong sign, fix it. */ 3086 if (have_r)
3092 if (i2 < 0 ? i1 > 0 : i1 < 0) 3087 {
3093 i1 += i2; 3088 /* If MODULO and the remainder has the wrong sign, fix it. */
3089 if (modulo && (d < 0 ? r > 0 : r < 0))
3090 r += d;
3094 3091
3095 return make_fixnum (i1); 3092 return make_fixnum (r);
3093 }
3096 } 3094 }
3097 else
3098 {
3099 mpz_t const *ym = bignum_integer (&mpz[1], y);
3100 bool neg_y = mpz_sgn (*ym) < 0;
3101 mpz_tdiv_r (mpz[0], *bignum_integer (&mpz[0], x), *ym);
3102 3095
3103 /* Fix the sign if needed. */ 3096 mpz_t const *d = bignum_integer (&mpz[1], den);
3104 int sgn_r = mpz_sgn (mpz[0]); 3097 mpz_t *r = &mpz[0];
3105 if (neg_y ? sgn_r > 0 : sgn_r < 0) 3098 mpz_tdiv_r (*r, *bignum_integer (&mpz[0], num), *d);
3106 mpz_add (mpz[0], mpz[0], *ym);
3107 3099
3108 return make_integer_mpz (); 3100 if (modulo)
3101 {
3102 /* If the remainder has the wrong sign, fix it. */
3103 int sgn_r = mpz_sgn (*r);
3104 if (mpz_sgn (*d) < 0 ? sgn_r > 0 : sgn_r < 0)
3105 mpz_add (*r, *r, *d);
3109 } 3106 }
3107
3108 return make_integer_mpz ();
3109}
3110
3111DEFUN ("%", Frem, Srem, 2, 2, 0,
3112 doc: /* Return remainder of X divided by Y.
3113Both must be integers or markers. */)
3114 (register Lisp_Object x, Lisp_Object y)
3115{
3116 CHECK_INTEGER_COERCE_MARKER (x);
3117 CHECK_INTEGER_COERCE_MARKER (y);
3118 return integer_remainder (x, y, false);
3110} 3119}
3111 3120
3112DEFUN ("mod", Fmod, Smod, 2, 2, 0, 3121DEFUN ("mod", Fmod, Smod, 2, 2, 0,
@@ -3119,12 +3128,7 @@ Both X and Y must be numbers or markers. */)
3119 CHECK_NUMBER_COERCE_MARKER (y); 3128 CHECK_NUMBER_COERCE_MARKER (y);
3120 if (FLOATP (x) || FLOATP (y)) 3129 if (FLOATP (x) || FLOATP (y))
3121 return fmod_float (x, y); 3130 return fmod_float (x, y);
3122 3131 return integer_remainder (x, y, true);
3123 /* A bignum can never be 0, so don't check that case. */
3124 if (EQ (y, make_fixnum (0)))
3125 xsignal0 (Qarith_error);
3126
3127 return integer_mod (x, y);
3128} 3132}
3129 3133
3130static Lisp_Object 3134static Lisp_Object