diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | mini-gmp/mini-mpq.c | 388 | ||||
-rw-r--r-- | mini-gmp/mini-mpq.h | 82 | ||||
-rw-r--r-- | mini-gmp/tests/Makefile | 7 | ||||
-rw-r--r-- | mini-gmp/tests/t-mpq_addsub.c | 164 | ||||
-rw-r--r-- | mini-gmp/tests/t-mpq_muldiv.c | 160 | ||||
-rw-r--r-- | mini-gmp/tests/t-mpq_muldiv_2exp.c | 138 | ||||
-rw-r--r-- | mini-gmp/tests/testutils.c | 1 |
8 files changed, 938 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am index 8b387b313..b177f5471 100644 --- a/Makefile.am +++ b/Makefile.am @@ -406,6 +406,7 @@ EXTRA_DIST += gen-psqr.c # Distribute mini-gmp. Test sources copied by dist-hook. EXTRA_DIST += mini-gmp/README mini-gmp/mini-gmp.c mini-gmp/mini-gmp.h \ + mini-gmp/mini-mpq.c mini-gmp/mini-mpq.h \ mini-gmp/tests/Makefile mini-gmp/tests/run-tests # Avoid: CVS - cvs directories diff --git a/mini-gmp/mini-mpq.c b/mini-gmp/mini-mpq.c new file mode 100644 index 000000000..a9bf6ae6d --- /dev/null +++ b/mini-gmp/mini-mpq.c @@ -0,0 +1,388 @@ +/* mini-mpq, a minimalistic implementation of a GNU GMP subset. + + Contributed to the GNU project by Marco Bodrato + +Copyright 2018 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with the GNU MP Library. If not, +see https://www.gnu.org/licenses/. */ + +#include <assert.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> + +#include "mini-mpq.h" + +#ifndef GMP_LIMB_HIGHBIT +/* Define macros and static functions already defined by mini-gmp.c */ +#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT) +#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1)) +#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1)) +#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b)) + +static mpz_srcptr +mpz_roinit_normal_n (mpz_t x, mp_srcptr xp, mp_size_t xs) +{ + x->_mp_alloc = 0; + x->_mp_d = (mp_ptr) xp; + x->_mp_size = xs; + return x; +} + +static void +gmp_die (const char *msg) +{ + fprintf (stderr, "%s\n", msg); + abort(); +} +#endif + + +/* MPQ helper functions */ +static mpq_srcptr +mpq_roinit_normal_n (mpq_t x, mp_srcptr np, mp_size_t ns, + mp_srcptr dp, mp_size_t ds) +{ + mpz_roinit_normal_n (mpq_numref(x), np, ns); + mpz_roinit_normal_n (mpq_denref(x), dp, ds); + return x; +} + +static mpq_srcptr +mpq_roinit_z (mpq_t x, mpz_srcptr n, mpz_srcptr d) +{ + return mpq_roinit_normal_n (x, n->_mp_d, n->_mp_size, + d->_mp_d, d->_mp_size); +} + +void +mpq_init (mpq_t x) +{ + mpz_init (mpq_numref (x)); + mpz_init_set_ui (mpq_denref (x), 1); +} + +void +mpq_clear (mpq_t x) +{ + mpz_clear (mpq_numref (x)); + mpz_clear (mpq_denref (x)); +} + +static void +mpq_canonical_sign (mpq_t r) +{ + int cmp = mpq_denref (r)->_mp_size; + if (cmp <= 0) + { + if (cmp == 0) + gmp_die("mpq: Fraction with zero denominator."); + mpz_neg (mpq_denref (r), mpq_denref (r)); + mpz_neg (mpq_numref (r), mpq_numref (r)); + } +} + +static void +mpq_helper_canonicalize (mpq_t r, const mpq_t c, mpz_t g) +{ + if (mpq_numref (c)->_mp_size == 0) + mpq_set_ui (r, 0, 1); + else + { + mpz_gcd (g, mpq_numref (c), mpq_denref (c)); + mpz_tdiv_q (mpq_numref (r), mpq_numref (c), g); + mpz_tdiv_q (mpq_denref (r), mpq_denref (c), g); + mpq_canonical_sign (r); + } +} + +void +mpq_canonicalize (mpq_t r) +{ + mpz_t t; + + mpz_init (t); + mpq_helper_canonicalize (r, r, t); + mpz_clear (t); +} + +void +mpq_swap (mpq_t a, mpq_t b) +{ + mpz_swap (mpq_numref (a), mpq_numref (b)); + mpz_swap (mpq_denref (a), mpq_denref (b)); +} + + +/* MPQ assignment and conversions. */ +void +mpz_set_q (mpz_t r, const mpq_t q) +{ + mpz_tdiv_q (r, mpq_numref (q), mpq_denref (q)); +} + +void +mpq_set (mpq_t r, const mpq_t q) +{ + mpz_set (mpq_numref (r), mpq_numref (q)); + mpz_set (mpq_denref (r), mpq_denref (q)); +} + +void +mpq_set_ui (mpq_t r, unsigned long n, unsigned long d) +{ + assert (d != 0); + + mpz_set_ui (mpq_numref (r), n); + mpz_set_ui (mpq_denref (r), d); +} + +void +mpq_set_si (mpq_t r, signed long n, unsigned long d) +{ + assert (d != 0); + + mpz_set_si (mpq_numref (r), n); + mpz_set_ui (mpq_denref (r), d); +} + +void +mpq_set_z (mpq_t r, const mpz_t n) +{ + mpz_set_ui (mpq_denref (r), 1); + mpz_set (mpq_numref (r), n); +} + +void +mpq_set_num (mpq_t r, const mpz_t z) +{ + mpz_set (mpq_numref (r), z); +} + +void +mpq_set_den (mpq_t r, const mpz_t z) +{ + assert (z->_mp_size != 0); + mpz_set (mpq_denref (r), z); +} + +void +mpq_get_num (mpz_t r, const mpq_t q) +{ + mpz_set (r, mpq_numref (q)); +} + +void +mpq_get_den (mpz_t r, const mpq_t q) +{ + mpz_set (r, mpq_denref (q)); +} + + +/* MPQ comparisons and the like. */ +int +mpq_cmp (const mpq_t a, const mpq_t b) +{ + mpz_t t1, t2; + int res; + + mpz_init (t1); + mpz_init (t2); + mpz_mul (t1, mpq_numref (a), mpq_denref (b)); + mpz_mul (t2, mpq_numref (b), mpq_denref (a)); + res = mpz_cmp (t1, t2); + mpz_clear (t1); + mpz_clear (t2); + + return res; +} + +int +mpq_cmp_z (const mpq_t a, const mpz_t b) +{ + mpz_t t; + int res; + + mpz_init (t); + mpz_mul (t, b, mpq_denref (a)); + res = mpz_cmp (mpq_numref (a), t); + mpz_clear (t); + + return res; +} + +int +mpq_equal (const mpq_t a, const mpq_t b) +{ + return (mpz_cmp (mpq_numref (a), mpq_numref (b)) == 0) && + (mpz_cmp (mpq_denref (a), mpq_denref (b)) == 0); +} + +int +mpq_cmp_ui (const mpq_t q, unsigned long n, unsigned long d) +{ + mpq_t t; + assert (d != 0); + return mpq_cmp (q, mpq_roinit_normal_n (t, &n, n != 0, &d, 1)); +} + +int +mpq_cmp_si (const mpq_t q, signed long n, unsigned long d) +{ + assert (d != 0); + + if (n >= 0) + return mpq_cmp_ui (q, n, d); + else + { + mpq_t t; + unsigned long l_n = GMP_NEG_CAST (unsigned long, n); + + return mpq_cmp (q, mpq_roinit_normal_n (t, &l_n, -1, &d, 1)); + } +} + +int +mpq_sgn (const mpq_t a) +{ + return mpz_sgn (mpq_numref (a)); +} + + +/* MPQ arithmetic. */ +void +mpq_abs (mpq_t r, const mpq_t q) +{ + mpz_abs (mpq_numref (r), mpq_numref (q)); + mpz_set (mpq_denref (r), mpq_denref (q)); +} + +void +mpq_neg (mpq_t r, const mpq_t q) +{ + mpz_neg (mpq_numref (r), mpq_numref (q)); + mpz_set (mpq_denref (r), mpq_denref (q)); +} + +void +mpq_add (mpq_t r, const mpq_t a, const mpq_t b) +{ + mpz_t t; + + mpz_init (t); + mpz_gcd (t, mpq_denref (a), mpq_denref (b)); + if (mpz_cmp_ui (t, 1) == 0) + { + mpz_mul (t, mpq_numref (a), mpq_denref (b)); + mpz_addmul (t, mpq_numref (b), mpq_denref (a)); + mpz_mul (mpq_denref (r), mpq_denref (a), mpq_denref (b)); + mpz_swap (mpq_numref (r), t); + } + else + { + mpz_t x, y; + mpz_init (x); + mpz_init (y); + + mpz_tdiv_q (x, mpq_denref (b), t); + mpz_tdiv_q (y, mpq_denref (a), t); + mpz_mul (x, mpq_numref (a), x); + mpz_addmul (x, mpq_numref (b), y); + + mpz_gcd (t, x, t); + mpz_tdiv_q (mpq_numref (r), x, t); + mpz_tdiv_q (x, mpq_denref (b), t); + mpz_mul (mpq_denref (r), x, y); + + mpz_clear (x); + mpz_clear (y); + } + mpz_clear (t); +} + +void +mpq_sub (mpq_t r, const mpq_t a, const mpq_t b) +{ + mpq_t t; + + mpq_roinit_normal_n (t, mpq_numref (b)->_mp_d, - mpq_numref (b)->_mp_size, + mpq_denref (b)->_mp_d, mpq_denref (b)->_mp_size); + mpq_add (r, a, t); +} + +void +mpq_div (mpq_t r, const mpq_t a, const mpq_t b) +{ + mpq_t t; + mpq_mul (r, a, mpq_roinit_z (t, mpq_denref (b), mpq_numref (b))); +} + +void +mpq_mul (mpq_t r, const mpq_t a, const mpq_t b) +{ + mpq_t t, d; + mpz_t g; + mpz_init (g); + mpq_init (t); + + mpq_roinit_z (d, mpq_numref (a), mpq_denref (b)); + mpq_helper_canonicalize (t, d, g); + + mpq_roinit_z (d, mpq_numref (b), mpq_denref (a)); + mpq_helper_canonicalize (r, d, g); + mpz_clear (g); + + mpz_mul (mpq_numref (r), mpq_numref (r), mpq_numref (t)); + mpz_mul (mpq_denref (r), mpq_denref (r), mpq_denref (t)); + mpq_clear (t); +} + +void +mpq_div_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e) +{ + mp_bitcnt_t z = mpz_scan1 (mpq_numref (q), 0); + z = GMP_MIN (z, e); + mpz_mul_2exp (mpq_denref (r), mpq_denref (q), e - z); + mpz_tdiv_q_2exp (mpq_numref (r), mpq_numref (q), z); +} + +void +mpq_mul_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e) +{ + mp_bitcnt_t z = mpz_scan1 (mpq_denref (q), 0); + z = GMP_MIN (z, e); + mpz_mul_2exp (mpq_numref (r), mpq_numref (q), e - z); + mpz_tdiv_q_2exp (mpq_denref (r), mpq_denref (q), z); +} + +void +mpq_inv (mpq_t r, const mpq_t q) +{ + mpq_set (r, q); + mpz_swap (mpq_denref (r), mpq_numref (r)); + mpq_canonical_sign (r); +} diff --git a/mini-gmp/mini-mpq.h b/mini-gmp/mini-mpq.h new file mode 100644 index 000000000..31af47591 --- /dev/null +++ b/mini-gmp/mini-mpq.h @@ -0,0 +1,82 @@ +/* mini-mpq, a minimalistic implementation of a GNU GMP subset. + +Copyright 1991-1997, 1999-2018 Free Software Foundation, Inc. +Copyright 2018 Marco BODRATO. + +This file is intendet for the GNU MP Library. + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Affero General Public License as published by +the Free Software Foundation; either version 3 of the License, or (at +your option) any later version. + +This software is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero +General Public License for more details. + +You should have received copies of the GNU Affero General Public +License with the software. +If not, see https://www.gnu.org/licenses/. */ + +/* Header */ + +#ifndef __MINI_MPQ_H__ +#define __MINI_MPQ_H__ + +#include "mini-gmp.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +typedef struct +{ + __mpz_struct _mp_num; + __mpz_struct _mp_den; +} __mpq_struct; + +typedef __mpq_struct mpq_t[1]; + +typedef const __mpq_struct *mpq_srcptr; +typedef __mpq_struct *mpq_ptr; + +#define mpq_numref(Q) (&((Q)->_mp_num)) +#define mpq_denref(Q) (&((Q)->_mp_den)) + +void mpq_abs (mpq_t, const mpq_t); +void mpq_add (mpq_t, const mpq_t, const mpq_t); +void mpq_canonicalize (mpq_t); +void mpq_clear (mpq_t); +int mpq_cmp (const mpq_t, const mpq_t); +int mpq_cmp_si (const mpq_t, signed long, unsigned long); +int mpq_cmp_ui (const mpq_t, unsigned long, unsigned long); +int mpq_cmp_z (const mpq_t, const mpz_t); +void mpq_div (mpq_t, const mpq_t, const mpq_t); +void mpq_div_2exp (mpq_t, const mpq_t, mp_bitcnt_t); +int mpq_equal (const mpq_t, const mpq_t); +double mpq_get_d (const mpq_t); +void mpq_get_den (mpz_t, const mpq_t); +void mpq_get_num (mpz_t, const mpq_t); +void mpq_init (mpq_t); +void mpq_inv (mpq_t, const mpq_t); +void mpq_mul (mpq_t, const mpq_t, const mpq_t); +void mpq_mul_2exp (mpq_t, const mpq_t, mp_bitcnt_t); +void mpq_neg (mpq_t, const mpq_t); +void mpq_set (mpq_t, const mpq_t); +void mpq_set_d (mpq_t, double); +void mpq_set_den (mpq_t, const mpz_t); +void mpq_set_num (mpq_t, const mpz_t); +void mpq_set_si (mpq_t, signed long, unsigned long); +void mpq_set_ui (mpq_t, unsigned long, unsigned long); +void mpq_set_z (mpq_t, const mpz_t); +int mpq_sgn (const mpq_t); +void mpq_sub (mpq_t, const mpq_t, const mpq_t); +void mpq_swap (mpq_t, mpq_t); + +void mpz_set_q (mpz_t, const mpq_t); + +#if defined (__cplusplus) +} +#endif +#endif /* __MINI_MPQ_H__ */ diff --git a/mini-gmp/tests/Makefile b/mini-gmp/tests/Makefile index e4191c59f..7440729e1 100644 --- a/mini-gmp/tests/Makefile +++ b/mini-gmp/tests/Makefile @@ -30,7 +30,8 @@ LIBS = -lgmp -lm -lmcheck CHECK_PROGRAMS = t-add t-sub t-mul t-invert t-div t-div_2exp \ t-double t-cmp_d t-gcd t-lcm t-import t-comb t-signed \ t-sqrt t-root t-powm t-logops t-bitops t-scan t-str \ - t-reuse t-aorsmul t-limbs t-cong t-pprime_p + t-reuse t-aorsmul t-limbs t-cong t-pprime_p \ + t-mpq_addsub t-mpq_muldiv t-mpq_muldiv_2exp # Default TESTS to all tests, allowing overriding TESTS for building tests # without running them. TESTS = $(CHECK_PROGRAMS) @@ -48,10 +49,10 @@ clean: # Keep object files .PRECIOUS: %.o -%.o: %.c $(MINI_GMP_DIR)/mini-gmp.h hex-random.h mini-random.h +%.o: %.c $(MINI_GMP_DIR)/mini-gmp.h $(MINI_GMP_DIR)/mini-mpq.h hex-random.h mini-random.h $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ -testutils.o: $(MINI_GMP_DIR)/mini-gmp.c +testutils.o: $(MINI_GMP_DIR)/mini-gmp.c $(MINI_GMP_DIR)/mini-mpq.c %: %.o $(MISC_OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ diff --git a/mini-gmp/tests/t-mpq_addsub.c b/mini-gmp/tests/t-mpq_addsub.c new file mode 100644 index 000000000..3cd53f13c --- /dev/null +++ b/mini-gmp/tests/t-mpq_addsub.c @@ -0,0 +1,164 @@ +/* + +Copyright 2012, 2013, 2018 Free Software Foundation, Inc. + +This file is part of the GNU MP Library test suite. + +The GNU MP Library test suite is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, +or (at your option) any later version. + +The GNU MP Library test suite is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +Public License for more details. + +You should have received a copy of the GNU General Public License along with +the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +#include "testutils.h" +#include "../mini-mpq.h" + +#define MAXBITS 300 +#define COUNT 10000 + +static void +_mpq_set_zz (mpq_t q, mpz_t n, mpz_t d) +{ + if (mpz_fits_ulong_p (d) && mpz_fits_slong_p (n)) + { + mpq_set_si (q, mpz_get_si (n), mpz_get_ui (d)); + } + else if (mpz_fits_ulong_p (d) && mpz_fits_ulong_p (n)) + { + mpq_set_ui (q, mpz_get_ui (n), mpz_get_ui (d)); + } + else + { + mpq_set_num (q, n); + mpq_set_den (q, d); + } + mpq_canonicalize (q); +} + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, b, q, r, c; + mpq_t rr, ii, ff; + int tst; + + mpz_init (a); + mpz_init (b); + mpz_init (r); + mpz_init (q); + mpz_init (c); + mpq_init (rr); + mpq_init (ff); + mpq_init (ii); + + for (i = 0; i < COUNT; i++) + { + mini_random_op4 (OP_TDIV, MAXBITS, a, b, q, r); + + _mpq_set_zz (rr, a, b); + _mpq_set_zz (ff, r, b); + + mpq_set_z (ii, q); + + mpz_set_q (c, rr); + if (mpz_cmp (c, q)) + { + fprintf (stderr, "mpz_set_q failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("c", c); + dump ("q", q); + abort (); + } + + if ((mpz_sgn (r) != 0) ^ (mpz_cmp_ui (mpq_denref (rr), 1) != 0)) + { + fprintf (stderr, "mpq_canonicalize failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", r); + dump ("D", mpq_denref (rr)); + abort (); + } + + if (i & 1) + { + if (mpz_fits_slong_p (q)) + tst = mpq_cmp_si (rr, mpz_get_si (q), 1); + else if (mpz_fits_ulong_p (q)) + tst = mpq_cmp_ui (rr, mpz_get_ui (q), 1); + else + tst = mpq_cmp_z (rr, q); + if (mpz_sgn (b) < 0) + tst = - tst; + if ((tst != mpz_sgn (r)) && ((tst < 0 && mpz_sgn (r) >= 0) || (tst > 0 && mpz_sgn (r) <= 0))) + { + fprintf (stderr, "mpq_cmp ii failed: %i %i\n", tst, mpz_sgn (r)); + dump ("a", a); + dump ("b", b); + dump ("r", r); + dump ("q", q); + abort (); + } + } + else + { + if (mpz_fits_ulong_p (b) && mpz_fits_slong_p (r)) + tst = mpq_cmp_si (rr, mpz_get_si (r), mpz_get_ui (b)); + else if (mpz_fits_ulong_p (b) && mpz_fits_ulong_p (r)) + tst = mpq_cmp_ui (rr, mpz_get_ui (r), mpz_get_ui (b)); + else + tst = mpq_cmp (rr, ff); + if ((tst != mpz_sgn (q)) && ((tst < 0 && mpz_sgn (q) >= 0) || (tst > 0 && mpz_sgn (q) <= 0))) + { + fprintf (stderr, "mpq_cmp ff failed: %i %i\n", tst, mpz_sgn (q)); + dump ("a", a); + dump ("b", b); + dump ("r", r); + dump ("q", q); + abort (); + } + } + + if (i & 1) + { + mpq_sub (rr, rr, ff); + } + else + { + mpq_neg (ff, ff); + mpq_add (rr, ff, rr); + } + + if (!mpq_equal (ii, rr)) + { + fprintf (stderr, "mpq_%s failed:\n", (i & 1) ? "sub" : "add"); + dump ("a", a); + dump ("b", b); + dump ("r", r); + dump ("q", q); + abort (); + } + } + + mpz_clear (a); + mpz_clear (b); + mpz_clear (r); + mpz_clear (q); + mpz_clear (c); + mpq_clear (rr); + mpq_clear (ff); + mpq_clear (ii); +} diff --git a/mini-gmp/tests/t-mpq_muldiv.c b/mini-gmp/tests/t-mpq_muldiv.c new file mode 100644 index 000000000..03282da62 --- /dev/null +++ b/mini-gmp/tests/t-mpq_muldiv.c @@ -0,0 +1,160 @@ +/* + +Copyright 2012, 2013, 2018 Free Software Foundation, Inc. + +This file is part of the GNU MP Library test suite. + +The GNU MP Library test suite is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, +or (at your option) any later version. + +The GNU MP Library test suite is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +Public License for more details. + +You should have received a copy of the GNU General Public License along with +the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +#include "testutils.h" +#include "../mini-mpq.h" + +#define MAXBITS 300 +#define COUNT 10000 + +static void +_mpq_set_zz (mpq_t q, mpz_t n, mpz_t d) +{ + if (mpz_fits_ulong_p (d) && mpz_fits_slong_p (n)) + { + mpq_set_si (q, mpz_get_si (n), mpz_get_ui (d)); + } + else if (mpz_fits_ulong_p (d) && mpz_fits_ulong_p (n)) + { + mpq_set_ui (q, mpz_get_ui (n), mpz_get_ui (d)); + } + else + { + mpq_set_num (q, n); + mpq_set_den (q, d); + } + mpq_canonicalize (q); +} + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t an, bn, rn, ad, bd, rd; + mpq_t aq, bq, refq, resq; + int tst; + + mpz_init (an); + mpz_init (bn); + mpz_init (rn); + mpz_init (ad); + mpz_init (bd); + mpz_init (rd); + mpq_init (aq); + mpq_init (bq); + mpq_init (refq); + mpq_init (resq); + + for (i = 0; i < COUNT; i++) + { + mini_random_op3 (OP_MUL, MAXBITS, an, bn, rn); + do { + mini_random_op3 (OP_MUL, MAXBITS, ad, bd, rd); + } while (mpz_sgn (rd) == 0); + + _mpq_set_zz (aq, an, ad); + _mpq_set_zz (bq, bn, bd); + _mpq_set_zz (refq, rn, rd); + + mpq_mul (resq, aq, bq); + if (!mpq_equal (resq, refq)) + { + fprintf (stderr, "mpq_mul failed [%i]:\n", i); + dump ("an", an); + dump ("ad", ad); + dump ("bn", bn); + dump ("bd", bd); + dump ("refn", rn); + dump ("refd", rd); + dump ("resn", mpq_numref (resq)); + dump ("resd", mpq_denref (resq)); + abort (); + } + + if (mpq_sgn (refq) != 0) + { + mpq_set_ui (resq, ~6, 8); + mpq_inv (aq, aq); + mpq_div (resq, aq, bq); + mpq_inv (resq, resq); + if (!mpq_equal (resq, refq)) + { + fprintf (stderr, "mpq_div failed [%i]:\n", i); + dump ("an", an); + dump ("ad", ad); + dump ("bn", bn); + dump ("bd", bd); + dump ("refn", rn); + dump ("refd", rd); + dump ("resn", mpq_numref (resq)); + dump ("resd", mpq_denref (resq)); + abort (); + } + + mpq_swap (bq, aq); + mpq_div (resq, aq, bq); + if (!mpq_equal (resq, refq)) + { + fprintf (stderr, "mpq_swap failed [%i]:\n", i); + dump ("an", an); + dump ("ad", ad); + dump ("bn", bn); + dump ("bd", bd); + dump ("refn", rn); + dump ("refd", rd); + dump ("resn", mpq_numref (resq)); + dump ("resd", mpq_denref (resq)); + abort (); + } + } + + mpq_set (resq, aq); + mpq_neg (bq, aq); + mpq_abs (refq, aq); + if (mpq_equal (refq, resq)) + mpq_add (resq, refq, bq); + else + mpq_add (resq, refq, resq); + mpq_set_ui (refq, 0, 1); + if (!mpq_equal (resq, refq)) + { + fprintf (stderr, "mpq_abs failed [%i]:\n", i); + dump ("an", an); + dump ("ad", ad); + dump ("resn", mpq_numref (resq)); + dump ("resd", mpq_denref (resq)); + abort (); + } + } + + mpz_clear (an); + mpz_clear (bn); + mpz_clear (rn); + mpz_clear (ad); + mpz_clear (bd); + mpz_clear (rd); + mpq_clear (aq); + mpq_clear (bq); + mpq_clear (refq); + mpq_clear (resq); +} diff --git a/mini-gmp/tests/t-mpq_muldiv_2exp.c b/mini-gmp/tests/t-mpq_muldiv_2exp.c new file mode 100644 index 000000000..fe78f3b35 --- /dev/null +++ b/mini-gmp/tests/t-mpq_muldiv_2exp.c @@ -0,0 +1,138 @@ +/* + +Copyright 2012, 2013, 2018 Free Software Foundation, Inc. + +This file is part of the GNU MP Library test suite. + +The GNU MP Library test suite is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, +or (at your option) any later version. + +The GNU MP Library test suite is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +Public License for more details. + +You should have received a copy of the GNU General Public License along with +the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +#include "testutils.h" +#include "../mini-mpq.h" + +#define MAXBITS 300 +#define COUNT 10000 + +static void +_mpq_set_zz (mpq_t q, mpz_t n, mpz_t d) +{ + if (mpz_fits_ulong_p (d) && mpz_fits_slong_p (n)) + { + mpq_set_si (q, mpz_get_si (n), mpz_get_ui (d)); + } + else if (mpz_fits_ulong_p (d) && mpz_fits_ulong_p (n)) + { + mpq_set_ui (q, mpz_get_ui (n), mpz_get_ui (d)); + } + else + { + mpq_set_num (q, n); + mpq_set_den (q, d); + } + mpq_canonicalize (q); +} + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, b, t; + mpq_t aq, rq, tq; + mp_bitcnt_t e; + long int e2, t1, t2; + + mpz_init (a); + mpz_init (b); + mpz_init (t); + mpq_init (aq); + mpq_init (rq); + mpq_init (tq); + + for (i = 0; i < COUNT; i++) + { + do { + mini_random_bit_op (OP_COMBIT, MAXBITS, a, &e, b); + } while (mpz_sgn (a) == 0 || mpz_sgn (b) == 0); + + _mpq_set_zz (aq, a, b); + e2 = mpz_scan1 (a, 0); + e2-= mpz_scan1 (b, 0); + + mpq_mul_2exp (rq, aq, e); + t1 = mpz_scan1 (mpq_numref (rq), 0); + t2 = mpz_scan1 (mpq_denref (rq), 0); + mpq_neg (tq, rq); + mpq_div (tq, aq, tq); + mpq_get_den (t, tq); + + if (e2 + e != t1 - t2 || (t2 != 0 && t1 != 0) || mpz_scan1 (t, 0) != e + || mpz_sizeinbase (t, 2) - 1 != e || mpz_cmp_si (mpq_numref (tq), -1) != 0) + { + fprintf (stderr, "mpq_mul_2exp failed: %lu\n", e); + dump ("na", a); + dump ("da", b); + dump ("nr", mpq_numref (rq)); + dump ("dr", mpq_denref (rq)); + abort (); + } + + mpq_div_2exp (rq, aq, e); + t1 = mpz_scan1 (mpq_numref (rq), 0); + t2 = mpz_scan1 (mpq_denref (rq), 0); + mpq_div (aq, aq, rq); + mpq_get_num (t, aq); + + if (e2 != t1 - t2 + e || (t2 != 0 && t1 != 0) || mpz_scan1 (t, 0) != e + || mpz_sizeinbase (t, 2) - 1 != e || mpz_cmp_ui (mpq_denref (aq), 1) != 0) + { + fprintf (stderr, "mpq_div_2exp failed: %lu\n", e); + fprintf (stderr, "%li %li %lu %lu\n", e2, t2, mpz_scan1 (t, 0), mpz_sizeinbase (t, 2)); + dump ("na", a); + dump ("da", b); + dump ("nr", mpq_numref (rq)); + dump ("dr", mpq_denref (rq)); + abort (); + } + + mpq_set_ui (aq, 0, 1); + mpq_set_ui (rq, 6, 7); + mpq_set (tq, aq); + mpq_div_2exp (rq, aq, e); + + if (!mpq_equal (tq, rq)) + { + fprintf (stderr, "mpq_div_2exp failed on zero: %lu\n", e); + abort (); + } + + mpq_set_ui (rq, 7, 6); + mpq_mul_2exp (rq, aq, e); + + if (!mpq_equal (rq, tq)) + { + fprintf (stderr, "mpq_mul_2exp failed on zero: %lu\n", e); + abort (); + } + } + + mpz_clear (a); + mpz_clear (b); + mpz_clear (t); + mpq_clear (aq); + mpq_clear (rq); + mpq_clear (tq); +} diff --git a/mini-gmp/tests/testutils.c b/mini-gmp/tests/testutils.c index b49bd2267..ff4a4a178 100644 --- a/mini-gmp/tests/testutils.c +++ b/mini-gmp/tests/testutils.c @@ -22,6 +22,7 @@ the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ /* Include it here, so we we could tweak, e.g., how MPZ_REALLOC works. */ #include "../mini-gmp.c" +#include "../mini-mpq.c" static size_t total_alloc = 0; |