diff options
| author | Tom Tromey | 2018-07-07 23:42:10 -0600 |
|---|---|---|
| committer | Tom Tromey | 2018-07-12 22:12:28 -0600 |
| commit | 3dea8f8f53f81a1d15a55c9e3c87a7eade7ca273 (patch) | |
| tree | 1f543cc1ccfe3552011f899d8f8e132ee9c7c276 /src/data.c | |
| parent | d0fac17abdf6883bbf82b1752988db38d05282e6 (diff) | |
| download | emacs-3dea8f8f53f81a1d15a55c9e3c87a7eade7ca273.tar.gz emacs-3dea8f8f53f81a1d15a55c9e3c87a7eade7ca273.zip | |
Make % and mod handle bignums
* src/data.c (Frem, Fmod): Handle bignums.
* src/lisp.h (CHECK_INTEGER_COERCE_MARKER): New macro.
* test/src/data-tests.el (data-tests-check-sign)
(data-tests-%-mod): New tests.
Diffstat (limited to 'src/data.c')
| -rw-r--r-- | src/data.c | 112 |
1 files changed, 97 insertions, 15 deletions
diff --git a/src/data.c b/src/data.c index 7ded8366e32..ac74ff5547f 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -3073,13 +3073,47 @@ Both must be integers or markers. */) | |||
| 3073 | { | 3073 | { |
| 3074 | Lisp_Object val; | 3074 | Lisp_Object val; |
| 3075 | 3075 | ||
| 3076 | CHECK_FIXNUM_COERCE_MARKER (x); | 3076 | CHECK_INTEGER_COERCE_MARKER (x); |
| 3077 | CHECK_FIXNUM_COERCE_MARKER (y); | 3077 | CHECK_INTEGER_COERCE_MARKER (y); |
| 3078 | 3078 | ||
| 3079 | if (XINT (y) == 0) | 3079 | /* Note that a bignum can never be 0, so we don't need to check that |
| 3080 | case. */ | ||
| 3081 | if (FIXNUMP (y) && XINT (y) == 0) | ||
| 3080 | xsignal0 (Qarith_error); | 3082 | xsignal0 (Qarith_error); |
| 3081 | 3083 | ||
| 3082 | XSETINT (val, XINT (x) % XINT (y)); | 3084 | if (FIXNUMP (x) && FIXNUMP (y)) |
| 3085 | XSETINT (val, XINT (x) % XINT (y)); | ||
| 3086 | else | ||
| 3087 | { | ||
| 3088 | mpz_t xm, ym, *xmp, *ymp; | ||
| 3089 | mpz_t result; | ||
| 3090 | |||
| 3091 | if (BIGNUMP (x)) | ||
| 3092 | xmp = &XBIGNUM (x)->value; | ||
| 3093 | else | ||
| 3094 | { | ||
| 3095 | mpz_init_set_si (xm, XINT (x)); | ||
| 3096 | xmp = &xm; | ||
| 3097 | } | ||
| 3098 | |||
| 3099 | if (BIGNUMP (y)) | ||
| 3100 | ymp = &XBIGNUM (y)->value; | ||
| 3101 | else | ||
| 3102 | { | ||
| 3103 | mpz_init_set_si (ym, XINT (y)); | ||
| 3104 | ymp = &ym; | ||
| 3105 | } | ||
| 3106 | |||
| 3107 | mpz_init (result); | ||
| 3108 | mpz_tdiv_r (result, *xmp, *ymp); | ||
| 3109 | val = make_number (result); | ||
| 3110 | mpz_clear (result); | ||
| 3111 | |||
| 3112 | if (xmp == &xm) | ||
| 3113 | mpz_clear (xm); | ||
| 3114 | if (ymp == &ym) | ||
| 3115 | mpz_clear (ym); | ||
| 3116 | } | ||
| 3083 | return val; | 3117 | return val; |
| 3084 | } | 3118 | } |
| 3085 | 3119 | ||
| @@ -3092,25 +3126,73 @@ Both X and Y must be numbers or markers. */) | |||
| 3092 | Lisp_Object val; | 3126 | Lisp_Object val; |
| 3093 | EMACS_INT i1, i2; | 3127 | EMACS_INT i1, i2; |
| 3094 | 3128 | ||
| 3095 | CHECK_FIXNUM_OR_FLOAT_COERCE_MARKER (x); | 3129 | CHECK_NUMBER_COERCE_MARKER (x); |
| 3096 | CHECK_FIXNUM_OR_FLOAT_COERCE_MARKER (y); | 3130 | CHECK_NUMBER_COERCE_MARKER (y); |
| 3131 | |||
| 3132 | /* Note that a bignum can never be 0, so we don't need to check that | ||
| 3133 | case. */ | ||
| 3134 | if (FIXNUMP (y) && XINT (y) == 0) | ||
| 3135 | xsignal0 (Qarith_error); | ||
| 3097 | 3136 | ||
| 3098 | if (FLOATP (x) || FLOATP (y)) | 3137 | if (FLOATP (x) || FLOATP (y)) |
| 3099 | return fmod_float (x, y); | 3138 | return fmod_float (x, y); |
| 3100 | 3139 | ||
| 3101 | i1 = XINT (x); | 3140 | if (FIXNUMP (x) && FIXNUMP (y)) |
| 3102 | i2 = XINT (y); | 3141 | { |
| 3142 | i1 = XINT (x); | ||
| 3143 | i2 = XINT (y); | ||
| 3103 | 3144 | ||
| 3104 | if (i2 == 0) | 3145 | if (i2 == 0) |
| 3105 | xsignal0 (Qarith_error); | 3146 | xsignal0 (Qarith_error); |
| 3106 | 3147 | ||
| 3107 | i1 %= i2; | 3148 | i1 %= i2; |
| 3108 | 3149 | ||
| 3109 | /* If the "remainder" comes out with the wrong sign, fix it. */ | 3150 | /* If the "remainder" comes out with the wrong sign, fix it. */ |
| 3110 | if (i2 < 0 ? i1 > 0 : i1 < 0) | 3151 | if (i2 < 0 ? i1 > 0 : i1 < 0) |
| 3111 | i1 += i2; | 3152 | i1 += i2; |
| 3153 | |||
| 3154 | XSETINT (val, i1); | ||
| 3155 | } | ||
| 3156 | else | ||
| 3157 | { | ||
| 3158 | mpz_t xm, ym, *xmp, *ymp; | ||
| 3159 | mpz_t result; | ||
| 3160 | int cmpr, cmpy; | ||
| 3161 | |||
| 3162 | if (BIGNUMP (x)) | ||
| 3163 | xmp = &XBIGNUM (x)->value; | ||
| 3164 | else | ||
| 3165 | { | ||
| 3166 | mpz_init_set_si (xm, XINT (x)); | ||
| 3167 | xmp = &xm; | ||
| 3168 | } | ||
| 3169 | |||
| 3170 | if (BIGNUMP (y)) | ||
| 3171 | ymp = &XBIGNUM (y)->value; | ||
| 3172 | else | ||
| 3173 | { | ||
| 3174 | mpz_init_set_si (ym, XINT (y)); | ||
| 3175 | ymp = &ym; | ||
| 3176 | } | ||
| 3177 | |||
| 3178 | mpz_init (result); | ||
| 3179 | mpz_mod (result, *xmp, *ymp); | ||
| 3180 | |||
| 3181 | /* Fix the sign if needed. */ | ||
| 3182 | cmpr = mpz_cmp_si (result, 0); | ||
| 3183 | cmpy = mpz_cmp_si (*ymp, 0); | ||
| 3184 | if (cmpy < 0 ? cmpr > 0 : cmpr < 0) | ||
| 3185 | mpz_add (result, result, *ymp); | ||
| 3186 | |||
| 3187 | val = make_number (result); | ||
| 3188 | mpz_clear (result); | ||
| 3189 | |||
| 3190 | if (xmp == &xm) | ||
| 3191 | mpz_clear (xm); | ||
| 3192 | if (ymp == &ym) | ||
| 3193 | mpz_clear (ym); | ||
| 3194 | } | ||
| 3112 | 3195 | ||
| 3113 | XSETINT (val, i1); | ||
| 3114 | return val; | 3196 | return val; |
| 3115 | } | 3197 | } |
| 3116 | 3198 | ||