[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] feature/bignum 3dea8f8 19/24: Make % and mod handle bignum
From: |
Tom Tromey |
Subject: |
[Emacs-diffs] feature/bignum 3dea8f8 19/24: Make % and mod handle bignums |
Date: |
Fri, 13 Jul 2018 00:25:09 -0400 (EDT) |
branch: feature/bignum
commit 3dea8f8f53f81a1d15a55c9e3c87a7eade7ca273
Author: Tom Tromey <address@hidden>
Commit: Tom Tromey <address@hidden>
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.
---
src/data.c | 112 ++++++++++++++++++++++++++++++++++++++++++-------
src/lisp.h | 8 ++++
test/src/data-tests.el | 17 ++++++++
3 files changed, 122 insertions(+), 15 deletions(-)
diff --git a/src/data.c b/src/data.c
index 7ded836..ac74ff5 100644
--- a/src/data.c
+++ b/src/data.c
@@ -3073,13 +3073,47 @@ Both must be integers or markers. */)
{
Lisp_Object val;
- CHECK_FIXNUM_COERCE_MARKER (x);
- CHECK_FIXNUM_COERCE_MARKER (y);
+ CHECK_INTEGER_COERCE_MARKER (x);
+ CHECK_INTEGER_COERCE_MARKER (y);
- if (XINT (y) == 0)
+ /* Note that a bignum can never be 0, so we don't need to check that
+ case. */
+ if (FIXNUMP (y) && XINT (y) == 0)
xsignal0 (Qarith_error);
- XSETINT (val, XINT (x) % XINT (y));
+ if (FIXNUMP (x) && FIXNUMP (y))
+ XSETINT (val, XINT (x) % XINT (y));
+ else
+ {
+ mpz_t xm, ym, *xmp, *ymp;
+ mpz_t result;
+
+ if (BIGNUMP (x))
+ xmp = &XBIGNUM (x)->value;
+ else
+ {
+ mpz_init_set_si (xm, XINT (x));
+ xmp = &xm;
+ }
+
+ if (BIGNUMP (y))
+ ymp = &XBIGNUM (y)->value;
+ else
+ {
+ mpz_init_set_si (ym, XINT (y));
+ ymp = &ym;
+ }
+
+ mpz_init (result);
+ mpz_tdiv_r (result, *xmp, *ymp);
+ val = make_number (result);
+ mpz_clear (result);
+
+ if (xmp == &xm)
+ mpz_clear (xm);
+ if (ymp == &ym)
+ mpz_clear (ym);
+ }
return val;
}
@@ -3092,25 +3126,73 @@ Both X and Y must be numbers or markers. */)
Lisp_Object val;
EMACS_INT i1, i2;
- CHECK_FIXNUM_OR_FLOAT_COERCE_MARKER (x);
- CHECK_FIXNUM_OR_FLOAT_COERCE_MARKER (y);
+ CHECK_NUMBER_COERCE_MARKER (x);
+ CHECK_NUMBER_COERCE_MARKER (y);
+
+ /* Note that a bignum can never be 0, so we don't need to check that
+ case. */
+ if (FIXNUMP (y) && XINT (y) == 0)
+ xsignal0 (Qarith_error);
if (FLOATP (x) || FLOATP (y))
return fmod_float (x, y);
- i1 = XINT (x);
- i2 = XINT (y);
+ if (FIXNUMP (x) && FIXNUMP (y))
+ {
+ i1 = XINT (x);
+ i2 = XINT (y);
- if (i2 == 0)
- xsignal0 (Qarith_error);
+ if (i2 == 0)
+ xsignal0 (Qarith_error);
- i1 %= i2;
+ i1 %= i2;
- /* If the "remainder" comes out with the wrong sign, fix it. */
- if (i2 < 0 ? i1 > 0 : i1 < 0)
- i1 += i2;
+ /* If the "remainder" comes out with the wrong sign, fix it. */
+ if (i2 < 0 ? i1 > 0 : i1 < 0)
+ i1 += i2;
+
+ XSETINT (val, i1);
+ }
+ else
+ {
+ mpz_t xm, ym, *xmp, *ymp;
+ mpz_t result;
+ int cmpr, cmpy;
+
+ if (BIGNUMP (x))
+ xmp = &XBIGNUM (x)->value;
+ else
+ {
+ mpz_init_set_si (xm, XINT (x));
+ xmp = &xm;
+ }
+
+ if (BIGNUMP (y))
+ ymp = &XBIGNUM (y)->value;
+ else
+ {
+ mpz_init_set_si (ym, XINT (y));
+ ymp = &ym;
+ }
+
+ mpz_init (result);
+ mpz_mod (result, *xmp, *ymp);
+
+ /* Fix the sign if needed. */
+ cmpr = mpz_cmp_si (result, 0);
+ cmpy = mpz_cmp_si (*ymp, 0);
+ if (cmpy < 0 ? cmpr > 0 : cmpr < 0)
+ mpz_add (result, result, *ymp);
+
+ val = make_number (result);
+ mpz_clear (result);
+
+ if (xmp == &xm)
+ mpz_clear (xm);
+ if (ymp == &ym)
+ mpz_clear (ym);
+ }
- XSETINT (val, i1);
return val;
}
diff --git a/src/lisp.h b/src/lisp.h
index 63b0570..846e955 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2958,6 +2958,14 @@ CHECK_INTEGER (Lisp_Object x)
CHECK_TYPE (NUMBERP (x), Qnumber_or_marker_p, x);
\
} while (false)
+#define CHECK_INTEGER_COERCE_MARKER(x) \
+ do { \
+ if (MARKERP (x)) \
+ XSETFASTINT (x, marker_position (x)); \
+ else \
+ CHECK_TYPE (INTEGERP (x), Qnumber_or_marker_p, x); \
+ } while (false)
+
/* Since we can't assign directly to the CAR or CDR fields of a cons
cell, use these when checking that those fields contain numbers. */
INLINE void
diff --git a/test/src/data-tests.el b/test/src/data-tests.el
index 4565cfb..2423d7a 100644
--- a/test/src/data-tests.el
+++ b/test/src/data-tests.el
@@ -597,4 +597,21 @@ comparing the subr with a much slower lisp implementation."
(should (= (min a b c) a))
(should (= (max a b c) b))))
+(defun data-tests-check-sign (x y)
+ (should (eq (cl-signum x) (cl-signum y))))
+
+(ert-deftest data-tests-%-mod ()
+ (let* ((b1 (+ most-positive-fixnum 1))
+ (nb1 (- b1))
+ (b3 (+ most-positive-fixnum 3))
+ (nb3 (- b3)))
+ (data-tests-check-sign (% 1 3) (% b1 b3))
+ (data-tests-check-sign (mod 1 3) (mod b1 b3))
+ (data-tests-check-sign (% 1 -3) (% b1 nb3))
+ (data-tests-check-sign (mod 1 -3) (mod b1 nb3))
+ (data-tests-check-sign (% -1 3) (% nb1 b3))
+ (data-tests-check-sign (mod -1 3) (mod nb1 b3))
+ (data-tests-check-sign (% -1 -3) (% nb1 nb3))
+ (data-tests-check-sign (mod -1 -3) (mod nb1 nb3))))
+
;;; data-tests.el ends here
- [Emacs-diffs] feature/bignum 580d173 05/24: Make eql work for bignums, (continued)
- [Emacs-diffs] feature/bignum 580d173 05/24: Make eql work for bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum a0f2adb 03/24: Introduce the bignum type, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 23eab9a 10/24: Make number-to-string work for bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 025adce 13/24: Make abs handle bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 6d4bf2c 09/24: Add some bignum tests, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 872faab 12/24: Allow conversion of bignums to floats, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 5875fba 08/24: Make arithmetic work with bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum a770fb4 16/24: Make logcount handle bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 0d86891 14/24: Make 1+ and 1- handle bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 8fb995b 17/24: Make min and max handle bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 3dea8f8 19/24: Make % and mod handle bignums,
Tom Tromey <=
- [Emacs-diffs] feature/bignum d14808c 11/24: Make format handle bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum c7e393b 15/24: Make lognot handle bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 1e8ae6c 06/24: Make the reader accept bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 27980e3 21/24: Make ash and lsh handle bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum cca0e79 20/24: Make logb handle bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum d0fac17 18/24: Let C modules access bignum values, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum e2a78b0 23/24: Bignum fixes for byte-compiler and bytecode interpreter, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 45eb3b3 22/24: Use fixnump rather than integerp in some spots, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum cc3d758 24/24: Document bignums, Tom Tromey, 2018/07/13
- [Emacs-diffs] feature/bignum 7cb45cd 02/24: Add configury for GMP library, Tom Tromey, 2018/07/13