From 11da511c784eca003deb90c23570f0873954e0de Mon Sep 17 00:00:00 2001 From: Duncan Wilkie Date: Sat, 18 Nov 2023 06:11:09 -0600 Subject: Initial commit. --- gmp-6.3.0/mini-gmp/ChangeLog | 768 +++++ gmp-6.3.0/mini-gmp/README | 72 + gmp-6.3.0/mini-gmp/mini-gmp.c | 4627 ++++++++++++++++++++++++++ gmp-6.3.0/mini-gmp/mini-gmp.h | 310 ++ gmp-6.3.0/mini-gmp/mini-mpq.c | 556 ++++ gmp-6.3.0/mini-gmp/mini-mpq.h | 114 + gmp-6.3.0/mini-gmp/tests/Makefile | 65 + gmp-6.3.0/mini-gmp/tests/hex-random.c | 573 ++++ gmp-6.3.0/mini-gmp/tests/hex-random.h | 55 + gmp-6.3.0/mini-gmp/tests/mini-random.c | 160 + gmp-6.3.0/mini-gmp/tests/mini-random.h | 35 + gmp-6.3.0/mini-gmp/tests/run-tests | 143 + gmp-6.3.0/mini-gmp/tests/t-add.c | 57 + gmp-6.3.0/mini-gmp/tests/t-aorsmul.c | 77 + gmp-6.3.0/mini-gmp/tests/t-bitops.c | 104 + gmp-6.3.0/mini-gmp/tests/t-cmp_d.c | 283 ++ gmp-6.3.0/mini-gmp/tests/t-comb.c | 175 + gmp-6.3.0/mini-gmp/tests/t-cong.c | 212 ++ gmp-6.3.0/mini-gmp/tests/t-div.c | 258 ++ gmp-6.3.0/mini-gmp/tests/t-div_2exp.c | 82 + gmp-6.3.0/mini-gmp/tests/t-double.c | 232 ++ gmp-6.3.0/mini-gmp/tests/t-gcd.c | 178 + gmp-6.3.0/mini-gmp/tests/t-import.c | 99 + gmp-6.3.0/mini-gmp/tests/t-invert.c | 141 + gmp-6.3.0/mini-gmp/tests/t-lcm.c | 73 + gmp-6.3.0/mini-gmp/tests/t-limbs.c | 111 + gmp-6.3.0/mini-gmp/tests/t-logops.c | 112 + gmp-6.3.0/mini-gmp/tests/t-lucm.c | 98 + gmp-6.3.0/mini-gmp/tests/t-mpq_addsub.c | 204 ++ gmp-6.3.0/mini-gmp/tests/t-mpq_double.c | 211 ++ gmp-6.3.0/mini-gmp/tests/t-mpq_muldiv.c | 176 + gmp-6.3.0/mini-gmp/tests/t-mpq_muldiv_2exp.c | 138 + gmp-6.3.0/mini-gmp/tests/t-mpq_str.c | 263 ++ gmp-6.3.0/mini-gmp/tests/t-mul.c | 113 + gmp-6.3.0/mini-gmp/tests/t-powm.c | 87 + gmp-6.3.0/mini-gmp/tests/t-pprime_p.c | 183 + gmp-6.3.0/mini-gmp/tests/t-reuse.c | 663 ++++ gmp-6.3.0/mini-gmp/tests/t-root.c | 95 + gmp-6.3.0/mini-gmp/tests/t-scan.c | 90 + gmp-6.3.0/mini-gmp/tests/t-signed.c | 348 ++ gmp-6.3.0/mini-gmp/tests/t-sqrt.c | 181 + gmp-6.3.0/mini-gmp/tests/t-str.c | 332 ++ gmp-6.3.0/mini-gmp/tests/t-sub.c | 71 + gmp-6.3.0/mini-gmp/tests/testutils.c | 196 ++ gmp-6.3.0/mini-gmp/tests/testutils.h | 42 + 45 files changed, 13163 insertions(+) create mode 100644 gmp-6.3.0/mini-gmp/ChangeLog create mode 100644 gmp-6.3.0/mini-gmp/README create mode 100644 gmp-6.3.0/mini-gmp/mini-gmp.c create mode 100644 gmp-6.3.0/mini-gmp/mini-gmp.h create mode 100644 gmp-6.3.0/mini-gmp/mini-mpq.c create mode 100644 gmp-6.3.0/mini-gmp/mini-mpq.h create mode 100644 gmp-6.3.0/mini-gmp/tests/Makefile create mode 100644 gmp-6.3.0/mini-gmp/tests/hex-random.c create mode 100644 gmp-6.3.0/mini-gmp/tests/hex-random.h create mode 100644 gmp-6.3.0/mini-gmp/tests/mini-random.c create mode 100644 gmp-6.3.0/mini-gmp/tests/mini-random.h create mode 100755 gmp-6.3.0/mini-gmp/tests/run-tests create mode 100644 gmp-6.3.0/mini-gmp/tests/t-add.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-aorsmul.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-bitops.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-cmp_d.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-comb.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-cong.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-div.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-div_2exp.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-double.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-gcd.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-import.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-invert.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-lcm.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-limbs.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-logops.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-lucm.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-mpq_addsub.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-mpq_double.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-mpq_muldiv.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-mpq_muldiv_2exp.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-mpq_str.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-mul.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-powm.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-pprime_p.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-reuse.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-root.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-scan.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-signed.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-sqrt.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-str.c create mode 100644 gmp-6.3.0/mini-gmp/tests/t-sub.c create mode 100644 gmp-6.3.0/mini-gmp/tests/testutils.c create mode 100644 gmp-6.3.0/mini-gmp/tests/testutils.h (limited to 'gmp-6.3.0/mini-gmp') diff --git a/gmp-6.3.0/mini-gmp/ChangeLog b/gmp-6.3.0/mini-gmp/ChangeLog new file mode 100644 index 0000000..94b3738 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/ChangeLog @@ -0,0 +1,768 @@ +2023-07-20 Niels Möller + + * mini-gmp.c (gmp_umullo_limb): New macro, to avoid unintended + promotion to signed int, in case mp_limb_t is a size smaller than + int. In particular, mp_limb_t configured to be a 16-bit unsigned + short, with 32-bit int, leads to undefined signed overflow. + Problem reported by Vincent Lefevre. + (gmp_udiv_qrnnd_preinv, gmp_udiv_qr_3by2): Use new macro. + +2022-09-08 Marco Bodrato + + * tests/t-powm.c: Test some corner cases (e.g. 1^0 mod 1). + +2022-09-05 Niels Möller + + * mini-gmp.c (mpz_powm): Fix case of x^0 (mod 1), should be 0. + Reported by Guido Vranken. + +2022-05-29 Marco Bodrato + + * mini-mpq.c (mpq_helper_2exp): New helper (internal) function. + +2022-04-18 Niels Möller + + * mini-gmp.c (gmp_assert_nocarry): Avoid warning about unused + variable in NDEBUG builds. Reported by Paul Egggert. + +2022-04-17 Marco Bodrato + * mini-mpq.c (mpq_helper_canonicalize): Remove tmp parameter. + +2022-03-19 Marco Bodrato + + * mini-gmp.c (mpz_swap): Use MPN_PTR_SWAP, tx Paul Eggert. + +2021-10-01 Marco Bodrato + + * mini-gmp.c: Add asserts (removed at compile time) on limb size. + * mini-mpq.c: Add #defines needed if mini-gmp.h is not included. + +2021-08-02 Marco Bodrato + + * mini-gmp.c (mpz_rootrem): Better initial guess. + (gmp_stronglucas): Shortcut, mpn_common_scan instead of mpz_scan0. + +2021-05-13 Marco Bodrato + + * tests/t-reuse.c: Use numberof() to reduce the risk of typos. + +2021-04-16 Marco Bodrato + + * mini-gmp.c (gmp_millerrabin): Don't check unlikely 0 or 1. + * mini-gmp.h: Update FILE tests from gmp-h. + +2021-01-02 Marco Bodrato + + * mini-gmp.c (mpz_export): Correct error message (tx: Guillermo Monguia) + +2020-11-28 Marco Bodrato + + * mini-gmp.c (mpz_gcd): Support limbs larger than unsigned long. + * tests/t-invert.c: Likewise. + +2020-05-21 Torbjörn Granlund + + * tests/t-double.c: Provide default M_PI definition. + +2020-11-10 Marco Bodrato + + * tests/run-tests: Update WINEPATH, instead of overwriting it. + +2020-10-25 Marco Bodrato + + * mini-mpq.c (mpq_canonical_sign): Use the correct type for size. + +2020-10-18 Marco Bodrato + + * mini-gmp.c: Use mpn_scan1 instead of mpz_scan1. + (mpn_set_str_bits): Reduce branches and writes. + (mpz_gcdext): Delay mpz_setbit (t0, ...). + + * mini-mpq.c (mpq_out_str): Return 0 when base is out of range. + * mini-gmp.c (mpz_out_str): Likewise. (spotted by Paul Eggert) + + * tests/t-str.c: Test out-of-range bases for mpz_out_str. + * tests/t-mpq_str.c: Likewise, for mpq_out_str. + +2020-10-06 Niels Möller + + * tests/run-tests: Better support for make check on wine or cygwin. + +2020-09-10 Marco Bodrato + + * tests/t-mpq_double.c (mpq_get_d_exact_p): Cleanup. + + * mini-gmp.c (mpz_get_str): Explicit cast from void* to char*. + + * mini-gmp.h: Update FILE tests from gmp-h (tx Vincent Lefèvre). + +2020-05-27 Minux Ma + + Pass correct old_size to custom free and reallocate functions. + * mini-gmp.c (gmp_alloc): Renamed macro from... + (gmp_xalloc): .. old name. + (gmp_realloc): New macro, with old_size argument. + (gmp_free): Take size argument, and pass on. + (gmp_realloc_limbs): Add old_size argument, and rename from + (gmp_xrealloc_limbs): ... old name.. + (gmp_free_limbs): New function, with size argument. Lots of + updates, only non-trivial ones listed below. + (mpn_div_qr_1_preinv): Use gmp_free_limbs, simplify dealloc logic. + (mpz_get_str): Realloc result area when needed, to match final + digit count. + * mini-mpq.c (mpq_get_str, mpq_out_str, mpq_set_str): Pass correct + size to gmp_free_func. + * tests/testutils.c (tu_realloc, tu_free): Check that old_size + matches size in block header. + (testfree): Add size argument. Update all callers. + +2020-04-20 Niels Möller + + * mini-gmp.c (mpz_fits_slong_p): Simplify, by using mpz_cmp_si. + (mpz_fits_sint_p, mpz_fits_uint_p, mpz_fits_sshort_p) + (mpz_fits_ushort_p): New functions. + * mini-gmp.h: Declare new functions. + * tests/t-signed.c (try_fits_utype_p, try_fits_sint_p) + (try_fits_sshort_p): New tests. + +2020-02-02 Marco Bodrato + + * mini-gmp/mini-gmp.c (gmp_jacobi_coprime): Exit condition on a. + +2019-12-04 Marco Bodrato + + * mini-gmp/mini-gmp.c (mpn_invert_3by2): Remove shortcuts. + +2019-11-19 Marco Bodrato + + * mini-gmp/mini-gmp.c (mpn_invert_3by2): Shortcut for short limbs. + +2019-11-09 Marco Bodrato + + * mini-gmp/mini-gmp.c (gmp_clz, gmp_popcount_limb, mpz_export): + Avoid undefined behaviour with small limb sizes. + +2019-09-30 Niels Möller + + * tests/t-gcd.c (gcdext_valid_p): Stricter checks for gcdext + corner cases. + +2018-12-21 Marco Bodrato + + * mini-gmp/mini-gmp.c: Support for micro-gmp. + +2018-11-07 Marco Bodrato + + * mini-gmp/mini-gmp.c: Silence a couple of warnings. + +2018-10-30 Marco Bodrato + + * mini-gmp.c (mpz_probab_prime_p): BPSW test for primality. + + * tests/hex-random.c (hex_random_lucm_op): New function. + * tests/hex-random.h: Declare it. + * tests/mini-random.c (mini_random_lucm_op): New function. + * tests/mini-random.h: Declare it. + * mini-gmp/tests/t-lucm.c: New test + * mini-gmp/tests/Makefile (CHECK_PROGRAMS): Add t-lucm. + +2018-09-07 Niels Möller + + * tests/t-div.c (testmain): Add missing const declarations. + +2018-05-20 Marco Bodrato + + * mini-gmp.c (mpz_get_d): Convert a fixed number of + bits (GMP_DBL_MANT_BITS) to avoid rounding. + + * mini-mpq.c (mpq_mul): Use mpq_nan_init. + + * tests/t-double.c (test_matissa): Tests converted bits. + +2018-04-26 Marco Bodrato + + * mini-mpq.c: New file, mini-implementation of mpq_t. + * mini-mpq.h: New file, definitions for mpq_t. + * tests/t-mpq_addsub: New tests for mpq_add and sub. + * tests/t-mpq_muldiv: New tests for mpq_mul and div. + * tests/t-mpq_muldiv_2exp: New tests for mpq_*_2exp. + +2018-03-11 Niels Möller + + * mini-gmp.c (mpn_div_qr_2_preinv): Drop separate rp argument. + Clobber input np, and store remainder in np[0] and np[1]. This is + all the current caller needs, and it eliminates one allocation in + the common case of un-normalized d. + (mpn_div_qr_2): Delete #if:ed out function. + (mpn_div_qr_preinv): Update the only call site for + mpn_div_qr_2_preinv. + +2018-02-10 Niels Möller + + * mini-gmp.c (mpn_div_qr_1_preinv): When qp is non-NULL, reuse + area for shifted input, to avoid an allocation. + +2018-01-15 Marco Bodrato + + * mini-gmp.c (gmp_popcount_limb): Micro-optimisations. + * tests/t-comb.c (checkWilson): Check also mpz_2fac_ui. + +2017-12-30 Marco Bodrato + + * mini-gmp.c (mpz_mfac_ui, mpz_2fac_ui): New functions. + * mini-gmp.h: Declare them. + * mini-gmp.c (mpz_fac_ui): Use mpz_mfac_ui. + +2017-07-23 Niels Möller + + * mini-gmp.c (GMP_MPN_OVERLAP_P): New macro, copy of + MPN_OVERLAP_P, from gmp-impl.h. + (mpn_mul): Assert that output area doesn't overlap with the input. + +2017-02-03 Marco Bodrato + + * mini-gmp.c (mpz_sizeinbase, mpz_get_str, mpz_set_str): Support + bases up to 62. + * tests/t-str.c: Update tests accordingly. + +2016-11-27 Marco Bodrato + + * mini-gmp.c (mpz_get_si): fewer branches, safer forumla for negatives. + + * tests/t-signed.c: Removed a typo + +2016-11-24 Niels Möller + + * tests/hex-random.c (mkseed): Produce a 48-bit mpz_t value, + regardless of word size. + (hex_random_init): Use gmp_randseed instead of gmp_randseed_ui, + and support seeds exceeding an unsigned long. + + * tests/hex-random.c (mkseed): New function, using /dev/urandom + for random seed when available. + (hex_random_init): Use it. + +2016-11-23 Niels Möller + + * mini-gmp.c (GMP_CMP): New macro. + (mpz_sgn, mpz_cmp_si, mpz_cmp_ui, mpz_cmpabs_ui): Use it. + +2016-11-22 Niels Möller + + * tests/t-invert.c (test_3by2, test_2by1): New functions, + extracted from testmain. + (testmain): Add test with inputs which triggered the + mpn_invert_3by2 bug (see 2016-11-16 entry). + +2016-11-21 Marco Bodrato + + * tests/t-signed.c: compare different signs, and after overflow. + +2016-11-20 Niels Möller + + * tests/t-signed.c: Reorganize testcase, to avoid undefined + behaviour with signed overflow. + +2016-11-19 Niels Möller + + * tests/run-tests: Set up LD_LIBRARY_PATH and DYLD_LIBRARY_PATH + for tests only, based on TEST_LIBRARY_PATH. + + * tests/mini-random.h: Use name "../mini-gmp.h" for include, so we + don't need any -I options to the compiler. + + * tests/Makefile: Pass CFLAGS to the linker, as + recommended by the GNU coding standard. + (CPPFLAGS): New variable, with empty default value. + (CFLAGS): Remove the -I flag involving MINI_GMP_DIR, to leave free + for overriding on make command line. + (EXTRA_CFLAGS): Deleted variable, no longer needed. + +2016-11-18 Torbjörn Granlund + + * tests/Makefile: Pass EXTRA_CFLAGS to linker as a intermediate fix. + +2016-11-17 Marco Bodrato + + * tests/t-str.c: free a pointer to avoid memory leaks. + +2016-11-16 Niels Möller + + * mini-gmp.c (mpn_invert_3by2): Fix arithmetic overflow + bug, and improve documentation of the algorithm. + +2016-11-15 Niels Möller + + * tests/t-limbs.c (testmain): Skip tests with zero product. + + * tests/hex-random.c (hex_random_init): Added fflush call. + +2016-11-15 Torbjörn Granlund + + * tests/Makefile (TESTS): New variable, allowing separation of + compilation and running of tests. + * tests/run-tests: Allow empty tests list. + +2016-11-14 Marco Bodrato + + * tests/t-str.c: Some more test cases. + * tests/t-pprime_p.c: Use shorter operands, with different sizes. + +2016-11-01 Torbjörn Granlund + + * tests/hex-random.c: Reinstate gmp.h inclusion. + +2016-08-22 Niels Möller + + * mini-gmp.c (mpn_set_str_other): Always return size >= 1, with + unnormalized result in the case the input digits are all zero. + Fixes crash on a large number of leading zeros, reported by Axel + Miller. + (mpz_set_str): Normalize as needed, after above change. Return + failure for inputs string with no digits, i.e., empty except for + optional sign, base prefix and white space. + +2016-01-01 Marco Bodrato + + * mini-gmp.c: Silence warnings due to (un)signed types. + * tests/testutils.c: Likewise. + * tests/t-logops.c: Likewise. + * tests/t-cmp_d.c: Likewise. + * tests/t-reuse.c: Likewise. + * tests/t-cong.c: Likewise. + +2015-11-13 Marco Bodrato + + * mini-gmp.c: Lazy allocation for mpz_t. + (mpz_rootrem): Exploit lazy allocation to avoid init2. + +2015-11-06 Marco Bodrato + + * mini-gmp.c (mpn_com, mpn_neg): New functions. + * mini-gmp.h: Declare them. + * mini-gmp.c (mpz_div_r_2exp): Use mpn_neg. + +2015-10-29 Marco Bodrato + + * mini-gmp.c: Removed a typo (spotted by Paul Zimmermann). + +2015-05-30 Marco Bodrato + + * mini-gmp.h: Declare mpn_zero_p. + * mini-gmp.c: Define mpn_zero_p as a function, not a macro. + +2014-08-27 Niels Möller + + * mini-gmp.c (mpz_abs_sub_bit): Do full normalization, + needed if mpz_clrbit clears the most significant one bit. + +2014-07-28 Marco Bodrato + + * mini-gmp.c: Remove some useless variables. + +2014-05-20 Marco Bodrato + + * mini-gmp.c: +1 in the init2 argument before setbit. + +2014-05-15 Marco Bodrato + + * mini-gmp.c: Micro-optimisations. + +2014-03-12 Marco Bodrato + + * mini-gmp.c (mpz_probab_prime_p): Micro-optimisation. + +2014-03-06 Niels Möller + + * mini-gmp.c (gmp_millerrabin): New internal function. + (mpz_probab_prime_p): New function. + * mini-gmp.h (mpz_probab_prime_p): Declare it. + * tests/t-pprime_p.c: New test program. + * tests/Makefile (CHECK_PROGRAMS): Added t-pprime_p. + +2014-03-03 Niels Möller + + * mini-gmp.c (mpz_congruent_p): New function. + * mini-gmp.h: Declare it. + * tests/t-cong.c: New file, based on tests/mpz/t-cong.c. + * tests/Makefile (CHECK_PROGRAMS): Added t-cong. + + * tests/testutils.c (dump): New function. Deleted static + functions in other files. + (mpz_set_str_or_abort): Moved function here, from... + * tests/t-cmp_d.c: ... old location. + + * tests/t-reuse.c (dump3): Renamed, from ... + (dump): ...old name. + +2014-02-21 Marco Bodrato + + * mini-gmp.c (mpn_sqrtrem): New function. + * mini-gmp.h: Declare it. + * tests/t-sqrt.c: Test it. + +2014-02-15 Marco Bodrato + + * mini-gmp.c (mpz_div_qr): init + set = init_set . + +2014-02-10 Marco Bodrato + + * tests/t-limbs.c: New test for mpz_limbs_*. + * tests/Makefile (CHECK_PROGRAMS): Add it. + +2014-02-08 Marco Bodrato + + * mini-gmp.c (mpz_realloc2, mpz_limbs_read, mpz_limbs_modify + mpz_limbs_write, mpz_limbs_finish, mpz_roinit_n): New functions. + (mpn_perfect_square_p): New function. + * mini-gmp.h: Declare them. + + * tests/t-mul.c: Use roinit and limbs_read to test mpn. + * tests/t-sqrt.c: Test also mpn_perfect_square_p. + +2014-02-03 Marco Bodrato + + * mini-gmp.c (mpn_rootrem): Allow NULL argument. + + * mini-gmp.c (mpn_zero): New function. + (mpz_perfect_square_p): New function. + * mini-gmp.h: Declare them. + + * tests/t-sqrt.c: Test mpz_perfect_square_p. + * tests/t-root.c: Test also 1-th root, allow perfect powers. + +2014-01-23 Marco Bodrato + + * tests/t-aorsmul.c: New file, test for mpz_{add,sub}mul{,_ui} + * tests/Makefile: Add t-aorsmul. + +2014-01-19 Marco Bodrato + + * mini-gmp.c (mpn_popcount): New function. + (mpz_popcount): Use it. + (mpz_addmul_ui, mpz_addmul, mpz_submul_ui, mpz_submul): Added. + * mini-gmp.h: Declare them. + +2014-01-16 Niels Möller + + * mini-gmp.c (mp_bits_per_limb): New const value. + * mini-gmp.h: Declare it. + +2013-03-13 Marco Bodrato + + * mini-gmp.c: Write loops in a cleaner way. + +2013-02-27 Marco Bodrato + + * mini-gmp.c (mpz_div_q_2exp): Adjust only if needed. + (mpn_common_scan): New service function to unify scan loops. + (mpz_scan0, mpz_scan1): Simplify by using mpn_common_scan. + (mpz_make_odd): Simplify, assume in-place operation on positive. + (mpn_scan0, mpn_scan1): New functions. + * mini-gmp.h (mpn_scan0, mpn_scan1): New declarations. + * tests/t-scan.c: Test also mpn_scan0 and mpn_scan1. + +2013-02-25 Niels Möller + + * tests/t-double.c (testmain): Declare double variables as + volatile, to drop extended precision. + + * tests/testutils.c (testfree): New function. Use it everywhere + where test programs deallocate storage allocated via the mini-gmp + allocation functions, including uses of mpz_get_str for various + test failure messages. + +2013-02-19 Marco Bodrato + + * mini-gmp.c: Move asserts to work-around a compiler bug. + (mpz_export): Reorder branches. + (mpz_mul_ui): Avoid temporary allocation (mpn_mul_1 can work in-place). + + * tests/t-reuse.c: Fix typo causing the same negation condition to + be applied to all operands. (See 2013-02-03, Torbjorn) + +2013-02-17 Marco Bodrato + + * mini-gmp.c (mpz_mul): Read sizes just once. + (mpn_set_str_other): Remove a redundant variable. + (mpz_abs_add): Use SWAP once, to order sizes. + (mpz_mul_ui): Micro-optimisation. + (mpz_rootrem): Use _init2 before _setbit. + (mpz_set_str): Optimise-out a variable. + (mpz_import): Normalise only if needed. + (mpn_div_qr_1): Speed-up the d=1 case, delaying a branch. + +2013-02-12 Marco Bodrato + + * mini-gmp.c (fac_ui, bin_uiui): Use shorter and faster code. + + * mini-gmp.c: Reduce branches. + +2013-01-23 Marco Bodrato + + * mini-gmp.c (mpz_cmpabs_d, mpz_cmp_d): Simplify. + (mpz_set_str): Behaviour more adherent to the real GMP. + + * tests/t-str.c: Cast size_t to unsigned long, for printf. + * tests/t-import.c: Likewise. + * tests/t-comb.c: Remove an unused var. + * tests/t-div.c: Remove unused args passed to fprintf. + * tests/t-double.c: Use float immediates with float vars. + +2013-01-22 Niels Möller + + * mini-gmp.c (mpz_cmp_d): Simplified, just sort out signs, then + call mpz_cmpabs_d. + + * tests/testutils.h: Include stdio.h and stdlib.h. + (numberof): New define. + + * tests/t-cmp_d.c: New file, copied from tests/mpz/t-cmp_d.c with + minor changes. + * tests/Makefile (CHECK_PROGRAMS): Added t-cmp_d, + + * mini-gmp.c (mpz_cmpabs_d): New function. + * mini-gmp.h: Declare it. + +2013-01-21 Niels Möller + + * tests/t-str.c (testmain): Test mpz_out_str, using + the tmpfile function for i/o. + +2013-01-20 Marco Bodrato + + * tests/testutils.c (testhalves): New function, test default + memory functions. + * tests/testutils.h (testhalves): Declare it + * tests/t-logops.c: Use testhalves. + + * mini-gmp.c (mpz_init_set_str): New function. + * mini-gmp.h (mpz_init_set_str): Declare it. + * tests/t-str.c: Test mpz_init_set_str. + +2013-01-19 Marco Bodrato + + * tests/t-double.c (testmain): Get the current free + function using mp_get_memory_functions. + * tests/t-str.c (testmain): Likewise. + + * tests/testutils.h (tu_free): Remove declaration. + + * tests/testutils.c (block_check, tu_free): Mark static. + +2013-01-18 Niels Möller + + * tests/t-str.c (test_small): New function, exercising + parsing of whitespace and base prefixes. + (testmain): Call it. + + * tests/t-gcd.c (gcdext_valid_p): Fixed memory leak. + + * tests/t-double.c (testmain): Call tu_free rather than + free, for storage allocated by mpz_get_str. + * tests/t-str.c (testmain): Likewise. + + * tests/testutils.c (block_init, block_check): New functions. + (tu_alloc, tu_realloc, tu_free): New functions. + (main): Use mp_set_memory_functions. + * tests/testutils.h (tu_free): Declare. + + * tests/testutils.h: New file, declarations for test programs. + + * tests/testutils.c (main): New file, with shared main + function for all the test programs. Also includes mini-gmp.c. + Calls testmain after initialization. All other test programs + updated to define testmain rather than main. + +2013-01-18 Marco Bodrato + + * tests/t-signed.c: Slightly larger coverage. + * tests/t-double.c: Test also mpz_init_set_d. + +2013-01-18 Torbjorn Granlund + + * tests/t-div.c: Test mpz_divisible_p and mpz_divisible_ui_p. + + * tests/t-div.c: Test also mpz_mod, mpz_mod_ui. Compare + mpz_divisible_p just to ceil, to save time. + + * mini-gmp.c: Prefix some names with GMP_. + +2013-01-16 Marco Bodrato + + * tests/t-double.c: Test mpz_cmp_d. + * mini-gmp.c (mpz_cmp_d): Correct multiword comparison. + + * mini-gmp.c (mpz_set_str): Handle the empty string. + * tests/t-str.c: Test base <= 0. + +2013-01-15 Niels Möller + + * tests/t-str.c (main): Use x->_mp_d rather than x[0]._mp_d. + * tests/t-invert.c (main): Likewise. + + * tests/t-mul.c (main): Test mpn_mul_n and mpn_sqr. + + * tests/hex-random.h (enum hex_random_op): New value OP_SQR. + + * tests/mini-random.c (mini_random_op3): Renamed, from... + (mini_random_op): ... old name. Updated callers. + (mini_random_op2): New function. + + * tests/hex-random.c (hex_random_op3): Renamed, from... + (hex_random_op): ... old name. Updated callers. + (hex_random_op2): New function. + +2013-01-15 Marco Bodrato + + * tests/t-logops.c: Improve popcount/hamdist testing. + * tests/t-signed.c: Test more cases. + +2013-01-14 Niels Möller + + * tests/t-str.c (main): Added tests for mpn_get_str and + mpn_set_str. + +2013-01-11 Marco Bodrato + + * tests/t-comb.c: New test program, testing both + mpz_fac_ui and mpz_bin_uiui. + * tests/Makefile (CHECK_PROGRAMS): Added t-comb. + + * mini-gmp.c (mpz_mul_si): Simplify. + (mpz_mul_ui, mpz_mul, mpz_div_qr): Replace init+REALLOC with init2. + + * mini-gmp.c (NEG_CAST): New macro. + (mpz_mul_si, mpz_set_si, mpz_cmp_si): Use NEG_CAST. + + * mini-gmp.c (mpz_set_si, mpz_cmp_si): Simplify by using + the _ui variant. + + * tests/t-root.c: Use mpz_ui_pow_ui, when base fits an ui. + + * tests/t-mul.c: Test also mpz_mul_si. + * tests/t-sub.c: Test also mpz_ui_sub. + + * mini-gmp.c (mpz_fits_slong_p): Correct range. + * tests/t-signed.c: New test program, for get/set/cmp_si. + * tests/Makefile (CHECK_PROGRAMS): Added t-signed. + + * mini-gmp.c (mpz_hamdist): Handle different sizes. + * tests/t-logops.c: Test also popcount and hamdist. + +2013-01-10 Marco Bodrato + + * mini-gmp.c (mpz_export, mpz_import): Less restrictive ASSERTs. + * tests/t-import.c: Test also size=0 or count=0. + +2013-01-10 Torbjorn Granlund + + * tests/t-import.c (main): Don't drop off function end. + +2013-01-09 Marco Bodrato + + * mini-gmp.c (mpz_export): Support op=0 countp=NULL. + +2013-01-08 Niels Möller + + * tests/t-import.c: New test program, testing both + mpz_import and mpz_export. + * tests/Makefile (CHECK_PROGRAMS): Added t-import. + + * tests/mini-random.c (mini_rrandomb_export): New function. + * tests/mini-random.h: Declare it. + * tests/hex-random.c (hex_rrandomb_export): New function. + * tests/hex-random.h: Declare it. + + * mini-gmp.c (mpz_export): Compute accurate word count up + front, to avoid generating any high zero words. + +2013-01-07 Marco Bodrato + + * README: Document base limitation for conversions. + * mini-gmp.c (mpz_set_str): Remove goto. + (mpz_import, mpz_export): Correctly use order/endianness. + +2013-01-04 Marco Bodrato + + From shuax: + * mini-gmp.c (mpz_import): Reset limb after storing it. + +2012-11-22 Niels Möller + + * tests/run-tests: Copied latest version from GNU Nettle. + Minor fix to the use of $EMULATOR, and proper copyright notice. + +2012-06-24 Marco Bodrato + + * mini-gmp.c (mpz_div_r_2exp, mpz_div_q_2exp): Improve + adjustment condition. + +2012-06-08 Marco Bodrato + + * mini-gmp.c (mpz_realloc): remove a branch. + +2012-05-25 Marco Bodrato + + * tests/t-div.c: Test all _qr, _q, _r variants. + * tests/t-lcm.c: Test the _ui variant. + + * mini-gmp.c (mpz_mod, mpz_mod_ui): New functions. + * mini-gmp.h (mpz_mod, mpz_mod_ui): Prototypes. + +2012-05-09 Marco Bodrato + + * mini-gmp.c: merge mpz_rootrem and mpz_sqrtrem. + +2012-04-13 Marco Bodrato + + * mini-gmp.h (mpz_fac_ui, mpz_bin_uiui): New definitions. + * mini-gmp.c (mpz_fac_ui, mpz_bin_uiui): Trivial implementation. + +2012-04-11 Marco Bodrato + + * mini-gmp.h (mpz_root, mpz_rootrem): define (correctly). + * mini-gmp.c (mpz_rootrem): Extended code from _root. + (mpz_root): Use mpz_rootrem. + (mpz_mul_ui): Correctly handle negative operands. + + * tests/Makefile (CHECK_PROGRAMS): add t-root. + * tests/t-root.c: New file. + * tests/t-reuse.c: Enable root{,rem} tests. + +2012-04-10 Marco Bodrato + + * mini-gmp.c (mpz_root): New, support negative operands. + * mini-gmp.h (mpz_root): define. + (mpz_out_str): Test also __STDIO_LOADED (for VMS). + * mpz/2fac_ui.c: Cosmetic change. + + * tests/t-reuse.c: New test case, based on tests/mpz/reuse.c. + + * mini-gmp.c (mpz_cdiv_r_ui): New function. + (mpz_fdiv_r_ui): New function. + (mpz_tdiv_r_ui): New function. + (mpz_powm_ui): New function. + (mpz_pow_ui): New function. + (mpz_ui_pow_ui): Use mpz_pow_ui. + (mpz_gcdext): Fixed input/output overlap, for the case of one + input being zero. + (mpz_sqrtrem): Fix for the case r NULL, U zero. + +2012-02-28 Niels Möller + + * tests/Makefile (srcdir, MINI_GMP_DIR): New make variables. These + can be overridden when using a separate build directory. + (EXTRA_CFLAGS): Renamed, was OPTFLAGS. + + * mini-gmp.c (mpz_abs_add): Don't cache limb pointers + over MPZ_REALLOC, since that breaks in-place operation. Bug + spotted by Torbjörn. + (mpz_and, mpz_ior, mpz_xor): Likewise. + (mpz_cmp): Fixed comparison of negative numbers. + +2012-02-26 Niels Möller + + * mini-gmp: New subdirectory. For use by GMP bootstrap, and as a + fallback for applications needing bignums but not high + performance. diff --git a/gmp-6.3.0/mini-gmp/README b/gmp-6.3.0/mini-gmp/README new file mode 100644 index 0000000..fd54054 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/README @@ -0,0 +1,72 @@ +Copyright 2011-2013, 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/. + + +This is "mini-gmp", a small implementation of a subset of GMP's mpn, +mpz and mpq interfaces. + +It is intended for applications which need arithmetic on numbers +larger than a machine word, but which don't need to handle very large +numbers very efficiently. Those applications can include a copy of +mini-gmp to get a GMP-compatible interface with small footprint. One +can also arrange for optional linking with the real GMP library, using +mini-gmp as a fallback when for some reason GMP is not available, or +not desired as a dependency. + +The supported GMP subset of the mpn and mpz interfaces is declared in +mini-gmp.h, and implemented in mini-gmp.c. The implemented +functions are fully compatible with the corresponding GMP functions, +as specified in the GMP manual, with a few exceptions: + + mpz_export and mpz_import support only NAILS = 0. + +The performance target for mini-gmp is to be at most 10 times slower +than the real GMP library, for numbers of size up to a few hundred +bits. No asymptotically fast algorithms are included in mini-gmp, so +it will be many orders of magnitude slower than GMP for very large +numbers. + +The supported GMP subset of the mpq layer is declared in mini-mpq.h, +and implemented in mini-mpq.c. + +You should never "install" mini-gmp. Applications can either just +#include mini-gmp.c (but then, beware that it defines several macros +and functions outside of the advertised interface), and if needed +#include mini-mpq.c in a later line (order is important). Or compile +mini-gmp.c and mini-mpq.c as separate compilation units, and use the +declarations in mini-gmp.h and mini-mpq.h. + +The tests subdirectory contains a testsuite. To use it, you need GMP +and GNU make. Just run make check in the tests directory. If the +hard-coded compiler settings are not right, you have to either edit the +Makefile or pass overriding values on the make command line (e.g., +make CC=cc check). + +The initial version of mini-gmp was put together by Niels Möller +, with a fair amount of copy-and-paste from the +GMP sources. diff --git a/gmp-6.3.0/mini-gmp/mini-gmp.c b/gmp-6.3.0/mini-gmp/mini-gmp.c new file mode 100644 index 0000000..69a72bf --- /dev/null +++ b/gmp-6.3.0/mini-gmp/mini-gmp.c @@ -0,0 +1,4627 @@ +/* mini-gmp, a minimalistic implementation of a GNU GMP subset. + + Contributed to the GNU project by Niels Möller + Additional functionalities and improvements by Marco Bodrato. + +Copyright 1991-1997, 1999-2022 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/. */ + +/* NOTE: All functions in this file which are not declared in + mini-gmp.h are internal, and are not intended to be compatible + with GMP or with future versions of mini-gmp. */ + +/* Much of the material copied from GMP files, including: gmp-impl.h, + longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c, + mpn/generic/lshift.c, mpn/generic/mul_1.c, + mpn/generic/mul_basecase.c, mpn/generic/rshift.c, + mpn/generic/sbpi1_div_qr.c, mpn/generic/sub_n.c, + mpn/generic/submul_1.c. */ + +#include +#include +#include +#include +#include +#include + +#include "mini-gmp.h" + +#if !defined(MINI_GMP_DONT_USE_FLOAT_H) +#include +#endif + + +/* Macros */ +#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT) + +#define GMP_LIMB_MAX ((mp_limb_t) ~ (mp_limb_t) 0) +#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1)) + +#define GMP_HLIMB_BIT ((mp_limb_t) 1 << (GMP_LIMB_BITS / 2)) +#define GMP_LLIMB_MASK (GMP_HLIMB_BIT - 1) + +#define GMP_ULONG_BITS (sizeof(unsigned long) * CHAR_BIT) +#define GMP_ULONG_HIGHBIT ((unsigned long) 1 << (GMP_ULONG_BITS - 1)) + +#define GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) +#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1)) + +#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b)) +#define GMP_MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define GMP_CMP(a,b) (((a) > (b)) - ((a) < (b))) + +#if defined(DBL_MANT_DIG) && FLT_RADIX == 2 +#define GMP_DBL_MANT_BITS DBL_MANT_DIG +#else +#define GMP_DBL_MANT_BITS (53) +#endif + +/* Return non-zero if xp,xsize and yp,ysize overlap. + If xp+xsize<=yp there's no overlap, or if yp+ysize<=xp there's no + overlap. If both these are false, there's an overlap. */ +#define GMP_MPN_OVERLAP_P(xp, xsize, yp, ysize) \ + ((xp) + (xsize) > (yp) && (yp) + (ysize) > (xp)) + +#define gmp_assert_nocarry(x) do { \ + mp_limb_t __cy = (x); \ + assert (__cy == 0); \ + (void) (__cy); \ + } while (0) + +#define gmp_clz(count, x) do { \ + mp_limb_t __clz_x = (x); \ + unsigned __clz_c = 0; \ + int LOCAL_SHIFT_BITS = 8; \ + if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS) \ + for (; \ + (__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0; \ + __clz_c += 8) \ + { __clz_x <<= LOCAL_SHIFT_BITS; } \ + for (; (__clz_x & GMP_LIMB_HIGHBIT) == 0; __clz_c++) \ + __clz_x <<= 1; \ + (count) = __clz_c; \ + } while (0) + +#define gmp_ctz(count, x) do { \ + mp_limb_t __ctz_x = (x); \ + unsigned __ctz_c = 0; \ + gmp_clz (__ctz_c, __ctz_x & - __ctz_x); \ + (count) = GMP_LIMB_BITS - 1 - __ctz_c; \ + } while (0) + +#define gmp_add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + mp_limb_t __x; \ + __x = (al) + (bl); \ + (sh) = (ah) + (bh) + (__x < (al)); \ + (sl) = __x; \ + } while (0) + +#define gmp_sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + mp_limb_t __x; \ + __x = (al) - (bl); \ + (sh) = (ah) - (bh) - ((al) < (bl)); \ + (sl) = __x; \ + } while (0) + +#define gmp_umul_ppmm(w1, w0, u, v) \ + do { \ + int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS; \ + if (sizeof(unsigned int) * CHAR_BIT >= 2 * GMP_LIMB_BITS) \ + { \ + unsigned int __ww = (unsigned int) (u) * (v); \ + w0 = (mp_limb_t) __ww; \ + w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS); \ + } \ + else if (GMP_ULONG_BITS >= 2 * GMP_LIMB_BITS) \ + { \ + unsigned long int __ww = (unsigned long int) (u) * (v); \ + w0 = (mp_limb_t) __ww; \ + w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS); \ + } \ + else { \ + mp_limb_t __x0, __x1, __x2, __x3; \ + unsigned __ul, __vl, __uh, __vh; \ + mp_limb_t __u = (u), __v = (v); \ + assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t)); \ + \ + __ul = __u & GMP_LLIMB_MASK; \ + __uh = __u >> (GMP_LIMB_BITS / 2); \ + __vl = __v & GMP_LLIMB_MASK; \ + __vh = __v >> (GMP_LIMB_BITS / 2); \ + \ + __x0 = (mp_limb_t) __ul * __vl; \ + __x1 = (mp_limb_t) __ul * __vh; \ + __x2 = (mp_limb_t) __uh * __vl; \ + __x3 = (mp_limb_t) __uh * __vh; \ + \ + __x1 += __x0 >> (GMP_LIMB_BITS / 2);/* this can't give carry */ \ + __x1 += __x2; /* but this indeed can */ \ + if (__x1 < __x2) /* did we get it? */ \ + __x3 += GMP_HLIMB_BIT; /* yes, add it in the proper pos. */ \ + \ + (w1) = __x3 + (__x1 >> (GMP_LIMB_BITS / 2)); \ + (w0) = (__x1 << (GMP_LIMB_BITS / 2)) + (__x0 & GMP_LLIMB_MASK); \ + } \ + } while (0) + +/* If mp_limb_t is of size smaller than int, plain u*v implies + automatic promotion to *signed* int, and then multiply may overflow + and cause undefined behavior. Explicitly cast to unsigned int for + that case. */ +#define gmp_umullo_limb(u, v) \ + ((sizeof(mp_limb_t) >= sizeof(int)) ? (u)*(v) : (unsigned int)(u) * (v)) + +#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di) \ + do { \ + mp_limb_t _qh, _ql, _r, _mask; \ + gmp_umul_ppmm (_qh, _ql, (nh), (di)); \ + gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl)); \ + _r = (nl) - gmp_umullo_limb (_qh, (d)); \ + _mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */ \ + _qh += _mask; \ + _r += _mask & (d); \ + if (_r >= (d)) \ + { \ + _r -= (d); \ + _qh++; \ + } \ + \ + (r) = _r; \ + (q) = _qh; \ + } while (0) + +#define gmp_udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv) \ + do { \ + mp_limb_t _q0, _t1, _t0, _mask; \ + gmp_umul_ppmm ((q), _q0, (n2), (dinv)); \ + gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1)); \ + \ + /* Compute the two most significant limbs of n - q'd */ \ + (r1) = (n1) - gmp_umullo_limb ((d1), (q)); \ + gmp_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0)); \ + gmp_umul_ppmm (_t1, _t0, (d0), (q)); \ + gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0); \ + (q)++; \ + \ + /* Conditionally adjust q and the remainders */ \ + _mask = - (mp_limb_t) ((r1) >= _q0); \ + (q) += _mask; \ + gmp_add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0)); \ + if ((r1) >= (d1)) \ + { \ + if ((r1) > (d1) || (r0) >= (d0)) \ + { \ + (q)++; \ + gmp_sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0)); \ + } \ + } \ + } while (0) + +/* Swap macros. */ +#define MP_LIMB_T_SWAP(x, y) \ + do { \ + mp_limb_t __mp_limb_t_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mp_limb_t_swap__tmp; \ + } while (0) +#define MP_SIZE_T_SWAP(x, y) \ + do { \ + mp_size_t __mp_size_t_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mp_size_t_swap__tmp; \ + } while (0) +#define MP_BITCNT_T_SWAP(x,y) \ + do { \ + mp_bitcnt_t __mp_bitcnt_t_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mp_bitcnt_t_swap__tmp; \ + } while (0) +#define MP_PTR_SWAP(x, y) \ + do { \ + mp_ptr __mp_ptr_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mp_ptr_swap__tmp; \ + } while (0) +#define MP_SRCPTR_SWAP(x, y) \ + do { \ + mp_srcptr __mp_srcptr_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mp_srcptr_swap__tmp; \ + } while (0) + +#define MPN_PTR_SWAP(xp,xs, yp,ys) \ + do { \ + MP_PTR_SWAP (xp, yp); \ + MP_SIZE_T_SWAP (xs, ys); \ + } while(0) +#define MPN_SRCPTR_SWAP(xp,xs, yp,ys) \ + do { \ + MP_SRCPTR_SWAP (xp, yp); \ + MP_SIZE_T_SWAP (xs, ys); \ + } while(0) + +#define MPZ_PTR_SWAP(x, y) \ + do { \ + mpz_ptr __mpz_ptr_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mpz_ptr_swap__tmp; \ + } while (0) +#define MPZ_SRCPTR_SWAP(x, y) \ + do { \ + mpz_srcptr __mpz_srcptr_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mpz_srcptr_swap__tmp; \ + } while (0) + +const int mp_bits_per_limb = GMP_LIMB_BITS; + + +/* Memory allocation and other helper functions. */ +static void +gmp_die (const char *msg) +{ + fprintf (stderr, "%s\n", msg); + abort(); +} + +static void * +gmp_default_alloc (size_t size) +{ + void *p; + + assert (size > 0); + + p = malloc (size); + if (!p) + gmp_die("gmp_default_alloc: Virtual memory exhausted."); + + return p; +} + +static void * +gmp_default_realloc (void *old, size_t unused_old_size, size_t new_size) +{ + void * p; + + p = realloc (old, new_size); + + if (!p) + gmp_die("gmp_default_realloc: Virtual memory exhausted."); + + return p; +} + +static void +gmp_default_free (void *p, size_t unused_size) +{ + free (p); +} + +static void * (*gmp_allocate_func) (size_t) = gmp_default_alloc; +static void * (*gmp_reallocate_func) (void *, size_t, size_t) = gmp_default_realloc; +static void (*gmp_free_func) (void *, size_t) = gmp_default_free; + +void +mp_get_memory_functions (void *(**alloc_func) (size_t), + void *(**realloc_func) (void *, size_t, size_t), + void (**free_func) (void *, size_t)) +{ + if (alloc_func) + *alloc_func = gmp_allocate_func; + + if (realloc_func) + *realloc_func = gmp_reallocate_func; + + if (free_func) + *free_func = gmp_free_func; +} + +void +mp_set_memory_functions (void *(*alloc_func) (size_t), + void *(*realloc_func) (void *, size_t, size_t), + void (*free_func) (void *, size_t)) +{ + if (!alloc_func) + alloc_func = gmp_default_alloc; + if (!realloc_func) + realloc_func = gmp_default_realloc; + if (!free_func) + free_func = gmp_default_free; + + gmp_allocate_func = alloc_func; + gmp_reallocate_func = realloc_func; + gmp_free_func = free_func; +} + +#define gmp_alloc(size) ((*gmp_allocate_func)((size))) +#define gmp_free(p, size) ((*gmp_free_func) ((p), (size))) +#define gmp_realloc(ptr, old_size, size) ((*gmp_reallocate_func)(ptr, old_size, size)) + +static mp_ptr +gmp_alloc_limbs (mp_size_t size) +{ + return (mp_ptr) gmp_alloc (size * sizeof (mp_limb_t)); +} + +static mp_ptr +gmp_realloc_limbs (mp_ptr old, mp_size_t old_size, mp_size_t size) +{ + assert (size > 0); + return (mp_ptr) gmp_realloc (old, old_size * sizeof (mp_limb_t), size * sizeof (mp_limb_t)); +} + +static void +gmp_free_limbs (mp_ptr old, mp_size_t size) +{ + gmp_free (old, size * sizeof (mp_limb_t)); +} + + +/* MPN interface */ + +void +mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n) +{ + mp_size_t i; + for (i = 0; i < n; i++) + d[i] = s[i]; +} + +void +mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n) +{ + while (--n >= 0) + d[n] = s[n]; +} + +int +mpn_cmp (mp_srcptr ap, mp_srcptr bp, mp_size_t n) +{ + while (--n >= 0) + { + if (ap[n] != bp[n]) + return ap[n] > bp[n] ? 1 : -1; + } + return 0; +} + +static int +mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn) +{ + if (an != bn) + return an < bn ? -1 : 1; + else + return mpn_cmp (ap, bp, an); +} + +static mp_size_t +mpn_normalized_size (mp_srcptr xp, mp_size_t n) +{ + while (n > 0 && xp[n-1] == 0) + --n; + return n; +} + +int +mpn_zero_p(mp_srcptr rp, mp_size_t n) +{ + return mpn_normalized_size (rp, n) == 0; +} + +void +mpn_zero (mp_ptr rp, mp_size_t n) +{ + while (--n >= 0) + rp[n] = 0; +} + +mp_limb_t +mpn_add_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b) +{ + mp_size_t i; + + assert (n > 0); + i = 0; + do + { + mp_limb_t r = ap[i] + b; + /* Carry out */ + b = (r < b); + rp[i] = r; + } + while (++i < n); + + return b; +} + +mp_limb_t +mpn_add_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n) +{ + mp_size_t i; + mp_limb_t cy; + + for (i = 0, cy = 0; i < n; i++) + { + mp_limb_t a, b, r; + a = ap[i]; b = bp[i]; + r = a + cy; + cy = (r < cy); + r += b; + cy += (r < b); + rp[i] = r; + } + return cy; +} + +mp_limb_t +mpn_add (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn) +{ + mp_limb_t cy; + + assert (an >= bn); + + cy = mpn_add_n (rp, ap, bp, bn); + if (an > bn) + cy = mpn_add_1 (rp + bn, ap + bn, an - bn, cy); + return cy; +} + +mp_limb_t +mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b) +{ + mp_size_t i; + + assert (n > 0); + + i = 0; + do + { + mp_limb_t a = ap[i]; + /* Carry out */ + mp_limb_t cy = a < b; + rp[i] = a - b; + b = cy; + } + while (++i < n); + + return b; +} + +mp_limb_t +mpn_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n) +{ + mp_size_t i; + mp_limb_t cy; + + for (i = 0, cy = 0; i < n; i++) + { + mp_limb_t a, b; + a = ap[i]; b = bp[i]; + b += cy; + cy = (b < cy); + cy += (a < b); + rp[i] = a - b; + } + return cy; +} + +mp_limb_t +mpn_sub (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn) +{ + mp_limb_t cy; + + assert (an >= bn); + + cy = mpn_sub_n (rp, ap, bp, bn); + if (an > bn) + cy = mpn_sub_1 (rp + bn, ap + bn, an - bn, cy); + return cy; +} + +mp_limb_t +mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl) +{ + mp_limb_t ul, cl, hpl, lpl; + + assert (n >= 1); + + cl = 0; + do + { + ul = *up++; + gmp_umul_ppmm (hpl, lpl, ul, vl); + + lpl += cl; + cl = (lpl < cl) + hpl; + + *rp++ = lpl; + } + while (--n != 0); + + return cl; +} + +mp_limb_t +mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl) +{ + mp_limb_t ul, cl, hpl, lpl, rl; + + assert (n >= 1); + + cl = 0; + do + { + ul = *up++; + gmp_umul_ppmm (hpl, lpl, ul, vl); + + lpl += cl; + cl = (lpl < cl) + hpl; + + rl = *rp; + lpl = rl + lpl; + cl += lpl < rl; + *rp++ = lpl; + } + while (--n != 0); + + return cl; +} + +mp_limb_t +mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl) +{ + mp_limb_t ul, cl, hpl, lpl, rl; + + assert (n >= 1); + + cl = 0; + do + { + ul = *up++; + gmp_umul_ppmm (hpl, lpl, ul, vl); + + lpl += cl; + cl = (lpl < cl) + hpl; + + rl = *rp; + lpl = rl - lpl; + cl += lpl > rl; + *rp++ = lpl; + } + while (--n != 0); + + return cl; +} + +mp_limb_t +mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn) +{ + assert (un >= vn); + assert (vn >= 1); + assert (!GMP_MPN_OVERLAP_P(rp, un + vn, up, un)); + assert (!GMP_MPN_OVERLAP_P(rp, un + vn, vp, vn)); + + /* We first multiply by the low order limb. This result can be + stored, not added, to rp. We also avoid a loop for zeroing this + way. */ + + rp[un] = mpn_mul_1 (rp, up, un, vp[0]); + + /* Now accumulate the product of up[] and the next higher limb from + vp[]. */ + + while (--vn >= 1) + { + rp += 1, vp += 1; + rp[un] = mpn_addmul_1 (rp, up, un, vp[0]); + } + return rp[un]; +} + +void +mpn_mul_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n) +{ + mpn_mul (rp, ap, n, bp, n); +} + +void +mpn_sqr (mp_ptr rp, mp_srcptr ap, mp_size_t n) +{ + mpn_mul (rp, ap, n, ap, n); +} + +mp_limb_t +mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt) +{ + mp_limb_t high_limb, low_limb; + unsigned int tnc; + mp_limb_t retval; + + assert (n >= 1); + assert (cnt >= 1); + assert (cnt < GMP_LIMB_BITS); + + up += n; + rp += n; + + tnc = GMP_LIMB_BITS - cnt; + low_limb = *--up; + retval = low_limb >> tnc; + high_limb = (low_limb << cnt); + + while (--n != 0) + { + low_limb = *--up; + *--rp = high_limb | (low_limb >> tnc); + high_limb = (low_limb << cnt); + } + *--rp = high_limb; + + return retval; +} + +mp_limb_t +mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt) +{ + mp_limb_t high_limb, low_limb; + unsigned int tnc; + mp_limb_t retval; + + assert (n >= 1); + assert (cnt >= 1); + assert (cnt < GMP_LIMB_BITS); + + tnc = GMP_LIMB_BITS - cnt; + high_limb = *up++; + retval = (high_limb << tnc); + low_limb = high_limb >> cnt; + + while (--n != 0) + { + high_limb = *up++; + *rp++ = low_limb | (high_limb << tnc); + low_limb = high_limb >> cnt; + } + *rp = low_limb; + + return retval; +} + +static mp_bitcnt_t +mpn_common_scan (mp_limb_t limb, mp_size_t i, mp_srcptr up, mp_size_t un, + mp_limb_t ux) +{ + unsigned cnt; + + assert (ux == 0 || ux == GMP_LIMB_MAX); + assert (0 <= i && i <= un ); + + while (limb == 0) + { + i++; + if (i == un) + return (ux == 0 ? ~(mp_bitcnt_t) 0 : un * GMP_LIMB_BITS); + limb = ux ^ up[i]; + } + gmp_ctz (cnt, limb); + return (mp_bitcnt_t) i * GMP_LIMB_BITS + cnt; +} + +mp_bitcnt_t +mpn_scan1 (mp_srcptr ptr, mp_bitcnt_t bit) +{ + mp_size_t i; + i = bit / GMP_LIMB_BITS; + + return mpn_common_scan ( ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)), + i, ptr, i, 0); +} + +mp_bitcnt_t +mpn_scan0 (mp_srcptr ptr, mp_bitcnt_t bit) +{ + mp_size_t i; + i = bit / GMP_LIMB_BITS; + + return mpn_common_scan (~ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)), + i, ptr, i, GMP_LIMB_MAX); +} + +void +mpn_com (mp_ptr rp, mp_srcptr up, mp_size_t n) +{ + while (--n >= 0) + *rp++ = ~ *up++; +} + +mp_limb_t +mpn_neg (mp_ptr rp, mp_srcptr up, mp_size_t n) +{ + while (*up == 0) + { + *rp = 0; + if (!--n) + return 0; + ++up; ++rp; + } + *rp = - *up; + mpn_com (++rp, ++up, --n); + return 1; +} + + +/* MPN division interface. */ + +/* The 3/2 inverse is defined as + + m = floor( (B^3-1) / (B u1 + u0)) - B +*/ +mp_limb_t +mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0) +{ + mp_limb_t r, m; + + { + mp_limb_t p, ql; + unsigned ul, uh, qh; + + assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t)); + /* For notation, let b denote the half-limb base, so that B = b^2. + Split u1 = b uh + ul. */ + ul = u1 & GMP_LLIMB_MASK; + uh = u1 >> (GMP_LIMB_BITS / 2); + + /* Approximation of the high half of quotient. Differs from the 2/1 + inverse of the half limb uh, since we have already subtracted + u0. */ + qh = (u1 ^ GMP_LIMB_MAX) / uh; + + /* Adjust to get a half-limb 3/2 inverse, i.e., we want + + qh' = floor( (b^3 - 1) / u) - b = floor ((b^3 - b u - 1) / u + = floor( (b (~u) + b-1) / u), + + and the remainder + + r = b (~u) + b-1 - qh (b uh + ul) + = b (~u - qh uh) + b-1 - qh ul + + Subtraction of qh ul may underflow, which implies adjustments. + But by normalization, 2 u >= B > qh ul, so we need to adjust by + at most 2. + */ + + r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK; + + p = (mp_limb_t) qh * ul; + /* Adjustment steps taken from udiv_qrnnd_c */ + if (r < p) + { + qh--; + r += u1; + if (r >= u1) /* i.e. we didn't get carry when adding to r */ + if (r < p) + { + qh--; + r += u1; + } + } + r -= p; + + /* Low half of the quotient is + + ql = floor ( (b r + b-1) / u1). + + This is a 3/2 division (on half-limbs), for which qh is a + suitable inverse. */ + + p = (r >> (GMP_LIMB_BITS / 2)) * qh + r; + /* Unlike full-limb 3/2, we can add 1 without overflow. For this to + work, it is essential that ql is a full mp_limb_t. */ + ql = (p >> (GMP_LIMB_BITS / 2)) + 1; + + /* By the 3/2 trick, we don't need the high half limb. */ + r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1; + + if (r >= (GMP_LIMB_MAX & (p << (GMP_LIMB_BITS / 2)))) + { + ql--; + r += u1; + } + m = ((mp_limb_t) qh << (GMP_LIMB_BITS / 2)) + ql; + if (r >= u1) + { + m++; + r -= u1; + } + } + + /* Now m is the 2/1 inverse of u1. If u0 > 0, adjust it to become a + 3/2 inverse. */ + if (u0 > 0) + { + mp_limb_t th, tl; + r = ~r; + r += u0; + if (r < u0) + { + m--; + if (r >= u1) + { + m--; + r -= u1; + } + r -= u1; + } + gmp_umul_ppmm (th, tl, u0, m); + r += th; + if (r < th) + { + m--; + m -= ((r > u1) | ((r == u1) & (tl > u0))); + } + } + + return m; +} + +struct gmp_div_inverse +{ + /* Normalization shift count. */ + unsigned shift; + /* Normalized divisor (d0 unused for mpn_div_qr_1) */ + mp_limb_t d1, d0; + /* Inverse, for 2/1 or 3/2. */ + mp_limb_t di; +}; + +static void +mpn_div_qr_1_invert (struct gmp_div_inverse *inv, mp_limb_t d) +{ + unsigned shift; + + assert (d > 0); + gmp_clz (shift, d); + inv->shift = shift; + inv->d1 = d << shift; + inv->di = mpn_invert_limb (inv->d1); +} + +static void +mpn_div_qr_2_invert (struct gmp_div_inverse *inv, + mp_limb_t d1, mp_limb_t d0) +{ + unsigned shift; + + assert (d1 > 0); + gmp_clz (shift, d1); + inv->shift = shift; + if (shift > 0) + { + d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift)); + d0 <<= shift; + } + inv->d1 = d1; + inv->d0 = d0; + inv->di = mpn_invert_3by2 (d1, d0); +} + +static void +mpn_div_qr_invert (struct gmp_div_inverse *inv, + mp_srcptr dp, mp_size_t dn) +{ + assert (dn > 0); + + if (dn == 1) + mpn_div_qr_1_invert (inv, dp[0]); + else if (dn == 2) + mpn_div_qr_2_invert (inv, dp[1], dp[0]); + else + { + unsigned shift; + mp_limb_t d1, d0; + + d1 = dp[dn-1]; + d0 = dp[dn-2]; + assert (d1 > 0); + gmp_clz (shift, d1); + inv->shift = shift; + if (shift > 0) + { + d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift)); + d0 = (d0 << shift) | (dp[dn-3] >> (GMP_LIMB_BITS - shift)); + } + inv->d1 = d1; + inv->d0 = d0; + inv->di = mpn_invert_3by2 (d1, d0); + } +} + +/* Not matching current public gmp interface, rather corresponding to + the sbpi1_div_* functions. */ +static mp_limb_t +mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn, + const struct gmp_div_inverse *inv) +{ + mp_limb_t d, di; + mp_limb_t r; + mp_ptr tp = NULL; + mp_size_t tn = 0; + + if (inv->shift > 0) + { + /* Shift, reusing qp area if possible. In-place shift if qp == np. */ + tp = qp; + if (!tp) + { + tn = nn; + tp = gmp_alloc_limbs (tn); + } + r = mpn_lshift (tp, np, nn, inv->shift); + np = tp; + } + else + r = 0; + + d = inv->d1; + di = inv->di; + while (--nn >= 0) + { + mp_limb_t q; + + gmp_udiv_qrnnd_preinv (q, r, r, np[nn], d, di); + if (qp) + qp[nn] = q; + } + if (tn) + gmp_free_limbs (tp, tn); + + return r >> inv->shift; +} + +static void +mpn_div_qr_2_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn, + const struct gmp_div_inverse *inv) +{ + unsigned shift; + mp_size_t i; + mp_limb_t d1, d0, di, r1, r0; + + assert (nn >= 2); + shift = inv->shift; + d1 = inv->d1; + d0 = inv->d0; + di = inv->di; + + if (shift > 0) + r1 = mpn_lshift (np, np, nn, shift); + else + r1 = 0; + + r0 = np[nn - 1]; + + i = nn - 2; + do + { + mp_limb_t n0, q; + n0 = np[i]; + gmp_udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di); + + if (qp) + qp[i] = q; + } + while (--i >= 0); + + if (shift > 0) + { + assert ((r0 & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - shift))) == 0); + r0 = (r0 >> shift) | (r1 << (GMP_LIMB_BITS - shift)); + r1 >>= shift; + } + + np[1] = r1; + np[0] = r0; +} + +static void +mpn_div_qr_pi1 (mp_ptr qp, + mp_ptr np, mp_size_t nn, mp_limb_t n1, + mp_srcptr dp, mp_size_t dn, + mp_limb_t dinv) +{ + mp_size_t i; + + mp_limb_t d1, d0; + mp_limb_t cy, cy1; + mp_limb_t q; + + assert (dn > 2); + assert (nn >= dn); + + d1 = dp[dn - 1]; + d0 = dp[dn - 2]; + + assert ((d1 & GMP_LIMB_HIGHBIT) != 0); + /* Iteration variable is the index of the q limb. + * + * We divide + * by + */ + + i = nn - dn; + do + { + mp_limb_t n0 = np[dn-1+i]; + + if (n1 == d1 && n0 == d0) + { + q = GMP_LIMB_MAX; + mpn_submul_1 (np+i, dp, dn, q); + n1 = np[dn-1+i]; /* update n1, last loop's value will now be invalid */ + } + else + { + gmp_udiv_qr_3by2 (q, n1, n0, n1, n0, np[dn-2+i], d1, d0, dinv); + + cy = mpn_submul_1 (np + i, dp, dn-2, q); + + cy1 = n0 < cy; + n0 = n0 - cy; + cy = n1 < cy1; + n1 = n1 - cy1; + np[dn-2+i] = n0; + + if (cy != 0) + { + n1 += d1 + mpn_add_n (np + i, np + i, dp, dn - 1); + q--; + } + } + + if (qp) + qp[i] = q; + } + while (--i >= 0); + + np[dn - 1] = n1; +} + +static void +mpn_div_qr_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn, + mp_srcptr dp, mp_size_t dn, + const struct gmp_div_inverse *inv) +{ + assert (dn > 0); + assert (nn >= dn); + + if (dn == 1) + np[0] = mpn_div_qr_1_preinv (qp, np, nn, inv); + else if (dn == 2) + mpn_div_qr_2_preinv (qp, np, nn, inv); + else + { + mp_limb_t nh; + unsigned shift; + + assert (inv->d1 == dp[dn-1]); + assert (inv->d0 == dp[dn-2]); + assert ((inv->d1 & GMP_LIMB_HIGHBIT) != 0); + + shift = inv->shift; + if (shift > 0) + nh = mpn_lshift (np, np, nn, shift); + else + nh = 0; + + mpn_div_qr_pi1 (qp, np, nn, nh, dp, dn, inv->di); + + if (shift > 0) + gmp_assert_nocarry (mpn_rshift (np, np, dn, shift)); + } +} + +static void +mpn_div_qr (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn) +{ + struct gmp_div_inverse inv; + mp_ptr tp = NULL; + + assert (dn > 0); + assert (nn >= dn); + + mpn_div_qr_invert (&inv, dp, dn); + if (dn > 2 && inv.shift > 0) + { + tp = gmp_alloc_limbs (dn); + gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift)); + dp = tp; + } + mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv); + if (tp) + gmp_free_limbs (tp, dn); +} + + +/* MPN base conversion. */ +static unsigned +mpn_base_power_of_two_p (unsigned b) +{ + switch (b) + { + case 2: return 1; + case 4: return 2; + case 8: return 3; + case 16: return 4; + case 32: return 5; + case 64: return 6; + case 128: return 7; + case 256: return 8; + default: return 0; + } +} + +struct mpn_base_info +{ + /* bb is the largest power of the base which fits in one limb, and + exp is the corresponding exponent. */ + unsigned exp; + mp_limb_t bb; +}; + +static void +mpn_get_base_info (struct mpn_base_info *info, mp_limb_t b) +{ + mp_limb_t m; + mp_limb_t p; + unsigned exp; + + m = GMP_LIMB_MAX / b; + for (exp = 1, p = b; p <= m; exp++) + p *= b; + + info->exp = exp; + info->bb = p; +} + +static mp_bitcnt_t +mpn_limb_size_in_base_2 (mp_limb_t u) +{ + unsigned shift; + + assert (u > 0); + gmp_clz (shift, u); + return GMP_LIMB_BITS - shift; +} + +static size_t +mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un) +{ + unsigned char mask; + size_t sn, j; + mp_size_t i; + unsigned shift; + + sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]) + + bits - 1) / bits; + + mask = (1U << bits) - 1; + + for (i = 0, j = sn, shift = 0; j-- > 0;) + { + unsigned char digit = up[i] >> shift; + + shift += bits; + + if (shift >= GMP_LIMB_BITS && ++i < un) + { + shift -= GMP_LIMB_BITS; + digit |= up[i] << (bits - shift); + } + sp[j] = digit & mask; + } + return sn; +} + +/* We generate digits from the least significant end, and reverse at + the end. */ +static size_t +mpn_limb_get_str (unsigned char *sp, mp_limb_t w, + const struct gmp_div_inverse *binv) +{ + mp_size_t i; + for (i = 0; w > 0; i++) + { + mp_limb_t h, l, r; + + h = w >> (GMP_LIMB_BITS - binv->shift); + l = w << binv->shift; + + gmp_udiv_qrnnd_preinv (w, r, h, l, binv->d1, binv->di); + assert ((r & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - binv->shift))) == 0); + r >>= binv->shift; + + sp[i] = r; + } + return i; +} + +static size_t +mpn_get_str_other (unsigned char *sp, + int base, const struct mpn_base_info *info, + mp_ptr up, mp_size_t un) +{ + struct gmp_div_inverse binv; + size_t sn; + size_t i; + + mpn_div_qr_1_invert (&binv, base); + + sn = 0; + + if (un > 1) + { + struct gmp_div_inverse bbinv; + mpn_div_qr_1_invert (&bbinv, info->bb); + + do + { + mp_limb_t w; + size_t done; + w = mpn_div_qr_1_preinv (up, up, un, &bbinv); + un -= (up[un-1] == 0); + done = mpn_limb_get_str (sp + sn, w, &binv); + + for (sn += done; done < info->exp; done++) + sp[sn++] = 0; + } + while (un > 1); + } + sn += mpn_limb_get_str (sp + sn, up[0], &binv); + + /* Reverse order */ + for (i = 0; 2*i + 1 < sn; i++) + { + unsigned char t = sp[i]; + sp[i] = sp[sn - i - 1]; + sp[sn - i - 1] = t; + } + + return sn; +} + +size_t +mpn_get_str (unsigned char *sp, int base, mp_ptr up, mp_size_t un) +{ + unsigned bits; + + assert (un > 0); + assert (up[un-1] > 0); + + bits = mpn_base_power_of_two_p (base); + if (bits) + return mpn_get_str_bits (sp, bits, up, un); + else + { + struct mpn_base_info info; + + mpn_get_base_info (&info, base); + return mpn_get_str_other (sp, base, &info, up, un); + } +} + +static mp_size_t +mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn, + unsigned bits) +{ + mp_size_t rn; + mp_limb_t limb; + unsigned shift; + + for (limb = 0, rn = 0, shift = 0; sn-- > 0; ) + { + limb |= (mp_limb_t) sp[sn] << shift; + shift += bits; + if (shift >= GMP_LIMB_BITS) + { + shift -= GMP_LIMB_BITS; + rp[rn++] = limb; + /* Next line is correct also if shift == 0, + bits == 8, and mp_limb_t == unsigned char. */ + limb = (unsigned int) sp[sn] >> (bits - shift); + } + } + if (limb != 0) + rp[rn++] = limb; + else + rn = mpn_normalized_size (rp, rn); + return rn; +} + +/* Result is usually normalized, except for all-zero input, in which + case a single zero limb is written at *RP, and 1 is returned. */ +static mp_size_t +mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn, + mp_limb_t b, const struct mpn_base_info *info) +{ + mp_size_t rn; + mp_limb_t w; + unsigned k; + size_t j; + + assert (sn > 0); + + k = 1 + (sn - 1) % info->exp; + + j = 0; + w = sp[j++]; + while (--k != 0) + w = w * b + sp[j++]; + + rp[0] = w; + + for (rn = 1; j < sn;) + { + mp_limb_t cy; + + w = sp[j++]; + for (k = 1; k < info->exp; k++) + w = w * b + sp[j++]; + + cy = mpn_mul_1 (rp, rp, rn, info->bb); + cy += mpn_add_1 (rp, rp, rn, w); + if (cy > 0) + rp[rn++] = cy; + } + assert (j == sn); + + return rn; +} + +mp_size_t +mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base) +{ + unsigned bits; + + if (sn == 0) + return 0; + + bits = mpn_base_power_of_two_p (base); + if (bits) + return mpn_set_str_bits (rp, sp, sn, bits); + else + { + struct mpn_base_info info; + + mpn_get_base_info (&info, base); + return mpn_set_str_other (rp, sp, sn, base, &info); + } +} + + +/* MPZ interface */ +void +mpz_init (mpz_t r) +{ + static const mp_limb_t dummy_limb = GMP_LIMB_MAX & 0xc1a0; + + r->_mp_alloc = 0; + r->_mp_size = 0; + r->_mp_d = (mp_ptr) &dummy_limb; +} + +/* The utility of this function is a bit limited, since many functions + assigns the result variable using mpz_swap. */ +void +mpz_init2 (mpz_t r, mp_bitcnt_t bits) +{ + mp_size_t rn; + + bits -= (bits != 0); /* Round down, except if 0 */ + rn = 1 + bits / GMP_LIMB_BITS; + + r->_mp_alloc = rn; + r->_mp_size = 0; + r->_mp_d = gmp_alloc_limbs (rn); +} + +void +mpz_clear (mpz_t r) +{ + if (r->_mp_alloc) + gmp_free_limbs (r->_mp_d, r->_mp_alloc); +} + +static mp_ptr +mpz_realloc (mpz_t r, mp_size_t size) +{ + size = GMP_MAX (size, 1); + + if (r->_mp_alloc) + r->_mp_d = gmp_realloc_limbs (r->_mp_d, r->_mp_alloc, size); + else + r->_mp_d = gmp_alloc_limbs (size); + r->_mp_alloc = size; + + if (GMP_ABS (r->_mp_size) > size) + r->_mp_size = 0; + + return r->_mp_d; +} + +/* Realloc for an mpz_t WHAT if it has less than NEEDED limbs. */ +#define MPZ_REALLOC(z,n) ((n) > (z)->_mp_alloc \ + ? mpz_realloc(z,n) \ + : (z)->_mp_d) + +/* MPZ assignment and basic conversions. */ +void +mpz_set_si (mpz_t r, signed long int x) +{ + if (x >= 0) + mpz_set_ui (r, x); + else /* (x < 0) */ + if (GMP_LIMB_BITS < GMP_ULONG_BITS) + { + mpz_set_ui (r, GMP_NEG_CAST (unsigned long int, x)); + mpz_neg (r, r); + } + else + { + r->_mp_size = -1; + MPZ_REALLOC (r, 1)[0] = GMP_NEG_CAST (unsigned long int, x); + } +} + +void +mpz_set_ui (mpz_t r, unsigned long int x) +{ + if (x > 0) + { + r->_mp_size = 1; + MPZ_REALLOC (r, 1)[0] = x; + if (GMP_LIMB_BITS < GMP_ULONG_BITS) + { + int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS; + while (x >>= LOCAL_GMP_LIMB_BITS) + { + ++ r->_mp_size; + MPZ_REALLOC (r, r->_mp_size)[r->_mp_size - 1] = x; + } + } + } + else + r->_mp_size = 0; +} + +void +mpz_set (mpz_t r, const mpz_t x) +{ + /* Allow the NOP r == x */ + if (r != x) + { + mp_size_t n; + mp_ptr rp; + + n = GMP_ABS (x->_mp_size); + rp = MPZ_REALLOC (r, n); + + mpn_copyi (rp, x->_mp_d, n); + r->_mp_size = x->_mp_size; + } +} + +void +mpz_init_set_si (mpz_t r, signed long int x) +{ + mpz_init (r); + mpz_set_si (r, x); +} + +void +mpz_init_set_ui (mpz_t r, unsigned long int x) +{ + mpz_init (r); + mpz_set_ui (r, x); +} + +void +mpz_init_set (mpz_t r, const mpz_t x) +{ + mpz_init (r); + mpz_set (r, x); +} + +int +mpz_fits_slong_p (const mpz_t u) +{ + return mpz_cmp_si (u, LONG_MAX) <= 0 && mpz_cmp_si (u, LONG_MIN) >= 0; +} + +static int +mpn_absfits_ulong_p (mp_srcptr up, mp_size_t un) +{ + int ulongsize = GMP_ULONG_BITS / GMP_LIMB_BITS; + mp_limb_t ulongrem = 0; + + if (GMP_ULONG_BITS % GMP_LIMB_BITS != 0) + ulongrem = (mp_limb_t) (ULONG_MAX >> GMP_LIMB_BITS * ulongsize) + 1; + + return un <= ulongsize || (up[ulongsize] < ulongrem && un == ulongsize + 1); +} + +int +mpz_fits_ulong_p (const mpz_t u) +{ + mp_size_t us = u->_mp_size; + + return us >= 0 && mpn_absfits_ulong_p (u->_mp_d, us); +} + +int +mpz_fits_sint_p (const mpz_t u) +{ + return mpz_cmp_si (u, INT_MAX) <= 0 && mpz_cmp_si (u, INT_MIN) >= 0; +} + +int +mpz_fits_uint_p (const mpz_t u) +{ + return u->_mp_size >= 0 && mpz_cmpabs_ui (u, UINT_MAX) <= 0; +} + +int +mpz_fits_sshort_p (const mpz_t u) +{ + return mpz_cmp_si (u, SHRT_MAX) <= 0 && mpz_cmp_si (u, SHRT_MIN) >= 0; +} + +int +mpz_fits_ushort_p (const mpz_t u) +{ + return u->_mp_size >= 0 && mpz_cmpabs_ui (u, USHRT_MAX) <= 0; +} + +long int +mpz_get_si (const mpz_t u) +{ + unsigned long r = mpz_get_ui (u); + unsigned long c = -LONG_MAX - LONG_MIN; + + if (u->_mp_size < 0) + /* This expression is necessary to properly handle -LONG_MIN */ + return -(long) c - (long) ((r - c) & LONG_MAX); + else + return (long) (r & LONG_MAX); +} + +unsigned long int +mpz_get_ui (const mpz_t u) +{ + if (GMP_LIMB_BITS < GMP_ULONG_BITS) + { + int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS; + unsigned long r = 0; + mp_size_t n = GMP_ABS (u->_mp_size); + n = GMP_MIN (n, 1 + (mp_size_t) (GMP_ULONG_BITS - 1) / GMP_LIMB_BITS); + while (--n >= 0) + r = (r << LOCAL_GMP_LIMB_BITS) + u->_mp_d[n]; + return r; + } + + return u->_mp_size == 0 ? 0 : u->_mp_d[0]; +} + +size_t +mpz_size (const mpz_t u) +{ + return GMP_ABS (u->_mp_size); +} + +mp_limb_t +mpz_getlimbn (const mpz_t u, mp_size_t n) +{ + if (n >= 0 && n < GMP_ABS (u->_mp_size)) + return u->_mp_d[n]; + else + return 0; +} + +void +mpz_realloc2 (mpz_t x, mp_bitcnt_t n) +{ + mpz_realloc (x, 1 + (n - (n != 0)) / GMP_LIMB_BITS); +} + +mp_srcptr +mpz_limbs_read (mpz_srcptr x) +{ + return x->_mp_d; +} + +mp_ptr +mpz_limbs_modify (mpz_t x, mp_size_t n) +{ + assert (n > 0); + return MPZ_REALLOC (x, n); +} + +mp_ptr +mpz_limbs_write (mpz_t x, mp_size_t n) +{ + return mpz_limbs_modify (x, n); +} + +void +mpz_limbs_finish (mpz_t x, mp_size_t xs) +{ + mp_size_t xn; + xn = mpn_normalized_size (x->_mp_d, GMP_ABS (xs)); + x->_mp_size = xs < 0 ? -xn : xn; +} + +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; +} + +mpz_srcptr +mpz_roinit_n (mpz_t x, mp_srcptr xp, mp_size_t xs) +{ + mpz_roinit_normal_n (x, xp, xs); + mpz_limbs_finish (x, xs); + return x; +} + + +/* Conversions and comparison to double. */ +void +mpz_set_d (mpz_t r, double x) +{ + int sign; + mp_ptr rp; + mp_size_t rn, i; + double B; + double Bi; + mp_limb_t f; + + /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is + zero or infinity. */ + if (x != x || x == x * 0.5) + { + r->_mp_size = 0; + return; + } + + sign = x < 0.0 ; + if (sign) + x = - x; + + if (x < 1.0) + { + r->_mp_size = 0; + return; + } + B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1); + Bi = 1.0 / B; + for (rn = 1; x >= B; rn++) + x *= Bi; + + rp = MPZ_REALLOC (r, rn); + + f = (mp_limb_t) x; + x -= f; + assert (x < 1.0); + i = rn-1; + rp[i] = f; + while (--i >= 0) + { + x = B * x; + f = (mp_limb_t) x; + x -= f; + assert (x < 1.0); + rp[i] = f; + } + + r->_mp_size = sign ? - rn : rn; +} + +void +mpz_init_set_d (mpz_t r, double x) +{ + mpz_init (r); + mpz_set_d (r, x); +} + +double +mpz_get_d (const mpz_t u) +{ + int m; + mp_limb_t l; + mp_size_t un; + double x; + double B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1); + + un = GMP_ABS (u->_mp_size); + + if (un == 0) + return 0.0; + + l = u->_mp_d[--un]; + gmp_clz (m, l); + m = m + GMP_DBL_MANT_BITS - GMP_LIMB_BITS; + if (m < 0) + l &= GMP_LIMB_MAX << -m; + + for (x = l; --un >= 0;) + { + x = B*x; + if (m > 0) { + l = u->_mp_d[un]; + m -= GMP_LIMB_BITS; + if (m < 0) + l &= GMP_LIMB_MAX << -m; + x += l; + } + } + + if (u->_mp_size < 0) + x = -x; + + return x; +} + +int +mpz_cmpabs_d (const mpz_t x, double d) +{ + mp_size_t xn; + double B, Bi; + mp_size_t i; + + xn = x->_mp_size; + d = GMP_ABS (d); + + if (xn != 0) + { + xn = GMP_ABS (xn); + + B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1); + Bi = 1.0 / B; + + /* Scale d so it can be compared with the top limb. */ + for (i = 1; i < xn; i++) + d *= Bi; + + if (d >= B) + return -1; + + /* Compare floor(d) to top limb, subtract and cancel when equal. */ + for (i = xn; i-- > 0;) + { + mp_limb_t f, xl; + + f = (mp_limb_t) d; + xl = x->_mp_d[i]; + if (xl > f) + return 1; + else if (xl < f) + return -1; + d = B * (d - f); + } + } + return - (d > 0.0); +} + +int +mpz_cmp_d (const mpz_t x, double d) +{ + if (x->_mp_size < 0) + { + if (d >= 0.0) + return -1; + else + return -mpz_cmpabs_d (x, d); + } + else + { + if (d < 0.0) + return 1; + else + return mpz_cmpabs_d (x, d); + } +} + + +/* MPZ comparisons and the like. */ +int +mpz_sgn (const mpz_t u) +{ + return GMP_CMP (u->_mp_size, 0); +} + +int +mpz_cmp_si (const mpz_t u, long v) +{ + mp_size_t usize = u->_mp_size; + + if (v >= 0) + return mpz_cmp_ui (u, v); + else if (usize >= 0) + return 1; + else + return - mpz_cmpabs_ui (u, GMP_NEG_CAST (unsigned long int, v)); +} + +int +mpz_cmp_ui (const mpz_t u, unsigned long v) +{ + mp_size_t usize = u->_mp_size; + + if (usize < 0) + return -1; + else + return mpz_cmpabs_ui (u, v); +} + +int +mpz_cmp (const mpz_t a, const mpz_t b) +{ + mp_size_t asize = a->_mp_size; + mp_size_t bsize = b->_mp_size; + + if (asize != bsize) + return (asize < bsize) ? -1 : 1; + else if (asize >= 0) + return mpn_cmp (a->_mp_d, b->_mp_d, asize); + else + return mpn_cmp (b->_mp_d, a->_mp_d, -asize); +} + +int +mpz_cmpabs_ui (const mpz_t u, unsigned long v) +{ + mp_size_t un = GMP_ABS (u->_mp_size); + + if (! mpn_absfits_ulong_p (u->_mp_d, un)) + return 1; + else + { + unsigned long uu = mpz_get_ui (u); + return GMP_CMP(uu, v); + } +} + +int +mpz_cmpabs (const mpz_t u, const mpz_t v) +{ + return mpn_cmp4 (u->_mp_d, GMP_ABS (u->_mp_size), + v->_mp_d, GMP_ABS (v->_mp_size)); +} + +void +mpz_abs (mpz_t r, const mpz_t u) +{ + mpz_set (r, u); + r->_mp_size = GMP_ABS (r->_mp_size); +} + +void +mpz_neg (mpz_t r, const mpz_t u) +{ + mpz_set (r, u); + r->_mp_size = -r->_mp_size; +} + +void +mpz_swap (mpz_t u, mpz_t v) +{ + MP_SIZE_T_SWAP (u->_mp_alloc, v->_mp_alloc); + MPN_PTR_SWAP (u->_mp_d, u->_mp_size, v->_mp_d, v->_mp_size); +} + + +/* MPZ addition and subtraction */ + + +void +mpz_add_ui (mpz_t r, const mpz_t a, unsigned long b) +{ + mpz_t bb; + mpz_init_set_ui (bb, b); + mpz_add (r, a, bb); + mpz_clear (bb); +} + +void +mpz_sub_ui (mpz_t r, const mpz_t a, unsigned long b) +{ + mpz_ui_sub (r, b, a); + mpz_neg (r, r); +} + +void +mpz_ui_sub (mpz_t r, unsigned long a, const mpz_t b) +{ + mpz_neg (r, b); + mpz_add_ui (r, r, a); +} + +static mp_size_t +mpz_abs_add (mpz_t r, const mpz_t a, const mpz_t b) +{ + mp_size_t an = GMP_ABS (a->_mp_size); + mp_size_t bn = GMP_ABS (b->_mp_size); + mp_ptr rp; + mp_limb_t cy; + + if (an < bn) + { + MPZ_SRCPTR_SWAP (a, b); + MP_SIZE_T_SWAP (an, bn); + } + + rp = MPZ_REALLOC (r, an + 1); + cy = mpn_add (rp, a->_mp_d, an, b->_mp_d, bn); + + rp[an] = cy; + + return an + cy; +} + +static mp_size_t +mpz_abs_sub (mpz_t r, const mpz_t a, const mpz_t b) +{ + mp_size_t an = GMP_ABS (a->_mp_size); + mp_size_t bn = GMP_ABS (b->_mp_size); + int cmp; + mp_ptr rp; + + cmp = mpn_cmp4 (a->_mp_d, an, b->_mp_d, bn); + if (cmp > 0) + { + rp = MPZ_REALLOC (r, an); + gmp_assert_nocarry (mpn_sub (rp, a->_mp_d, an, b->_mp_d, bn)); + return mpn_normalized_size (rp, an); + } + else if (cmp < 0) + { + rp = MPZ_REALLOC (r, bn); + gmp_assert_nocarry (mpn_sub (rp, b->_mp_d, bn, a->_mp_d, an)); + return -mpn_normalized_size (rp, bn); + } + else + return 0; +} + +void +mpz_add (mpz_t r, const mpz_t a, const mpz_t b) +{ + mp_size_t rn; + + if ( (a->_mp_size ^ b->_mp_size) >= 0) + rn = mpz_abs_add (r, a, b); + else + rn = mpz_abs_sub (r, a, b); + + r->_mp_size = a->_mp_size >= 0 ? rn : - rn; +} + +void +mpz_sub (mpz_t r, const mpz_t a, const mpz_t b) +{ + mp_size_t rn; + + if ( (a->_mp_size ^ b->_mp_size) >= 0) + rn = mpz_abs_sub (r, a, b); + else + rn = mpz_abs_add (r, a, b); + + r->_mp_size = a->_mp_size >= 0 ? rn : - rn; +} + + +/* MPZ multiplication */ +void +mpz_mul_si (mpz_t r, const mpz_t u, long int v) +{ + if (v < 0) + { + mpz_mul_ui (r, u, GMP_NEG_CAST (unsigned long int, v)); + mpz_neg (r, r); + } + else + mpz_mul_ui (r, u, v); +} + +void +mpz_mul_ui (mpz_t r, const mpz_t u, unsigned long int v) +{ + mpz_t vv; + mpz_init_set_ui (vv, v); + mpz_mul (r, u, vv); + mpz_clear (vv); + return; +} + +void +mpz_mul (mpz_t r, const mpz_t u, const mpz_t v) +{ + int sign; + mp_size_t un, vn, rn; + mpz_t t; + mp_ptr tp; + + un = u->_mp_size; + vn = v->_mp_size; + + if (un == 0 || vn == 0) + { + r->_mp_size = 0; + return; + } + + sign = (un ^ vn) < 0; + + un = GMP_ABS (un); + vn = GMP_ABS (vn); + + mpz_init2 (t, (un + vn) * GMP_LIMB_BITS); + + tp = t->_mp_d; + if (un >= vn) + mpn_mul (tp, u->_mp_d, un, v->_mp_d, vn); + else + mpn_mul (tp, v->_mp_d, vn, u->_mp_d, un); + + rn = un + vn; + rn -= tp[rn-1] == 0; + + t->_mp_size = sign ? - rn : rn; + mpz_swap (r, t); + mpz_clear (t); +} + +void +mpz_mul_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bits) +{ + mp_size_t un, rn; + mp_size_t limbs; + unsigned shift; + mp_ptr rp; + + un = GMP_ABS (u->_mp_size); + if (un == 0) + { + r->_mp_size = 0; + return; + } + + limbs = bits / GMP_LIMB_BITS; + shift = bits % GMP_LIMB_BITS; + + rn = un + limbs + (shift > 0); + rp = MPZ_REALLOC (r, rn); + if (shift > 0) + { + mp_limb_t cy = mpn_lshift (rp + limbs, u->_mp_d, un, shift); + rp[rn-1] = cy; + rn -= (cy == 0); + } + else + mpn_copyd (rp + limbs, u->_mp_d, un); + + mpn_zero (rp, limbs); + + r->_mp_size = (u->_mp_size < 0) ? - rn : rn; +} + +void +mpz_addmul_ui (mpz_t r, const mpz_t u, unsigned long int v) +{ + mpz_t t; + mpz_init_set_ui (t, v); + mpz_mul (t, u, t); + mpz_add (r, r, t); + mpz_clear (t); +} + +void +mpz_submul_ui (mpz_t r, const mpz_t u, unsigned long int v) +{ + mpz_t t; + mpz_init_set_ui (t, v); + mpz_mul (t, u, t); + mpz_sub (r, r, t); + mpz_clear (t); +} + +void +mpz_addmul (mpz_t r, const mpz_t u, const mpz_t v) +{ + mpz_t t; + mpz_init (t); + mpz_mul (t, u, v); + mpz_add (r, r, t); + mpz_clear (t); +} + +void +mpz_submul (mpz_t r, const mpz_t u, const mpz_t v) +{ + mpz_t t; + mpz_init (t); + mpz_mul (t, u, v); + mpz_sub (r, r, t); + mpz_clear (t); +} + + +/* MPZ division */ +enum mpz_div_round_mode { GMP_DIV_FLOOR, GMP_DIV_CEIL, GMP_DIV_TRUNC }; + +/* Allows q or r to be zero. Returns 1 iff remainder is non-zero. */ +static int +mpz_div_qr (mpz_t q, mpz_t r, + const mpz_t n, const mpz_t d, enum mpz_div_round_mode mode) +{ + mp_size_t ns, ds, nn, dn, qs; + ns = n->_mp_size; + ds = d->_mp_size; + + if (ds == 0) + gmp_die("mpz_div_qr: Divide by zero."); + + if (ns == 0) + { + if (q) + q->_mp_size = 0; + if (r) + r->_mp_size = 0; + return 0; + } + + nn = GMP_ABS (ns); + dn = GMP_ABS (ds); + + qs = ds ^ ns; + + if (nn < dn) + { + if (mode == GMP_DIV_CEIL && qs >= 0) + { + /* q = 1, r = n - d */ + if (r) + mpz_sub (r, n, d); + if (q) + mpz_set_ui (q, 1); + } + else if (mode == GMP_DIV_FLOOR && qs < 0) + { + /* q = -1, r = n + d */ + if (r) + mpz_add (r, n, d); + if (q) + mpz_set_si (q, -1); + } + else + { + /* q = 0, r = d */ + if (r) + mpz_set (r, n); + if (q) + q->_mp_size = 0; + } + return 1; + } + else + { + mp_ptr np, qp; + mp_size_t qn, rn; + mpz_t tq, tr; + + mpz_init_set (tr, n); + np = tr->_mp_d; + + qn = nn - dn + 1; + + if (q) + { + mpz_init2 (tq, qn * GMP_LIMB_BITS); + qp = tq->_mp_d; + } + else + qp = NULL; + + mpn_div_qr (qp, np, nn, d->_mp_d, dn); + + if (qp) + { + qn -= (qp[qn-1] == 0); + + tq->_mp_size = qs < 0 ? -qn : qn; + } + rn = mpn_normalized_size (np, dn); + tr->_mp_size = ns < 0 ? - rn : rn; + + if (mode == GMP_DIV_FLOOR && qs < 0 && rn != 0) + { + if (q) + mpz_sub_ui (tq, tq, 1); + if (r) + mpz_add (tr, tr, d); + } + else if (mode == GMP_DIV_CEIL && qs >= 0 && rn != 0) + { + if (q) + mpz_add_ui (tq, tq, 1); + if (r) + mpz_sub (tr, tr, d); + } + + if (q) + { + mpz_swap (tq, q); + mpz_clear (tq); + } + if (r) + mpz_swap (tr, r); + + mpz_clear (tr); + + return rn != 0; + } +} + +void +mpz_cdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, r, n, d, GMP_DIV_CEIL); +} + +void +mpz_fdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, r, n, d, GMP_DIV_FLOOR); +} + +void +mpz_tdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, r, n, d, GMP_DIV_TRUNC); +} + +void +mpz_cdiv_q (mpz_t q, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, NULL, n, d, GMP_DIV_CEIL); +} + +void +mpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, NULL, n, d, GMP_DIV_FLOOR); +} + +void +mpz_tdiv_q (mpz_t q, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC); +} + +void +mpz_cdiv_r (mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (NULL, r, n, d, GMP_DIV_CEIL); +} + +void +mpz_fdiv_r (mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (NULL, r, n, d, GMP_DIV_FLOOR); +} + +void +mpz_tdiv_r (mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (NULL, r, n, d, GMP_DIV_TRUNC); +} + +void +mpz_mod (mpz_t r, const mpz_t n, const mpz_t d) +{ + mpz_div_qr (NULL, r, n, d, d->_mp_size >= 0 ? GMP_DIV_FLOOR : GMP_DIV_CEIL); +} + +static void +mpz_div_q_2exp (mpz_t q, const mpz_t u, mp_bitcnt_t bit_index, + enum mpz_div_round_mode mode) +{ + mp_size_t un, qn; + mp_size_t limb_cnt; + mp_ptr qp; + int adjust; + + un = u->_mp_size; + if (un == 0) + { + q->_mp_size = 0; + return; + } + limb_cnt = bit_index / GMP_LIMB_BITS; + qn = GMP_ABS (un) - limb_cnt; + bit_index %= GMP_LIMB_BITS; + + if (mode == ((un > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* un != 0 here. */ + /* Note: Below, the final indexing at limb_cnt is valid because at + that point we have qn > 0. */ + adjust = (qn <= 0 + || !mpn_zero_p (u->_mp_d, limb_cnt) + || (u->_mp_d[limb_cnt] + & (((mp_limb_t) 1 << bit_index) - 1))); + else + adjust = 0; + + if (qn <= 0) + qn = 0; + else + { + qp = MPZ_REALLOC (q, qn); + + if (bit_index != 0) + { + mpn_rshift (qp, u->_mp_d + limb_cnt, qn, bit_index); + qn -= qp[qn - 1] == 0; + } + else + { + mpn_copyi (qp, u->_mp_d + limb_cnt, qn); + } + } + + q->_mp_size = qn; + + if (adjust) + mpz_add_ui (q, q, 1); + if (un < 0) + mpz_neg (q, q); +} + +static void +mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index, + enum mpz_div_round_mode mode) +{ + mp_size_t us, un, rn; + mp_ptr rp; + mp_limb_t mask; + + us = u->_mp_size; + if (us == 0 || bit_index == 0) + { + r->_mp_size = 0; + return; + } + rn = (bit_index + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS; + assert (rn > 0); + + rp = MPZ_REALLOC (r, rn); + un = GMP_ABS (us); + + mask = GMP_LIMB_MAX >> (rn * GMP_LIMB_BITS - bit_index); + + if (rn > un) + { + /* Quotient (with truncation) is zero, and remainder is + non-zero */ + if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */ + { + /* Have to negate and sign extend. */ + mp_size_t i; + + gmp_assert_nocarry (! mpn_neg (rp, u->_mp_d, un)); + for (i = un; i < rn - 1; i++) + rp[i] = GMP_LIMB_MAX; + + rp[rn-1] = mask; + us = -us; + } + else + { + /* Just copy */ + if (r != u) + mpn_copyi (rp, u->_mp_d, un); + + rn = un; + } + } + else + { + if (r != u) + mpn_copyi (rp, u->_mp_d, rn - 1); + + rp[rn-1] = u->_mp_d[rn-1] & mask; + + if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */ + { + /* If r != 0, compute 2^{bit_count} - r. */ + mpn_neg (rp, rp, rn); + + rp[rn-1] &= mask; + + /* us is not used for anything else, so we can modify it + here to indicate flipped sign. */ + us = -us; + } + } + rn = mpn_normalized_size (rp, rn); + r->_mp_size = us < 0 ? -rn : rn; +} + +void +mpz_cdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_q_2exp (r, u, cnt, GMP_DIV_CEIL); +} + +void +mpz_fdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_q_2exp (r, u, cnt, GMP_DIV_FLOOR); +} + +void +mpz_tdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_q_2exp (r, u, cnt, GMP_DIV_TRUNC); +} + +void +mpz_cdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_r_2exp (r, u, cnt, GMP_DIV_CEIL); +} + +void +mpz_fdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_r_2exp (r, u, cnt, GMP_DIV_FLOOR); +} + +void +mpz_tdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt) +{ + mpz_div_r_2exp (r, u, cnt, GMP_DIV_TRUNC); +} + +void +mpz_divexact (mpz_t q, const mpz_t n, const mpz_t d) +{ + gmp_assert_nocarry (mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC)); +} + +int +mpz_divisible_p (const mpz_t n, const mpz_t d) +{ + return mpz_div_qr (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0; +} + +int +mpz_congruent_p (const mpz_t a, const mpz_t b, const mpz_t m) +{ + mpz_t t; + int res; + + /* a == b (mod 0) iff a == b */ + if (mpz_sgn (m) == 0) + return (mpz_cmp (a, b) == 0); + + mpz_init (t); + mpz_sub (t, a, b); + res = mpz_divisible_p (t, m); + mpz_clear (t); + + return res; +} + +static unsigned long +mpz_div_qr_ui (mpz_t q, mpz_t r, + const mpz_t n, unsigned long d, enum mpz_div_round_mode mode) +{ + unsigned long ret; + mpz_t rr, dd; + + mpz_init (rr); + mpz_init_set_ui (dd, d); + mpz_div_qr (q, rr, n, dd, mode); + mpz_clear (dd); + ret = mpz_get_ui (rr); + + if (r) + mpz_swap (r, rr); + mpz_clear (rr); + + return ret; +} + +unsigned long +mpz_cdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, r, n, d, GMP_DIV_CEIL); +} + +unsigned long +mpz_fdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, r, n, d, GMP_DIV_FLOOR); +} + +unsigned long +mpz_tdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, r, n, d, GMP_DIV_TRUNC); +} + +unsigned long +mpz_cdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_CEIL); +} + +unsigned long +mpz_fdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_FLOOR); +} + +unsigned long +mpz_tdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC); +} + +unsigned long +mpz_cdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_CEIL); +} +unsigned long +mpz_fdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR); +} +unsigned long +mpz_tdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_TRUNC); +} + +unsigned long +mpz_cdiv_ui (const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_CEIL); +} + +unsigned long +mpz_fdiv_ui (const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_FLOOR); +} + +unsigned long +mpz_tdiv_ui (const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC); +} + +unsigned long +mpz_mod_ui (mpz_t r, const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR); +} + +void +mpz_divexact_ui (mpz_t q, const mpz_t n, unsigned long d) +{ + gmp_assert_nocarry (mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC)); +} + +int +mpz_divisible_ui_p (const mpz_t n, unsigned long d) +{ + return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0; +} + + +/* GCD */ +static mp_limb_t +mpn_gcd_11 (mp_limb_t u, mp_limb_t v) +{ + unsigned shift; + + assert ( (u | v) > 0); + + if (u == 0) + return v; + else if (v == 0) + return u; + + gmp_ctz (shift, u | v); + + u >>= shift; + v >>= shift; + + if ( (u & 1) == 0) + MP_LIMB_T_SWAP (u, v); + + while ( (v & 1) == 0) + v >>= 1; + + while (u != v) + { + if (u > v) + { + u -= v; + do + u >>= 1; + while ( (u & 1) == 0); + } + else + { + v -= u; + do + v >>= 1; + while ( (v & 1) == 0); + } + } + return u << shift; +} + +unsigned long +mpz_gcd_ui (mpz_t g, const mpz_t u, unsigned long v) +{ + mpz_t t; + mpz_init_set_ui(t, v); + mpz_gcd (t, u, t); + if (v > 0) + v = mpz_get_ui (t); + + if (g) + mpz_swap (t, g); + + mpz_clear (t); + + return v; +} + +static mp_bitcnt_t +mpz_make_odd (mpz_t r) +{ + mp_bitcnt_t shift; + + assert (r->_mp_size > 0); + /* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */ + shift = mpn_scan1 (r->_mp_d, 0); + mpz_tdiv_q_2exp (r, r, shift); + + return shift; +} + +void +mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v) +{ + mpz_t tu, tv; + mp_bitcnt_t uz, vz, gz; + + if (u->_mp_size == 0) + { + mpz_abs (g, v); + return; + } + if (v->_mp_size == 0) + { + mpz_abs (g, u); + return; + } + + mpz_init (tu); + mpz_init (tv); + + mpz_abs (tu, u); + uz = mpz_make_odd (tu); + mpz_abs (tv, v); + vz = mpz_make_odd (tv); + gz = GMP_MIN (uz, vz); + + if (tu->_mp_size < tv->_mp_size) + mpz_swap (tu, tv); + + mpz_tdiv_r (tu, tu, tv); + if (tu->_mp_size == 0) + { + mpz_swap (g, tv); + } + else + for (;;) + { + int c; + + mpz_make_odd (tu); + c = mpz_cmp (tu, tv); + if (c == 0) + { + mpz_swap (g, tu); + break; + } + if (c < 0) + mpz_swap (tu, tv); + + if (tv->_mp_size == 1) + { + mp_limb_t *gp; + + mpz_tdiv_r (tu, tu, tv); + gp = MPZ_REALLOC (g, 1); /* gp = mpz_limbs_modify (g, 1); */ + *gp = mpn_gcd_11 (tu->_mp_d[0], tv->_mp_d[0]); + + g->_mp_size = *gp != 0; /* mpz_limbs_finish (g, 1); */ + break; + } + mpz_sub (tu, tu, tv); + } + mpz_clear (tu); + mpz_clear (tv); + mpz_mul_2exp (g, g, gz); +} + +void +mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v) +{ + mpz_t tu, tv, s0, s1, t0, t1; + mp_bitcnt_t uz, vz, gz; + mp_bitcnt_t power; + + if (u->_mp_size == 0) + { + /* g = 0 u + sgn(v) v */ + signed long sign = mpz_sgn (v); + mpz_abs (g, v); + if (s) + s->_mp_size = 0; + if (t) + mpz_set_si (t, sign); + return; + } + + if (v->_mp_size == 0) + { + /* g = sgn(u) u + 0 v */ + signed long sign = mpz_sgn (u); + mpz_abs (g, u); + if (s) + mpz_set_si (s, sign); + if (t) + t->_mp_size = 0; + return; + } + + mpz_init (tu); + mpz_init (tv); + mpz_init (s0); + mpz_init (s1); + mpz_init (t0); + mpz_init (t1); + + mpz_abs (tu, u); + uz = mpz_make_odd (tu); + mpz_abs (tv, v); + vz = mpz_make_odd (tv); + gz = GMP_MIN (uz, vz); + + uz -= gz; + vz -= gz; + + /* Cofactors corresponding to odd gcd. gz handled later. */ + if (tu->_mp_size < tv->_mp_size) + { + mpz_swap (tu, tv); + MPZ_SRCPTR_SWAP (u, v); + MPZ_PTR_SWAP (s, t); + MP_BITCNT_T_SWAP (uz, vz); + } + + /* Maintain + * + * u = t0 tu + t1 tv + * v = s0 tu + s1 tv + * + * where u and v denote the inputs with common factors of two + * eliminated, and det (s0, t0; s1, t1) = 2^p. Then + * + * 2^p tu = s1 u - t1 v + * 2^p tv = -s0 u + t0 v + */ + + /* After initial division, tu = q tv + tu', we have + * + * u = 2^uz (tu' + q tv) + * v = 2^vz tv + * + * or + * + * t0 = 2^uz, t1 = 2^uz q + * s0 = 0, s1 = 2^vz + */ + + mpz_tdiv_qr (t1, tu, tu, tv); + mpz_mul_2exp (t1, t1, uz); + + mpz_setbit (s1, vz); + power = uz + vz; + + if (tu->_mp_size > 0) + { + mp_bitcnt_t shift; + shift = mpz_make_odd (tu); + mpz_setbit (t0, uz + shift); + power += shift; + + for (;;) + { + int c; + c = mpz_cmp (tu, tv); + if (c == 0) + break; + + if (c < 0) + { + /* tv = tv' + tu + * + * u = t0 tu + t1 (tv' + tu) = (t0 + t1) tu + t1 tv' + * v = s0 tu + s1 (tv' + tu) = (s0 + s1) tu + s1 tv' */ + + mpz_sub (tv, tv, tu); + mpz_add (t0, t0, t1); + mpz_add (s0, s0, s1); + + shift = mpz_make_odd (tv); + mpz_mul_2exp (t1, t1, shift); + mpz_mul_2exp (s1, s1, shift); + } + else + { + mpz_sub (tu, tu, tv); + mpz_add (t1, t0, t1); + mpz_add (s1, s0, s1); + + shift = mpz_make_odd (tu); + mpz_mul_2exp (t0, t0, shift); + mpz_mul_2exp (s0, s0, shift); + } + power += shift; + } + } + else + mpz_setbit (t0, uz); + + /* Now tv = odd part of gcd, and -s0 and t0 are corresponding + cofactors. */ + + mpz_mul_2exp (tv, tv, gz); + mpz_neg (s0, s0); + + /* 2^p g = s0 u + t0 v. Eliminate one factor of two at a time. To + adjust cofactors, we need u / g and v / g */ + + mpz_divexact (s1, v, tv); + mpz_abs (s1, s1); + mpz_divexact (t1, u, tv); + mpz_abs (t1, t1); + + while (power-- > 0) + { + /* s0 u + t0 v = (s0 - v/g) u - (t0 + u/g) v */ + if (mpz_odd_p (s0) || mpz_odd_p (t0)) + { + mpz_sub (s0, s0, s1); + mpz_add (t0, t0, t1); + } + assert (mpz_even_p (t0) && mpz_even_p (s0)); + mpz_tdiv_q_2exp (s0, s0, 1); + mpz_tdiv_q_2exp (t0, t0, 1); + } + + /* Arrange so that |s| < |u| / 2g */ + mpz_add (s1, s0, s1); + if (mpz_cmpabs (s0, s1) > 0) + { + mpz_swap (s0, s1); + mpz_sub (t0, t0, t1); + } + if (u->_mp_size < 0) + mpz_neg (s0, s0); + if (v->_mp_size < 0) + mpz_neg (t0, t0); + + mpz_swap (g, tv); + if (s) + mpz_swap (s, s0); + if (t) + mpz_swap (t, t0); + + mpz_clear (tu); + mpz_clear (tv); + mpz_clear (s0); + mpz_clear (s1); + mpz_clear (t0); + mpz_clear (t1); +} + +void +mpz_lcm (mpz_t r, const mpz_t u, const mpz_t v) +{ + mpz_t g; + + if (u->_mp_size == 0 || v->_mp_size == 0) + { + r->_mp_size = 0; + return; + } + + mpz_init (g); + + mpz_gcd (g, u, v); + mpz_divexact (g, u, g); + mpz_mul (r, g, v); + + mpz_clear (g); + mpz_abs (r, r); +} + +void +mpz_lcm_ui (mpz_t r, const mpz_t u, unsigned long v) +{ + if (v == 0 || u->_mp_size == 0) + { + r->_mp_size = 0; + return; + } + + v /= mpz_gcd_ui (NULL, u, v); + mpz_mul_ui (r, u, v); + + mpz_abs (r, r); +} + +int +mpz_invert (mpz_t r, const mpz_t u, const mpz_t m) +{ + mpz_t g, tr; + int invertible; + + if (u->_mp_size == 0 || mpz_cmpabs_ui (m, 1) <= 0) + return 0; + + mpz_init (g); + mpz_init (tr); + + mpz_gcdext (g, tr, NULL, u, m); + invertible = (mpz_cmp_ui (g, 1) == 0); + + if (invertible) + { + if (tr->_mp_size < 0) + { + if (m->_mp_size >= 0) + mpz_add (tr, tr, m); + else + mpz_sub (tr, tr, m); + } + mpz_swap (r, tr); + } + + mpz_clear (g); + mpz_clear (tr); + return invertible; +} + + +/* Higher level operations (sqrt, pow and root) */ + +void +mpz_pow_ui (mpz_t r, const mpz_t b, unsigned long e) +{ + unsigned long bit; + mpz_t tr; + mpz_init_set_ui (tr, 1); + + bit = GMP_ULONG_HIGHBIT; + do + { + mpz_mul (tr, tr, tr); + if (e & bit) + mpz_mul (tr, tr, b); + bit >>= 1; + } + while (bit > 0); + + mpz_swap (r, tr); + mpz_clear (tr); +} + +void +mpz_ui_pow_ui (mpz_t r, unsigned long blimb, unsigned long e) +{ + mpz_t b; + + mpz_init_set_ui (b, blimb); + mpz_pow_ui (r, b, e); + mpz_clear (b); +} + +void +mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m) +{ + mpz_t tr; + mpz_t base; + mp_size_t en, mn; + mp_srcptr mp; + struct gmp_div_inverse minv; + unsigned shift; + mp_ptr tp = NULL; + + en = GMP_ABS (e->_mp_size); + mn = GMP_ABS (m->_mp_size); + if (mn == 0) + gmp_die ("mpz_powm: Zero modulo."); + + if (en == 0) + { + mpz_set_ui (r, mpz_cmpabs_ui (m, 1)); + return; + } + + mp = m->_mp_d; + mpn_div_qr_invert (&minv, mp, mn); + shift = minv.shift; + + if (shift > 0) + { + /* To avoid shifts, we do all our reductions, except the final + one, using a *normalized* m. */ + minv.shift = 0; + + tp = gmp_alloc_limbs (mn); + gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift)); + mp = tp; + } + + mpz_init (base); + + if (e->_mp_size < 0) + { + if (!mpz_invert (base, b, m)) + gmp_die ("mpz_powm: Negative exponent and non-invertible base."); + } + else + { + mp_size_t bn; + mpz_abs (base, b); + + bn = base->_mp_size; + if (bn >= mn) + { + mpn_div_qr_preinv (NULL, base->_mp_d, base->_mp_size, mp, mn, &minv); + bn = mn; + } + + /* We have reduced the absolute value. Now take care of the + sign. Note that we get zero represented non-canonically as + m. */ + if (b->_mp_size < 0) + { + mp_ptr bp = MPZ_REALLOC (base, mn); + gmp_assert_nocarry (mpn_sub (bp, mp, mn, bp, bn)); + bn = mn; + } + base->_mp_size = mpn_normalized_size (base->_mp_d, bn); + } + mpz_init_set_ui (tr, 1); + + while (--en >= 0) + { + mp_limb_t w = e->_mp_d[en]; + mp_limb_t bit; + + bit = GMP_LIMB_HIGHBIT; + do + { + mpz_mul (tr, tr, tr); + if (w & bit) + mpz_mul (tr, tr, base); + if (tr->_mp_size > mn) + { + mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv); + tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn); + } + bit >>= 1; + } + while (bit > 0); + } + + /* Final reduction */ + if (tr->_mp_size >= mn) + { + minv.shift = shift; + mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv); + tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn); + } + if (tp) + gmp_free_limbs (tp, mn); + + mpz_swap (r, tr); + mpz_clear (tr); + mpz_clear (base); +} + +void +mpz_powm_ui (mpz_t r, const mpz_t b, unsigned long elimb, const mpz_t m) +{ + mpz_t e; + + mpz_init_set_ui (e, elimb); + mpz_powm (r, b, e, m); + mpz_clear (e); +} + +/* x=trunc(y^(1/z)), r=y-x^z */ +void +mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z) +{ + int sgn; + mp_bitcnt_t bc; + mpz_t t, u; + + sgn = y->_mp_size < 0; + if ((~z & sgn) != 0) + gmp_die ("mpz_rootrem: Negative argument, with even root."); + if (z == 0) + gmp_die ("mpz_rootrem: Zeroth root."); + + if (mpz_cmpabs_ui (y, 1) <= 0) { + if (x) + mpz_set (x, y); + if (r) + r->_mp_size = 0; + return; + } + + mpz_init (u); + mpz_init (t); + bc = (mpz_sizeinbase (y, 2) - 1) / z + 1; + mpz_setbit (t, bc); + + if (z == 2) /* simplify sqrt loop: z-1 == 1 */ + do { + mpz_swap (u, t); /* u = x */ + mpz_tdiv_q (t, y, u); /* t = y/x */ + mpz_add (t, t, u); /* t = y/x + x */ + mpz_tdiv_q_2exp (t, t, 1); /* x'= (y/x + x)/2 */ + } while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */ + else /* z != 2 */ { + mpz_t v; + + mpz_init (v); + if (sgn) + mpz_neg (t, t); + + do { + mpz_swap (u, t); /* u = x */ + mpz_pow_ui (t, u, z - 1); /* t = x^(z-1) */ + mpz_tdiv_q (t, y, t); /* t = y/x^(z-1) */ + mpz_mul_ui (v, u, z - 1); /* v = x*(z-1) */ + mpz_add (t, t, v); /* t = y/x^(z-1) + x*(z-1) */ + mpz_tdiv_q_ui (t, t, z); /* x'=(y/x^(z-1) + x*(z-1))/z */ + } while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */ + + mpz_clear (v); + } + + if (r) { + mpz_pow_ui (t, u, z); + mpz_sub (r, y, t); + } + if (x) + mpz_swap (x, u); + mpz_clear (u); + mpz_clear (t); +} + +int +mpz_root (mpz_t x, const mpz_t y, unsigned long z) +{ + int res; + mpz_t r; + + mpz_init (r); + mpz_rootrem (x, r, y, z); + res = r->_mp_size == 0; + mpz_clear (r); + + return res; +} + +/* Compute s = floor(sqrt(u)) and r = u - s^2. Allows r == NULL */ +void +mpz_sqrtrem (mpz_t s, mpz_t r, const mpz_t u) +{ + mpz_rootrem (s, r, u, 2); +} + +void +mpz_sqrt (mpz_t s, const mpz_t u) +{ + mpz_rootrem (s, NULL, u, 2); +} + +int +mpz_perfect_square_p (const mpz_t u) +{ + if (u->_mp_size <= 0) + return (u->_mp_size == 0); + else + return mpz_root (NULL, u, 2); +} + +int +mpn_perfect_square_p (mp_srcptr p, mp_size_t n) +{ + mpz_t t; + + assert (n > 0); + assert (p [n-1] != 0); + return mpz_root (NULL, mpz_roinit_normal_n (t, p, n), 2); +} + +mp_size_t +mpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr p, mp_size_t n) +{ + mpz_t s, r, u; + mp_size_t res; + + assert (n > 0); + assert (p [n-1] != 0); + + mpz_init (r); + mpz_init (s); + mpz_rootrem (s, r, mpz_roinit_normal_n (u, p, n), 2); + + assert (s->_mp_size == (n+1)/2); + mpn_copyd (sp, s->_mp_d, s->_mp_size); + mpz_clear (s); + res = r->_mp_size; + if (rp) + mpn_copyd (rp, r->_mp_d, res); + mpz_clear (r); + return res; +} + +/* Combinatorics */ + +void +mpz_mfac_uiui (mpz_t x, unsigned long n, unsigned long m) +{ + mpz_set_ui (x, n + (n == 0)); + if (m + 1 < 2) return; + while (n > m + 1) + mpz_mul_ui (x, x, n -= m); +} + +void +mpz_2fac_ui (mpz_t x, unsigned long n) +{ + mpz_mfac_uiui (x, n, 2); +} + +void +mpz_fac_ui (mpz_t x, unsigned long n) +{ + mpz_mfac_uiui (x, n, 1); +} + +void +mpz_bin_uiui (mpz_t r, unsigned long n, unsigned long k) +{ + mpz_t t; + + mpz_set_ui (r, k <= n); + + if (k > (n >> 1)) + k = (k <= n) ? n - k : 0; + + mpz_init (t); + mpz_fac_ui (t, k); + + for (; k > 0; --k) + mpz_mul_ui (r, r, n--); + + mpz_divexact (r, r, t); + mpz_clear (t); +} + + +/* Primality testing */ + +/* Computes Kronecker (a/b) with odd b, a!=0 and GCD(a,b) = 1 */ +/* Adapted from JACOBI_BASE_METHOD==4 in mpn/generic/jacbase.c */ +static int +gmp_jacobi_coprime (mp_limb_t a, mp_limb_t b) +{ + int c, bit = 0; + + assert (b & 1); + assert (a != 0); + /* assert (mpn_gcd_11 (a, b) == 1); */ + + /* Below, we represent a and b shifted right so that the least + significant one bit is implicit. */ + b >>= 1; + + gmp_ctz(c, a); + a >>= 1; + + for (;;) + { + a >>= c; + /* (2/b) = -1 if b = 3 or 5 mod 8 */ + bit ^= c & (b ^ (b >> 1)); + if (a < b) + { + if (a == 0) + return bit & 1 ? -1 : 1; + bit ^= a & b; + a = b - a; + b -= a; + } + else + { + a -= b; + assert (a != 0); + } + + gmp_ctz(c, a); + ++c; + } +} + +static void +gmp_lucas_step_k_2k (mpz_t V, mpz_t Qk, const mpz_t n) +{ + mpz_mod (Qk, Qk, n); + /* V_{2k} <- V_k ^ 2 - 2Q^k */ + mpz_mul (V, V, V); + mpz_submul_ui (V, Qk, 2); + mpz_tdiv_r (V, V, n); + /* Q^{2k} = (Q^k)^2 */ + mpz_mul (Qk, Qk, Qk); +} + +/* Computes V_k, Q^k (mod n) for the Lucas' sequence */ +/* with P=1, Q=Q; k = (n>>b0)|1. */ +/* Requires an odd n > 4; b0 > 0; -2*Q must not overflow a long */ +/* Returns (U_k == 0) and sets V=V_k and Qk=Q^k. */ +static int +gmp_lucas_mod (mpz_t V, mpz_t Qk, long Q, + mp_bitcnt_t b0, const mpz_t n) +{ + mp_bitcnt_t bs; + mpz_t U; + int res; + + assert (b0 > 0); + assert (Q <= - (LONG_MIN / 2)); + assert (Q >= - (LONG_MAX / 2)); + assert (mpz_cmp_ui (n, 4) > 0); + assert (mpz_odd_p (n)); + + mpz_init_set_ui (U, 1); /* U1 = 1 */ + mpz_set_ui (V, 1); /* V1 = 1 */ + mpz_set_si (Qk, Q); + + for (bs = mpz_sizeinbase (n, 2) - 1; --bs >= b0;) + { + /* U_{2k} <- U_k * V_k */ + mpz_mul (U, U, V); + /* V_{2k} <- V_k ^ 2 - 2Q^k */ + /* Q^{2k} = (Q^k)^2 */ + gmp_lucas_step_k_2k (V, Qk, n); + + /* A step k->k+1 is performed if the bit in $n$ is 1 */ + /* mpz_tstbit(n,bs) or the bit is 0 in $n$ but */ + /* should be 1 in $n+1$ (bs == b0) */ + if (b0 == bs || mpz_tstbit (n, bs)) + { + /* Q^{k+1} <- Q^k * Q */ + mpz_mul_si (Qk, Qk, Q); + /* U_{k+1} <- (U_k + V_k) / 2 */ + mpz_swap (U, V); /* Keep in V the old value of U_k */ + mpz_add (U, U, V); + /* We have to compute U/2, so we need an even value, */ + /* equivalent (mod n) */ + if (mpz_odd_p (U)) + mpz_add (U, U, n); + mpz_tdiv_q_2exp (U, U, 1); + /* V_{k+1} <-(D*U_k + V_k) / 2 = + U_{k+1} + (D-1)/2*U_k = U_{k+1} - 2Q*U_k */ + mpz_mul_si (V, V, -2*Q); + mpz_add (V, U, V); + mpz_tdiv_r (V, V, n); + } + mpz_tdiv_r (U, U, n); + } + + res = U->_mp_size == 0; + mpz_clear (U); + return res; +} + +/* Performs strong Lucas' test on x, with parameters suggested */ +/* for the BPSW test. Qk is only passed to recycle a variable. */ +/* Requires GCD (x,6) = 1.*/ +static int +gmp_stronglucas (const mpz_t x, mpz_t Qk) +{ + mp_bitcnt_t b0; + mpz_t V, n; + mp_limb_t maxD, D; /* The absolute value is stored. */ + long Q; + mp_limb_t tl; + + /* Test on the absolute value. */ + mpz_roinit_normal_n (n, x->_mp_d, GMP_ABS (x->_mp_size)); + + assert (mpz_odd_p (n)); + /* assert (mpz_gcd_ui (NULL, n, 6) == 1); */ + if (mpz_root (Qk, n, 2)) + return 0; /* A square is composite. */ + + /* Check Ds up to square root (in case, n is prime) + or avoid overflows */ + maxD = (Qk->_mp_size == 1) ? Qk->_mp_d [0] - 1 : GMP_LIMB_MAX; + + D = 3; + /* Search a D such that (D/n) = -1 in the sequence 5,-7,9,-11,.. */ + /* For those Ds we have (D/n) = (n/|D|) */ + do + { + if (D >= maxD) + return 1 + (D != GMP_LIMB_MAX); /* (1 + ! ~ D) */ + D += 2; + tl = mpz_tdiv_ui (n, D); + if (tl == 0) + return 0; + } + while (gmp_jacobi_coprime (tl, D) == 1); + + mpz_init (V); + + /* n-(D/n) = n+1 = d*2^{b0}, with d = (n>>b0) | 1 */ + b0 = mpn_common_scan (~ n->_mp_d[0], 0, n->_mp_d, n->_mp_size, GMP_LIMB_MAX); + /* b0 = mpz_scan0 (n, 0); */ + + /* D= P^2 - 4Q; P = 1; Q = (1-D)/4 */ + Q = (D & 2) ? (long) (D >> 2) + 1 : -(long) (D >> 2); + + if (! gmp_lucas_mod (V, Qk, Q, b0, n)) /* If Ud != 0 */ + while (V->_mp_size != 0 && --b0 != 0) /* while Vk != 0 */ + /* V <- V ^ 2 - 2Q^k */ + /* Q^{2k} = (Q^k)^2 */ + gmp_lucas_step_k_2k (V, Qk, n); + + mpz_clear (V); + return (b0 != 0); +} + +static int +gmp_millerrabin (const mpz_t n, const mpz_t nm1, mpz_t y, + const mpz_t q, mp_bitcnt_t k) +{ + assert (k > 0); + + /* Caller must initialize y to the base. */ + mpz_powm (y, y, q, n); + + if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0) + return 1; + + while (--k > 0) + { + mpz_powm_ui (y, y, 2, n); + if (mpz_cmp (y, nm1) == 0) + return 1; + } + return 0; +} + +/* This product is 0xc0cfd797, and fits in 32 bits. */ +#define GMP_PRIME_PRODUCT \ + (3UL*5UL*7UL*11UL*13UL*17UL*19UL*23UL*29UL) + +/* Bit (p+1)/2 is set, for each odd prime <= 61 */ +#define GMP_PRIME_MASK 0xc96996dcUL + +int +mpz_probab_prime_p (const mpz_t n, int reps) +{ + mpz_t nm1; + mpz_t q; + mpz_t y; + mp_bitcnt_t k; + int is_prime; + int j; + + /* Note that we use the absolute value of n only, for compatibility + with the real GMP. */ + if (mpz_even_p (n)) + return (mpz_cmpabs_ui (n, 2) == 0) ? 2 : 0; + + /* Above test excludes n == 0 */ + assert (n->_mp_size != 0); + + if (mpz_cmpabs_ui (n, 64) < 0) + return (GMP_PRIME_MASK >> (n->_mp_d[0] >> 1)) & 2; + + if (mpz_gcd_ui (NULL, n, GMP_PRIME_PRODUCT) != 1) + return 0; + + /* All prime factors are >= 31. */ + if (mpz_cmpabs_ui (n, 31*31) < 0) + return 2; + + mpz_init (nm1); + mpz_init (q); + + /* Find q and k, where q is odd and n = 1 + 2**k * q. */ + mpz_abs (nm1, n); + nm1->_mp_d[0] -= 1; + /* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */ + k = mpn_scan1 (nm1->_mp_d, 0); + mpz_tdiv_q_2exp (q, nm1, k); + + /* BPSW test */ + mpz_init_set_ui (y, 2); + is_prime = gmp_millerrabin (n, nm1, y, q, k) && gmp_stronglucas (n, y); + reps -= 24; /* skip the first 24 repetitions */ + + /* Use Miller-Rabin, with a deterministic sequence of bases, a[j] = + j^2 + j + 41 using Euler's polynomial. We potentially stop early, + if a[j] >= n - 1. Since n >= 31*31, this can happen only if reps > + 30 (a[30] == 971 > 31*31 == 961). */ + + for (j = 0; is_prime & (j < reps); j++) + { + mpz_set_ui (y, (unsigned long) j*j+j+41); + if (mpz_cmp (y, nm1) >= 0) + { + /* Don't try any further bases. This "early" break does not affect + the result for any reasonable reps value (<=5000 was tested) */ + assert (j >= 30); + break; + } + is_prime = gmp_millerrabin (n, nm1, y, q, k); + } + mpz_clear (nm1); + mpz_clear (q); + mpz_clear (y); + + return is_prime; +} + + +/* Logical operations and bit manipulation. */ + +/* Numbers are treated as if represented in two's complement (and + infinitely sign extended). For a negative values we get the two's + complement from -x = ~x + 1, where ~ is bitwise complement. + Negation transforms + + xxxx10...0 + + into + + yyyy10...0 + + where yyyy is the bitwise complement of xxxx. So least significant + bits, up to and including the first one bit, are unchanged, and + the more significant bits are all complemented. + + To change a bit from zero to one in a negative number, subtract the + corresponding power of two from the absolute value. This can never + underflow. To change a bit from one to zero, add the corresponding + power of two, and this might overflow. E.g., if x = -001111, the + two's complement is 110001. Clearing the least significant bit, we + get two's complement 110000, and -010000. */ + +int +mpz_tstbit (const mpz_t d, mp_bitcnt_t bit_index) +{ + mp_size_t limb_index; + unsigned shift; + mp_size_t ds; + mp_size_t dn; + mp_limb_t w; + int bit; + + ds = d->_mp_size; + dn = GMP_ABS (ds); + limb_index = bit_index / GMP_LIMB_BITS; + if (limb_index >= dn) + return ds < 0; + + shift = bit_index % GMP_LIMB_BITS; + w = d->_mp_d[limb_index]; + bit = (w >> shift) & 1; + + if (ds < 0) + { + /* d < 0. Check if any of the bits below is set: If so, our bit + must be complemented. */ + if (shift > 0 && (mp_limb_t) (w << (GMP_LIMB_BITS - shift)) > 0) + return bit ^ 1; + while (--limb_index >= 0) + if (d->_mp_d[limb_index] > 0) + return bit ^ 1; + } + return bit; +} + +static void +mpz_abs_add_bit (mpz_t d, mp_bitcnt_t bit_index) +{ + mp_size_t dn, limb_index; + mp_limb_t bit; + mp_ptr dp; + + dn = GMP_ABS (d->_mp_size); + + limb_index = bit_index / GMP_LIMB_BITS; + bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS); + + if (limb_index >= dn) + { + mp_size_t i; + /* The bit should be set outside of the end of the number. + We have to increase the size of the number. */ + dp = MPZ_REALLOC (d, limb_index + 1); + + dp[limb_index] = bit; + for (i = dn; i < limb_index; i++) + dp[i] = 0; + dn = limb_index + 1; + } + else + { + mp_limb_t cy; + + dp = d->_mp_d; + + cy = mpn_add_1 (dp + limb_index, dp + limb_index, dn - limb_index, bit); + if (cy > 0) + { + dp = MPZ_REALLOC (d, dn + 1); + dp[dn++] = cy; + } + } + + d->_mp_size = (d->_mp_size < 0) ? - dn : dn; +} + +static void +mpz_abs_sub_bit (mpz_t d, mp_bitcnt_t bit_index) +{ + mp_size_t dn, limb_index; + mp_ptr dp; + mp_limb_t bit; + + dn = GMP_ABS (d->_mp_size); + dp = d->_mp_d; + + limb_index = bit_index / GMP_LIMB_BITS; + bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS); + + assert (limb_index < dn); + + gmp_assert_nocarry (mpn_sub_1 (dp + limb_index, dp + limb_index, + dn - limb_index, bit)); + dn = mpn_normalized_size (dp, dn); + d->_mp_size = (d->_mp_size < 0) ? - dn : dn; +} + +void +mpz_setbit (mpz_t d, mp_bitcnt_t bit_index) +{ + if (!mpz_tstbit (d, bit_index)) + { + if (d->_mp_size >= 0) + mpz_abs_add_bit (d, bit_index); + else + mpz_abs_sub_bit (d, bit_index); + } +} + +void +mpz_clrbit (mpz_t d, mp_bitcnt_t bit_index) +{ + if (mpz_tstbit (d, bit_index)) + { + if (d->_mp_size >= 0) + mpz_abs_sub_bit (d, bit_index); + else + mpz_abs_add_bit (d, bit_index); + } +} + +void +mpz_combit (mpz_t d, mp_bitcnt_t bit_index) +{ + if (mpz_tstbit (d, bit_index) ^ (d->_mp_size < 0)) + mpz_abs_sub_bit (d, bit_index); + else + mpz_abs_add_bit (d, bit_index); +} + +void +mpz_com (mpz_t r, const mpz_t u) +{ + mpz_add_ui (r, u, 1); + mpz_neg (r, r); +} + +void +mpz_and (mpz_t r, const mpz_t u, const mpz_t v) +{ + mp_size_t un, vn, rn, i; + mp_ptr up, vp, rp; + + mp_limb_t ux, vx, rx; + mp_limb_t uc, vc, rc; + mp_limb_t ul, vl, rl; + + un = GMP_ABS (u->_mp_size); + vn = GMP_ABS (v->_mp_size); + if (un < vn) + { + MPZ_SRCPTR_SWAP (u, v); + MP_SIZE_T_SWAP (un, vn); + } + if (vn == 0) + { + r->_mp_size = 0; + return; + } + + uc = u->_mp_size < 0; + vc = v->_mp_size < 0; + rc = uc & vc; + + ux = -uc; + vx = -vc; + rx = -rc; + + /* If the smaller input is positive, higher limbs don't matter. */ + rn = vx ? un : vn; + + rp = MPZ_REALLOC (r, rn + (mp_size_t) rc); + + up = u->_mp_d; + vp = v->_mp_d; + + i = 0; + do + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + vl = (vp[i] ^ vx) + vc; + vc = vl < vc; + + rl = ( (ul & vl) ^ rx) + rc; + rc = rl < rc; + rp[i] = rl; + } + while (++i < vn); + assert (vc == 0); + + for (; i < rn; i++) + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + rl = ( (ul & vx) ^ rx) + rc; + rc = rl < rc; + rp[i] = rl; + } + if (rc) + rp[rn++] = rc; + else + rn = mpn_normalized_size (rp, rn); + + r->_mp_size = rx ? -rn : rn; +} + +void +mpz_ior (mpz_t r, const mpz_t u, const mpz_t v) +{ + mp_size_t un, vn, rn, i; + mp_ptr up, vp, rp; + + mp_limb_t ux, vx, rx; + mp_limb_t uc, vc, rc; + mp_limb_t ul, vl, rl; + + un = GMP_ABS (u->_mp_size); + vn = GMP_ABS (v->_mp_size); + if (un < vn) + { + MPZ_SRCPTR_SWAP (u, v); + MP_SIZE_T_SWAP (un, vn); + } + if (vn == 0) + { + mpz_set (r, u); + return; + } + + uc = u->_mp_size < 0; + vc = v->_mp_size < 0; + rc = uc | vc; + + ux = -uc; + vx = -vc; + rx = -rc; + + /* If the smaller input is negative, by sign extension higher limbs + don't matter. */ + rn = vx ? vn : un; + + rp = MPZ_REALLOC (r, rn + (mp_size_t) rc); + + up = u->_mp_d; + vp = v->_mp_d; + + i = 0; + do + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + vl = (vp[i] ^ vx) + vc; + vc = vl < vc; + + rl = ( (ul | vl) ^ rx) + rc; + rc = rl < rc; + rp[i] = rl; + } + while (++i < vn); + assert (vc == 0); + + for (; i < rn; i++) + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + rl = ( (ul | vx) ^ rx) + rc; + rc = rl < rc; + rp[i] = rl; + } + if (rc) + rp[rn++] = rc; + else + rn = mpn_normalized_size (rp, rn); + + r->_mp_size = rx ? -rn : rn; +} + +void +mpz_xor (mpz_t r, const mpz_t u, const mpz_t v) +{ + mp_size_t un, vn, i; + mp_ptr up, vp, rp; + + mp_limb_t ux, vx, rx; + mp_limb_t uc, vc, rc; + mp_limb_t ul, vl, rl; + + un = GMP_ABS (u->_mp_size); + vn = GMP_ABS (v->_mp_size); + if (un < vn) + { + MPZ_SRCPTR_SWAP (u, v); + MP_SIZE_T_SWAP (un, vn); + } + if (vn == 0) + { + mpz_set (r, u); + return; + } + + uc = u->_mp_size < 0; + vc = v->_mp_size < 0; + rc = uc ^ vc; + + ux = -uc; + vx = -vc; + rx = -rc; + + rp = MPZ_REALLOC (r, un + (mp_size_t) rc); + + up = u->_mp_d; + vp = v->_mp_d; + + i = 0; + do + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + vl = (vp[i] ^ vx) + vc; + vc = vl < vc; + + rl = (ul ^ vl ^ rx) + rc; + rc = rl < rc; + rp[i] = rl; + } + while (++i < vn); + assert (vc == 0); + + for (; i < un; i++) + { + ul = (up[i] ^ ux) + uc; + uc = ul < uc; + + rl = (ul ^ ux) + rc; + rc = rl < rc; + rp[i] = rl; + } + if (rc) + rp[un++] = rc; + else + un = mpn_normalized_size (rp, un); + + r->_mp_size = rx ? -un : un; +} + +static unsigned +gmp_popcount_limb (mp_limb_t x) +{ + unsigned c; + + /* Do 16 bits at a time, to avoid limb-sized constants. */ + int LOCAL_SHIFT_BITS = 16; + for (c = 0; x > 0;) + { + unsigned w = x - ((x >> 1) & 0x5555); + w = ((w >> 2) & 0x3333) + (w & 0x3333); + w = (w >> 4) + w; + w = ((w >> 8) & 0x000f) + (w & 0x000f); + c += w; + if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS) + x >>= LOCAL_SHIFT_BITS; + else + x = 0; + } + return c; +} + +mp_bitcnt_t +mpn_popcount (mp_srcptr p, mp_size_t n) +{ + mp_size_t i; + mp_bitcnt_t c; + + for (c = 0, i = 0; i < n; i++) + c += gmp_popcount_limb (p[i]); + + return c; +} + +mp_bitcnt_t +mpz_popcount (const mpz_t u) +{ + mp_size_t un; + + un = u->_mp_size; + + if (un < 0) + return ~(mp_bitcnt_t) 0; + + return mpn_popcount (u->_mp_d, un); +} + +mp_bitcnt_t +mpz_hamdist (const mpz_t u, const mpz_t v) +{ + mp_size_t un, vn, i; + mp_limb_t uc, vc, ul, vl, comp; + mp_srcptr up, vp; + mp_bitcnt_t c; + + un = u->_mp_size; + vn = v->_mp_size; + + if ( (un ^ vn) < 0) + return ~(mp_bitcnt_t) 0; + + comp = - (uc = vc = (un < 0)); + if (uc) + { + assert (vn < 0); + un = -un; + vn = -vn; + } + + up = u->_mp_d; + vp = v->_mp_d; + + if (un < vn) + MPN_SRCPTR_SWAP (up, un, vp, vn); + + for (i = 0, c = 0; i < vn; i++) + { + ul = (up[i] ^ comp) + uc; + uc = ul < uc; + + vl = (vp[i] ^ comp) + vc; + vc = vl < vc; + + c += gmp_popcount_limb (ul ^ vl); + } + assert (vc == 0); + + for (; i < un; i++) + { + ul = (up[i] ^ comp) + uc; + uc = ul < uc; + + c += gmp_popcount_limb (ul ^ comp); + } + + return c; +} + +mp_bitcnt_t +mpz_scan1 (const mpz_t u, mp_bitcnt_t starting_bit) +{ + mp_ptr up; + mp_size_t us, un, i; + mp_limb_t limb, ux; + + us = u->_mp_size; + un = GMP_ABS (us); + i = starting_bit / GMP_LIMB_BITS; + + /* Past the end there's no 1 bits for u>=0, or an immediate 1 bit + for u<0. Notice this test picks up any u==0 too. */ + if (i >= un) + return (us >= 0 ? ~(mp_bitcnt_t) 0 : starting_bit); + + up = u->_mp_d; + ux = 0; + limb = up[i]; + + if (starting_bit != 0) + { + if (us < 0) + { + ux = mpn_zero_p (up, i); + limb = ~ limb + ux; + ux = - (mp_limb_t) (limb >= ux); + } + + /* Mask to 0 all bits before starting_bit, thus ignoring them. */ + limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS); + } + + return mpn_common_scan (limb, i, up, un, ux); +} + +mp_bitcnt_t +mpz_scan0 (const mpz_t u, mp_bitcnt_t starting_bit) +{ + mp_ptr up; + mp_size_t us, un, i; + mp_limb_t limb, ux; + + us = u->_mp_size; + ux = - (mp_limb_t) (us >= 0); + un = GMP_ABS (us); + i = starting_bit / GMP_LIMB_BITS; + + /* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for + u<0. Notice this test picks up all cases of u==0 too. */ + if (i >= un) + return (ux ? starting_bit : ~(mp_bitcnt_t) 0); + + up = u->_mp_d; + limb = up[i] ^ ux; + + if (ux == 0) + limb -= mpn_zero_p (up, i); /* limb = ~(~limb + zero_p) */ + + /* Mask all bits before starting_bit, thus ignoring them. */ + limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS); + + return mpn_common_scan (limb, i, up, un, ux); +} + + +/* MPZ base conversion. */ + +size_t +mpz_sizeinbase (const mpz_t u, int base) +{ + mp_size_t un, tn; + mp_srcptr up; + mp_ptr tp; + mp_bitcnt_t bits; + struct gmp_div_inverse bi; + size_t ndigits; + + assert (base >= 2); + assert (base <= 62); + + un = GMP_ABS (u->_mp_size); + if (un == 0) + return 1; + + up = u->_mp_d; + + bits = (un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]); + switch (base) + { + case 2: + return bits; + case 4: + return (bits + 1) / 2; + case 8: + return (bits + 2) / 3; + case 16: + return (bits + 3) / 4; + case 32: + return (bits + 4) / 5; + /* FIXME: Do something more clever for the common case of base + 10. */ + } + + tp = gmp_alloc_limbs (un); + mpn_copyi (tp, up, un); + mpn_div_qr_1_invert (&bi, base); + + tn = un; + ndigits = 0; + do + { + ndigits++; + mpn_div_qr_1_preinv (tp, tp, tn, &bi); + tn -= (tp[tn-1] == 0); + } + while (tn > 0); + + gmp_free_limbs (tp, un); + return ndigits; +} + +char * +mpz_get_str (char *sp, int base, const mpz_t u) +{ + unsigned bits; + const char *digits; + mp_size_t un; + size_t i, sn, osn; + + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + if (base > 1) + { + if (base <= 36) + digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + else if (base > 62) + return NULL; + } + else if (base >= -1) + base = 10; + else + { + base = -base; + if (base > 36) + return NULL; + } + + sn = 1 + mpz_sizeinbase (u, base); + if (!sp) + { + osn = 1 + sn; + sp = (char *) gmp_alloc (osn); + } + else + osn = 0; + un = GMP_ABS (u->_mp_size); + + if (un == 0) + { + sp[0] = '0'; + sn = 1; + goto ret; + } + + i = 0; + + if (u->_mp_size < 0) + sp[i++] = '-'; + + bits = mpn_base_power_of_two_p (base); + + if (bits) + /* Not modified in this case. */ + sn = i + mpn_get_str_bits ((unsigned char *) sp + i, bits, u->_mp_d, un); + else + { + struct mpn_base_info info; + mp_ptr tp; + + mpn_get_base_info (&info, base); + tp = gmp_alloc_limbs (un); + mpn_copyi (tp, u->_mp_d, un); + + sn = i + mpn_get_str_other ((unsigned char *) sp + i, base, &info, tp, un); + gmp_free_limbs (tp, un); + } + + for (; i < sn; i++) + sp[i] = digits[(unsigned char) sp[i]]; + +ret: + sp[sn] = '\0'; + if (osn && osn != sn + 1) + sp = (char*) gmp_realloc (sp, osn, sn + 1); + return sp; +} + +int +mpz_set_str (mpz_t r, const char *sp, int base) +{ + unsigned bits, value_of_a; + mp_size_t rn, alloc; + mp_ptr rp; + size_t dn, sn; + int sign; + unsigned char *dp; + + assert (base == 0 || (base >= 2 && base <= 62)); + + while (isspace( (unsigned char) *sp)) + sp++; + + sign = (*sp == '-'); + sp += sign; + + if (base == 0) + { + if (sp[0] == '0') + { + if (sp[1] == 'x' || sp[1] == 'X') + { + base = 16; + sp += 2; + } + else if (sp[1] == 'b' || sp[1] == 'B') + { + base = 2; + sp += 2; + } + else + base = 8; + } + else + base = 10; + } + + if (!*sp) + { + r->_mp_size = 0; + return -1; + } + sn = strlen(sp); + dp = (unsigned char *) gmp_alloc (sn); + + value_of_a = (base > 36) ? 36 : 10; + for (dn = 0; *sp; sp++) + { + unsigned digit; + + if (isspace ((unsigned char) *sp)) + continue; + else if (*sp >= '0' && *sp <= '9') + digit = *sp - '0'; + else if (*sp >= 'a' && *sp <= 'z') + digit = *sp - 'a' + value_of_a; + else if (*sp >= 'A' && *sp <= 'Z') + digit = *sp - 'A' + 10; + else + digit = base; /* fail */ + + if (digit >= (unsigned) base) + { + gmp_free (dp, sn); + r->_mp_size = 0; + return -1; + } + + dp[dn++] = digit; + } + + if (!dn) + { + gmp_free (dp, sn); + r->_mp_size = 0; + return -1; + } + bits = mpn_base_power_of_two_p (base); + + if (bits > 0) + { + alloc = (dn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS; + rp = MPZ_REALLOC (r, alloc); + rn = mpn_set_str_bits (rp, dp, dn, bits); + } + else + { + struct mpn_base_info info; + mpn_get_base_info (&info, base); + alloc = (dn + info.exp - 1) / info.exp; + rp = MPZ_REALLOC (r, alloc); + rn = mpn_set_str_other (rp, dp, dn, base, &info); + /* Normalization, needed for all-zero input. */ + assert (rn > 0); + rn -= rp[rn-1] == 0; + } + assert (rn <= alloc); + gmp_free (dp, sn); + + r->_mp_size = sign ? - rn : rn; + + return 0; +} + +int +mpz_init_set_str (mpz_t r, const char *sp, int base) +{ + mpz_init (r); + return mpz_set_str (r, sp, base); +} + +size_t +mpz_out_str (FILE *stream, int base, const mpz_t x) +{ + char *str; + size_t len, n; + + str = mpz_get_str (NULL, base, x); + if (!str) + return 0; + len = strlen (str); + n = fwrite (str, 1, len, stream); + gmp_free (str, len + 1); + return n; +} + + +static int +gmp_detect_endian (void) +{ + static const int i = 2; + const unsigned char *p = (const unsigned char *) &i; + return 1 - *p; +} + +/* Import and export. Does not support nails. */ +void +mpz_import (mpz_t r, size_t count, int order, size_t size, int endian, + size_t nails, const void *src) +{ + const unsigned char *p; + ptrdiff_t word_step; + mp_ptr rp; + mp_size_t rn; + + /* The current (partial) limb. */ + mp_limb_t limb; + /* The number of bytes already copied to this limb (starting from + the low end). */ + size_t bytes; + /* The index where the limb should be stored, when completed. */ + mp_size_t i; + + if (nails != 0) + gmp_die ("mpz_import: Nails not supported."); + + assert (order == 1 || order == -1); + assert (endian >= -1 && endian <= 1); + + if (endian == 0) + endian = gmp_detect_endian (); + + p = (unsigned char *) src; + + word_step = (order != endian) ? 2 * size : 0; + + /* Process bytes from the least significant end, so point p at the + least significant word. */ + if (order == 1) + { + p += size * (count - 1); + word_step = - word_step; + } + + /* And at least significant byte of that word. */ + if (endian == 1) + p += (size - 1); + + rn = (size * count + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t); + rp = MPZ_REALLOC (r, rn); + + for (limb = 0, bytes = 0, i = 0; count > 0; count--, p += word_step) + { + size_t j; + for (j = 0; j < size; j++, p -= (ptrdiff_t) endian) + { + limb |= (mp_limb_t) *p << (bytes++ * CHAR_BIT); + if (bytes == sizeof(mp_limb_t)) + { + rp[i++] = limb; + bytes = 0; + limb = 0; + } + } + } + assert (i + (bytes > 0) == rn); + if (limb != 0) + rp[i++] = limb; + else + i = mpn_normalized_size (rp, i); + + r->_mp_size = i; +} + +void * +mpz_export (void *r, size_t *countp, int order, size_t size, int endian, + size_t nails, const mpz_t u) +{ + size_t count; + mp_size_t un; + + if (nails != 0) + gmp_die ("mpz_export: Nails not supported."); + + assert (order == 1 || order == -1); + assert (endian >= -1 && endian <= 1); + assert (size > 0 || u->_mp_size == 0); + + un = u->_mp_size; + count = 0; + if (un != 0) + { + size_t k; + unsigned char *p; + ptrdiff_t word_step; + /* The current (partial) limb. */ + mp_limb_t limb; + /* The number of bytes left to do in this limb. */ + size_t bytes; + /* The index where the limb was read. */ + mp_size_t i; + + un = GMP_ABS (un); + + /* Count bytes in top limb. */ + limb = u->_mp_d[un-1]; + assert (limb != 0); + + k = (GMP_LIMB_BITS <= CHAR_BIT); + if (!k) + { + do { + int LOCAL_CHAR_BIT = CHAR_BIT; + k++; limb >>= LOCAL_CHAR_BIT; + } while (limb != 0); + } + /* else limb = 0; */ + + count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size; + + if (!r) + r = gmp_alloc (count * size); + + if (endian == 0) + endian = gmp_detect_endian (); + + p = (unsigned char *) r; + + word_step = (order != endian) ? 2 * size : 0; + + /* Process bytes from the least significant end, so point p at the + least significant word. */ + if (order == 1) + { + p += size * (count - 1); + word_step = - word_step; + } + + /* And at least significant byte of that word. */ + if (endian == 1) + p += (size - 1); + + for (bytes = 0, i = 0, k = 0; k < count; k++, p += word_step) + { + size_t j; + for (j = 0; j < size; ++j, p -= (ptrdiff_t) endian) + { + if (sizeof (mp_limb_t) == 1) + { + if (i < un) + *p = u->_mp_d[i++]; + else + *p = 0; + } + else + { + int LOCAL_CHAR_BIT = CHAR_BIT; + if (bytes == 0) + { + if (i < un) + limb = u->_mp_d[i++]; + bytes = sizeof (mp_limb_t); + } + *p = limb; + limb >>= LOCAL_CHAR_BIT; + bytes--; + } + } + } + assert (i == un); + assert (k == count); + } + + if (countp) + *countp = count; + + return r; +} diff --git a/gmp-6.3.0/mini-gmp/mini-gmp.h b/gmp-6.3.0/mini-gmp/mini-gmp.h new file mode 100644 index 0000000..59c24cf --- /dev/null +++ b/gmp-6.3.0/mini-gmp/mini-gmp.h @@ -0,0 +1,310 @@ +/* mini-gmp, a minimalistic implementation of a GNU GMP subset. + +Copyright 2011-2015, 2017, 2019-2021 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/. */ + +/* About mini-gmp: This is a minimal implementation of a subset of the + GMP interface. It is intended for inclusion into applications which + have modest bignums needs, as a fallback when the real GMP library + is not installed. + + This file defines the public interface. */ + +#ifndef __MINI_GMP_H__ +#define __MINI_GMP_H__ + +/* For size_t */ +#include + +#if defined (__cplusplus) +extern "C" { +#endif + +void mp_set_memory_functions (void *(*) (size_t), + void *(*) (void *, size_t, size_t), + void (*) (void *, size_t)); + +void mp_get_memory_functions (void *(**) (size_t), + void *(**) (void *, size_t, size_t), + void (**) (void *, size_t)); + +#ifndef MINI_GMP_LIMB_TYPE +#define MINI_GMP_LIMB_TYPE long +#endif + +typedef unsigned MINI_GMP_LIMB_TYPE mp_limb_t; +typedef long mp_size_t; +typedef unsigned long mp_bitcnt_t; + +typedef mp_limb_t *mp_ptr; +typedef const mp_limb_t *mp_srcptr; + +typedef struct +{ + int _mp_alloc; /* Number of *limbs* allocated and pointed + to by the _mp_d field. */ + int _mp_size; /* abs(_mp_size) is the number of limbs the + last field points to. If _mp_size is + negative this is a negative number. */ + mp_limb_t *_mp_d; /* Pointer to the limbs. */ +} __mpz_struct; + +typedef __mpz_struct mpz_t[1]; + +typedef __mpz_struct *mpz_ptr; +typedef const __mpz_struct *mpz_srcptr; + +extern const int mp_bits_per_limb; + +void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t); +void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t); +void mpn_zero (mp_ptr, mp_size_t); + +int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t); +int mpn_zero_p (mp_srcptr, mp_size_t); + +mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t); +mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t); +mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t); + +mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t); +mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t); +mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t); + +mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t); +mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t); +mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t); + +mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t); +void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t); +void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t); +int mpn_perfect_square_p (mp_srcptr, mp_size_t); +mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t); + +mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int); +mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int); + +mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t); +mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t); + +void mpn_com (mp_ptr, mp_srcptr, mp_size_t); +mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t); + +mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t); + +mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t); +#define mpn_invert_limb(x) mpn_invert_3by2 ((x), 0) + +size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t); +mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int); + +void mpz_init (mpz_t); +void mpz_init2 (mpz_t, mp_bitcnt_t); +void mpz_clear (mpz_t); + +#define mpz_odd_p(z) (((z)->_mp_size != 0) & (int) (z)->_mp_d[0]) +#define mpz_even_p(z) (! mpz_odd_p (z)) + +int mpz_sgn (const mpz_t); +int mpz_cmp_si (const mpz_t, long); +int mpz_cmp_ui (const mpz_t, unsigned long); +int mpz_cmp (const mpz_t, const mpz_t); +int mpz_cmpabs_ui (const mpz_t, unsigned long); +int mpz_cmpabs (const mpz_t, const mpz_t); +int mpz_cmp_d (const mpz_t, double); +int mpz_cmpabs_d (const mpz_t, double); + +void mpz_abs (mpz_t, const mpz_t); +void mpz_neg (mpz_t, const mpz_t); +void mpz_swap (mpz_t, mpz_t); + +void mpz_add_ui (mpz_t, const mpz_t, unsigned long); +void mpz_add (mpz_t, const mpz_t, const mpz_t); +void mpz_sub_ui (mpz_t, const mpz_t, unsigned long); +void mpz_ui_sub (mpz_t, unsigned long, const mpz_t); +void mpz_sub (mpz_t, const mpz_t, const mpz_t); + +void mpz_mul_si (mpz_t, const mpz_t, long int); +void mpz_mul_ui (mpz_t, const mpz_t, unsigned long int); +void mpz_mul (mpz_t, const mpz_t, const mpz_t); +void mpz_mul_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_addmul_ui (mpz_t, const mpz_t, unsigned long int); +void mpz_addmul (mpz_t, const mpz_t, const mpz_t); +void mpz_submul_ui (mpz_t, const mpz_t, unsigned long int); +void mpz_submul (mpz_t, const mpz_t, const mpz_t); + +void mpz_cdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t); +void mpz_fdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t); +void mpz_tdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t); +void mpz_cdiv_q (mpz_t, const mpz_t, const mpz_t); +void mpz_fdiv_q (mpz_t, const mpz_t, const mpz_t); +void mpz_tdiv_q (mpz_t, const mpz_t, const mpz_t); +void mpz_cdiv_r (mpz_t, const mpz_t, const mpz_t); +void mpz_fdiv_r (mpz_t, const mpz_t, const mpz_t); +void mpz_tdiv_r (mpz_t, const mpz_t, const mpz_t); + +void mpz_cdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_fdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_tdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_cdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_fdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t); +void mpz_tdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t); + +void mpz_mod (mpz_t, const mpz_t, const mpz_t); + +void mpz_divexact (mpz_t, const mpz_t, const mpz_t); + +int mpz_divisible_p (const mpz_t, const mpz_t); +int mpz_congruent_p (const mpz_t, const mpz_t, const mpz_t); + +unsigned long mpz_cdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long); +unsigned long mpz_fdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long); +unsigned long mpz_tdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long); +unsigned long mpz_cdiv_q_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_fdiv_q_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_tdiv_q_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_cdiv_r_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_fdiv_r_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_tdiv_r_ui (mpz_t, const mpz_t, unsigned long); +unsigned long mpz_cdiv_ui (const mpz_t, unsigned long); +unsigned long mpz_fdiv_ui (const mpz_t, unsigned long); +unsigned long mpz_tdiv_ui (const mpz_t, unsigned long); + +unsigned long mpz_mod_ui (mpz_t, const mpz_t, unsigned long); + +void mpz_divexact_ui (mpz_t, const mpz_t, unsigned long); + +int mpz_divisible_ui_p (const mpz_t, unsigned long); + +unsigned long mpz_gcd_ui (mpz_t, const mpz_t, unsigned long); +void mpz_gcd (mpz_t, const mpz_t, const mpz_t); +void mpz_gcdext (mpz_t, mpz_t, mpz_t, const mpz_t, const mpz_t); +void mpz_lcm_ui (mpz_t, const mpz_t, unsigned long); +void mpz_lcm (mpz_t, const mpz_t, const mpz_t); +int mpz_invert (mpz_t, const mpz_t, const mpz_t); + +void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t); +void mpz_sqrt (mpz_t, const mpz_t); +int mpz_perfect_square_p (const mpz_t); + +void mpz_pow_ui (mpz_t, const mpz_t, unsigned long); +void mpz_ui_pow_ui (mpz_t, unsigned long, unsigned long); +void mpz_powm (mpz_t, const mpz_t, const mpz_t, const mpz_t); +void mpz_powm_ui (mpz_t, const mpz_t, unsigned long, const mpz_t); + +void mpz_rootrem (mpz_t, mpz_t, const mpz_t, unsigned long); +int mpz_root (mpz_t, const mpz_t, unsigned long); + +void mpz_fac_ui (mpz_t, unsigned long); +void mpz_2fac_ui (mpz_t, unsigned long); +void mpz_mfac_uiui (mpz_t, unsigned long, unsigned long); +void mpz_bin_uiui (mpz_t, unsigned long, unsigned long); + +int mpz_probab_prime_p (const mpz_t, int); + +int mpz_tstbit (const mpz_t, mp_bitcnt_t); +void mpz_setbit (mpz_t, mp_bitcnt_t); +void mpz_clrbit (mpz_t, mp_bitcnt_t); +void mpz_combit (mpz_t, mp_bitcnt_t); + +void mpz_com (mpz_t, const mpz_t); +void mpz_and (mpz_t, const mpz_t, const mpz_t); +void mpz_ior (mpz_t, const mpz_t, const mpz_t); +void mpz_xor (mpz_t, const mpz_t, const mpz_t); + +mp_bitcnt_t mpz_popcount (const mpz_t); +mp_bitcnt_t mpz_hamdist (const mpz_t, const mpz_t); +mp_bitcnt_t mpz_scan0 (const mpz_t, mp_bitcnt_t); +mp_bitcnt_t mpz_scan1 (const mpz_t, mp_bitcnt_t); + +int mpz_fits_slong_p (const mpz_t); +int mpz_fits_ulong_p (const mpz_t); +int mpz_fits_sint_p (const mpz_t); +int mpz_fits_uint_p (const mpz_t); +int mpz_fits_sshort_p (const mpz_t); +int mpz_fits_ushort_p (const mpz_t); +long int mpz_get_si (const mpz_t); +unsigned long int mpz_get_ui (const mpz_t); +double mpz_get_d (const mpz_t); +size_t mpz_size (const mpz_t); +mp_limb_t mpz_getlimbn (const mpz_t, mp_size_t); + +void mpz_realloc2 (mpz_t, mp_bitcnt_t); +mp_srcptr mpz_limbs_read (mpz_srcptr); +mp_ptr mpz_limbs_modify (mpz_t, mp_size_t); +mp_ptr mpz_limbs_write (mpz_t, mp_size_t); +void mpz_limbs_finish (mpz_t, mp_size_t); +mpz_srcptr mpz_roinit_n (mpz_t, mp_srcptr, mp_size_t); + +#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }} + +void mpz_set_si (mpz_t, signed long int); +void mpz_set_ui (mpz_t, unsigned long int); +void mpz_set (mpz_t, const mpz_t); +void mpz_set_d (mpz_t, double); + +void mpz_init_set_si (mpz_t, signed long int); +void mpz_init_set_ui (mpz_t, unsigned long int); +void mpz_init_set (mpz_t, const mpz_t); +void mpz_init_set_d (mpz_t, double); + +size_t mpz_sizeinbase (const mpz_t, int); +char *mpz_get_str (char *, int, const mpz_t); +int mpz_set_str (mpz_t, const char *, int); +int mpz_init_set_str (mpz_t, const char *, int); + +/* This long list taken from gmp.h. */ +/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4, + defines EOF but not FILE. */ +#if defined (FILE) \ + || defined (H_STDIO) \ + || defined (_H_STDIO) /* AIX */ \ + || defined (_STDIO_H) /* glibc, Sun, SCO */ \ + || defined (_STDIO_H_) /* BSD, OSF */ \ + || defined (__STDIO_H) /* Borland */ \ + || defined (__STDIO_H__) /* IRIX */ \ + || defined (_STDIO_INCLUDED) /* HPUX */ \ + || defined (__dj_include_stdio_h_) /* DJGPP */ \ + || defined (_FILE_DEFINED) /* Microsoft */ \ + || defined (__STDIO__) /* Apple MPW MrC */ \ + || defined (_MSL_STDIO_H) /* Metrowerks */ \ + || defined (_STDIO_H_INCLUDED) /* QNX4 */ \ + || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ \ + || defined (__STDIO_LOADED) /* VMS */ \ + || defined (_STDIO) /* HPE NonStop */ \ + || defined (__DEFINED_FILE) /* musl */ +size_t mpz_out_str (FILE *, int, const mpz_t); +#endif + +void mpz_import (mpz_t, size_t, int, size_t, int, size_t, const void *); +void *mpz_export (void *, size_t *, int, size_t, int, size_t, const mpz_t); + +#if defined (__cplusplus) +} +#endif +#endif /* __MINI_GMP_H__ */ diff --git a/gmp-6.3.0/mini-gmp/mini-mpq.c b/gmp-6.3.0/mini-gmp/mini-mpq.c new file mode 100644 index 0000000..58ce37f --- /dev/null +++ b/gmp-6.3.0/mini-gmp/mini-mpq.c @@ -0,0 +1,556 @@ +/* mini-mpq, a minimalistic implementation of a GNU GMP subset. + + Contributed to the GNU project by Marco Bodrato + + Acknowledgment: special thanks to Bradley Lucier for his comments + to the preliminary version of this code. + +Copyright 2018-2022 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 +#include +#include +#include +#include + +#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_LIMB_MAX ((mp_limb_t) ~ (mp_limb_t) 0) +#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_nn (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_zz (mpq_t x, mpz_srcptr n, mpz_srcptr d) +{ + return mpq_roinit_normal_nn (x, n->_mp_d, n->_mp_size, + d->_mp_d, d->_mp_size); +} + +static void +mpq_nan_init (mpq_t x) +{ + mpz_init (mpq_numref (x)); + mpz_init (mpq_denref (x)); +} + +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) +{ + mp_size_t ds = mpq_denref (r)->_mp_size; + if (ds <= 0) + { + if (ds == 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 mpz_t num, const mpz_t den) +{ + if (num->_mp_size == 0) + mpq_set_ui (r, 0, 1); + else + { + mpz_t g; + + mpz_init (g); + mpz_gcd (g, num, den); + mpz_tdiv_q (mpq_numref (r), num, g); + mpz_tdiv_q (mpq_denref (r), den, g); + mpz_clear (g); + mpq_canonical_sign (r); + } +} + +void +mpq_canonicalize (mpq_t r) +{ + mpq_helper_canonicalize (r, mpq_numref (r), mpq_denref (r)); +} + +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) +{ + 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) +{ + 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) +{ + 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); + if (ULONG_MAX <= GMP_LIMB_MAX) { + mp_limb_t nl = n, dl = d; + return mpq_cmp (q, mpq_roinit_normal_nn (t, &nl, n != 0, &dl, 1)); + } else { + int ret; + + mpq_nan_init (t); + mpq_set_ui (t, n, d); + ret = mpq_cmp (q, t); + mpq_clear (t); + + return ret; + } +} + +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; + + if (ULONG_MAX <= GMP_LIMB_MAX) + { + mp_limb_t nl = GMP_NEG_CAST (unsigned long, n), dl = d; + return mpq_cmp (q, mpq_roinit_normal_nn (t, &nl, -1, &dl, 1)); + } + else + { + unsigned long l_n = GMP_NEG_CAST (unsigned long, n); + + mpq_roinit_normal_nn (t, mpq_numref (q)->_mp_d, - mpq_numref (q)->_mp_size, + mpq_denref (q)->_mp_d, mpq_denref (q)->_mp_size); + return - mpq_cmp_ui (t, l_n, d); + } + } +} + +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_nn (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_zz (t, mpq_denref (b), mpq_numref (b))); +} + +void +mpq_mul (mpq_t r, const mpq_t a, const mpq_t b) +{ + mpq_t t; + mpq_nan_init (t); + + if (a != b) { + mpq_helper_canonicalize (t, mpq_numref (a), mpq_denref (b)); + mpq_helper_canonicalize (r, mpq_numref (b), mpq_denref (a)); + + a = r; + b = t; + } + + mpz_mul (mpq_numref (r), mpq_numref (a), mpq_numref (b)); + mpz_mul (mpq_denref (r), mpq_denref (a), mpq_denref (b)); + mpq_clear (t); +} + +static void +mpq_helper_2exp (mpz_t rn, mpz_t rd, const mpz_t qn, const mpz_t qd, mp_bitcnt_t e) +{ + mp_bitcnt_t z = mpz_scan1 (qd, 0); + z = GMP_MIN (z, e); + mpz_mul_2exp (rn, qn, e - z); + mpz_tdiv_q_2exp (rd, qd, z); +} + +void +mpq_div_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e) +{ + mpq_helper_2exp (mpq_denref (r), mpq_numref (r), mpq_denref (q), mpq_numref (q), e); +} + +void +mpq_mul_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e) +{ + mpq_helper_2exp (mpq_numref (r), mpq_denref (r), mpq_numref (q), mpq_denref (q), e); +} + +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); +} + + +/* MPQ to/from double. */ +void +mpq_set_d (mpq_t r, double x) +{ + mpz_set_ui (mpq_denref (r), 1); + + /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is + zero or infinity. */ + if (x == x * 0.5 || x != x) + mpq_numref (r)->_mp_size = 0; + else + { + double B; + mp_bitcnt_t e; + + B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1); + for (e = 0; x != x + 0.5; e += GMP_LIMB_BITS) + x *= B; + + mpz_set_d (mpq_numref (r), x); + mpq_div_2exp (r, r, e); + } +} + +double +mpq_get_d (const mpq_t u) +{ + mp_bitcnt_t ne, de, ee; + mpz_t z; + double B, ret; + + ne = mpz_sizeinbase (mpq_numref (u), 2); + de = mpz_sizeinbase (mpq_denref (u), 2); + + ee = CHAR_BIT * sizeof (double); + if (de == 1 || ne > de + ee) + ee = 0; + else + ee = (ee + de - ne) / GMP_LIMB_BITS + 1; + + mpz_init (z); + mpz_mul_2exp (z, mpq_numref (u), ee * GMP_LIMB_BITS); + mpz_tdiv_q (z, z, mpq_denref (u)); + ret = mpz_get_d (z); + mpz_clear (z); + + B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1); + for (B = 1 / B; ee != 0; --ee) + ret *= B; + + return ret; +} + + +/* MPQ and strings/streams. */ +char * +mpq_get_str (char *sp, int base, const mpq_t q) +{ + char *res; + char *rden; + size_t len; + + res = mpz_get_str (sp, base, mpq_numref (q)); + if (res == NULL || mpz_cmp_ui (mpq_denref (q), 1) == 0) + return res; + + len = strlen (res) + 1; + rden = sp ? sp + len : NULL; + rden = mpz_get_str (rden, base, mpq_denref (q)); + assert (rden != NULL); + + if (sp == NULL) { + void * (*gmp_reallocate_func) (void *, size_t, size_t); + void (*gmp_free_func) (void *, size_t); + size_t lden; + + mp_get_memory_functions (NULL, &gmp_reallocate_func, &gmp_free_func); + lden = strlen (rden) + 1; + res = (char *) gmp_reallocate_func (res, len, (lden + len) * sizeof (char)); + memcpy (res + len, rden, lden); + gmp_free_func (rden, lden); + } + + res [len - 1] = '/'; + return res; +} + +size_t +mpq_out_str (FILE *stream, int base, const mpq_t x) +{ + char * str; + size_t len, n; + void (*gmp_free_func) (void *, size_t); + + str = mpq_get_str (NULL, base, x); + if (!str) + return 0; + len = strlen (str); + n = fwrite (str, 1, len, stream); + mp_get_memory_functions (NULL, NULL, &gmp_free_func); + gmp_free_func (str, len + 1); + return n; +} + +int +mpq_set_str (mpq_t r, const char *sp, int base) +{ + const char *slash; + + slash = strchr (sp, '/'); + if (slash == NULL) { + mpz_set_ui (mpq_denref(r), 1); + return mpz_set_str (mpq_numref(r), sp, base); + } else { + char *num; + size_t numlen; + int ret; + void * (*gmp_allocate_func) (size_t); + void (*gmp_free_func) (void *, size_t); + + mp_get_memory_functions (&gmp_allocate_func, NULL, &gmp_free_func); + numlen = slash - sp; + num = (char *) gmp_allocate_func (numlen + 1); + memcpy (num, sp, numlen); + num[numlen] = '\0'; + ret = mpz_set_str (mpq_numref(r), num, base); + gmp_free_func (num, numlen + 1); + + if (ret != 0) + return ret; + + return mpz_set_str (mpq_denref(r), slash + 1, base); + } +} diff --git a/gmp-6.3.0/mini-gmp/mini-mpq.h b/gmp-6.3.0/mini-gmp/mini-mpq.h new file mode 100644 index 0000000..8eabcec --- /dev/null +++ b/gmp-6.3.0/mini-gmp/mini-mpq.h @@ -0,0 +1,114 @@ +/* mini-mpq, a minimalistic implementation of a GNU GMP subset. + +Copyright 2018, 2019 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/. */ + +/* 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); +char * mpq_get_str (char *, int, const mpq_t q); +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); +int mpq_set_str (mpq_t, const char *, int); +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); + +/* This long list taken from gmp.h. */ +/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4, + defines EOF but not FILE. */ +#if defined (FILE) \ + || defined (H_STDIO) \ + || defined (_H_STDIO) /* AIX */ \ + || defined (_STDIO_H) /* glibc, Sun, SCO */ \ + || defined (_STDIO_H_) /* BSD, OSF */ \ + || defined (__STDIO_H) /* Borland */ \ + || defined (__STDIO_H__) /* IRIX */ \ + || defined (_STDIO_INCLUDED) /* HPUX */ \ + || defined (__dj_include_stdio_h_) /* DJGPP */ \ + || defined (_FILE_DEFINED) /* Microsoft */ \ + || defined (__STDIO__) /* Apple MPW MrC */ \ + || defined (_MSL_STDIO_H) /* Metrowerks */ \ + || defined (_STDIO_H_INCLUDED) /* QNX4 */ \ + || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ \ + || defined (__STDIO_LOADED) /* VMS */ +size_t mpq_out_str (FILE *, int, const mpq_t); +#endif + +void mpz_set_q (mpz_t, const mpq_t); + +#if defined (__cplusplus) +} +#endif +#endif /* __MINI_MPQ_H__ */ diff --git a/gmp-6.3.0/mini-gmp/tests/Makefile b/gmp-6.3.0/mini-gmp/tests/Makefile new file mode 100644 index 0000000..7cc4485 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/Makefile @@ -0,0 +1,65 @@ +# Note: Requires GNU make + +# Copyright 2011, 2012, 2014, 2016, 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/. + +srcdir=. +MINI_GMP_DIR=.. + +CC = gcc +CFLAGS = -O -Wall -g +CPPFLAGS = +LDFLAGS = + +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-lucm \ + t-mpq_addsub t-mpq_muldiv t-mpq_muldiv_2exp t-mpq_str \ + t-mpq_double +# Default TESTS to all tests, allowing overriding TESTS for building tests +# without running them. +TESTS = $(CHECK_PROGRAMS) + +MISC_OBJS = hex-random.o mini-random.o testutils.o + +all: + +clean: + rm -f *.o $(CHECK_PROGRAMS) + +%: %.c +.c: + +# Keep object files +.PRECIOUS: %.o + +%.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 $(MINI_GMP_DIR)/mini-mpq.c + +%: %.o $(MISC_OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ + +# Missing tests include: +# mpz_cmp_d, mpz_popcount, mpz_hamdist, mpz_ui_pow_ui + +check: $(CHECK_PROGRAMS) + $(srcdir)/run-tests $(TESTS) diff --git a/gmp-6.3.0/mini-gmp/tests/hex-random.c b/gmp-6.3.0/mini-gmp/tests/hex-random.c new file mode 100644 index 0000000..a5b405b --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/hex-random.c @@ -0,0 +1,573 @@ +/* + +Copyright 2011, 2016, 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 +#include + +#include + +#ifdef __unix__ +# include +# include +#endif + +#include "gmp.h" + +#include "hex-random.h" + +/* FIXME: gmp-impl.h included only for mpz_lucas_mod */ +/* #include "gmp-impl.h" */ +#if defined (__cplusplus) +extern "C" { +#endif + +#define mpz_lucas_mod __gmpz_lucas_mod +__GMP_DECLSPEC int mpz_lucas_mod (mpz_ptr, mpz_ptr, long, mp_bitcnt_t, mpz_srcptr, mpz_ptr, mpz_ptr); + +#if defined (__cplusplus) +} +#endif + +static gmp_randstate_t state; + +static void +mkseed (mpz_t seed) +{ + FILE *f = fopen ("/dev/urandom", "rb"); + if (f) + { + unsigned char buf[6]; + size_t res; + + setbuf (f, NULL); + res = fread (buf, sizeof(buf), 1, f); + fclose (f); + + if (res == 1) + { + mpz_import (seed, sizeof(buf), 1, 1, 0, 0, buf); + return; + } + } + +#ifdef __unix__ + { + struct timeval tv; + mpz_t usec; + mpz_init (usec); + + gettimeofday (&tv, NULL); + mpz_set_ui (seed, tv.tv_sec); + mpz_set_ui (usec, tv.tv_usec); + /* usec fits in 20 bits, shift left to make it 48 bits. */ + mpz_mul_2exp (usec, usec, 28); + mpz_xor (seed, seed, usec); + + mpz_clear (usec); + } +#else + mpz_set_ui (seed, time (NULL)); +#endif +} + +void +hex_random_init (void) +{ + mpz_t seed; + char *env_seed; + + mpz_init (seed); + + env_seed = getenv ("GMP_CHECK_RANDOMIZE"); + if (env_seed && env_seed[0]) + { + mpz_set_str (seed, env_seed, 0); + if (mpz_cmp_ui (seed, 0) != 0) + gmp_printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%Zd\n", seed); + else + { + mkseed (seed); + gmp_printf ("Seed GMP_CHECK_RANDOMIZE=%Zd (include this in bug reports)\n", seed); + } + fflush (stdout); + } + else + mpz_set_ui (seed, 4711); + + gmp_randinit_default (state); + gmp_randseed (state, seed); + + mpz_clear (seed); +} + +char * +hex_urandomb (unsigned long bits) +{ + char *res; + mpz_t x; + + mpz_init (x); + mpz_urandomb (x, state, bits); + gmp_asprintf (&res, "%Zx", x); + mpz_clear (x); + return res; +} + +char * +hex_rrandomb (unsigned long bits) +{ + char *res; + mpz_t x; + + mpz_init (x); + mpz_rrandomb (x, state, bits); + gmp_asprintf (&res, "%Zx", x); + mpz_clear (x); + return res; +} + +char * +hex_rrandomb_export (void *dst, size_t *countp, + int order, size_t size, int endian, unsigned long bits) +{ + char *res; + mpz_t x; + mpz_init (x); + mpz_rrandomb (x, state, bits); + gmp_asprintf (&res, "%Zx", x); + mpz_export (dst, countp, order, size, endian, 0, x); + mpz_clear (x); + return res; +} + +void hex_random_op2 (enum hex_random_op op, unsigned long maxbits, + char **ap, char **rp) +{ + mpz_t a, r; + unsigned long abits; + unsigned signs; + + mpz_init (a); + mpz_init (r); + + abits = gmp_urandomb_ui (state, 32) % maxbits; + + mpz_rrandomb (a, state, abits); + + signs = gmp_urandomb_ui (state, 1); + if (signs & 1) + mpz_neg (a, a); + + switch (op) + { + default: + abort (); + case OP_SQR: + mpz_mul (r, a, a); + break; + } + + gmp_asprintf (ap, "%Zx", a); + gmp_asprintf (rp, "%Zx", r); + + mpz_clear (a); + mpz_clear (r); +} + +void +hex_random_op3 (enum hex_random_op op, unsigned long maxbits, + char **ap, char **bp, char **rp) +{ + mpz_t a, b, r; + unsigned long abits, bbits; + unsigned signs; + + mpz_init (a); + mpz_init (b); + mpz_init (r); + + abits = gmp_urandomb_ui (state, 32) % maxbits; + bbits = gmp_urandomb_ui (state, 32) % maxbits; + + mpz_rrandomb (a, state, abits); + mpz_rrandomb (b, state, bbits); + + signs = gmp_urandomb_ui (state, 3); + if (signs & 1) + mpz_neg (a, a); + if (signs & 2) + mpz_neg (b, b); + + switch (op) + { + default: + abort (); + case OP_ADD: + mpz_add (r, a, b); + break; + case OP_SUB: + mpz_sub (r, a, b); + break; + case OP_MUL: + mpz_mul (r, a, b); + break; + case OP_GCD: + if (signs & 4) + { + /* Produce a large gcd */ + unsigned long gbits = gmp_urandomb_ui (state, 32) % maxbits; + mpz_rrandomb (r, state, gbits); + mpz_mul (a, a, r); + mpz_mul (b, b, r); + } + mpz_gcd (r, a, b); + break; + case OP_LCM: + if (signs & 4) + { + /* Produce a large gcd */ + unsigned long gbits = gmp_urandomb_ui (state, 32) % maxbits; + mpz_rrandomb (r, state, gbits); + mpz_mul (a, a, r); + mpz_mul (b, b, r); + } + mpz_lcm (r, a, b); + break; + case OP_AND: + mpz_and (r, a, b); + break; + case OP_IOR: + mpz_ior (r, a, b); + break; + case OP_XOR: + mpz_xor (r, a, b); + break; + } + + gmp_asprintf (ap, "%Zx", a); + gmp_asprintf (bp, "%Zx", b); + gmp_asprintf (rp, "%Zx", r); + + mpz_clear (a); + mpz_clear (b); + mpz_clear (r); +} + +void +hex_random_op4 (enum hex_random_op op, unsigned long maxbits, + char **ap, char **bp, char **cp, char **dp) +{ + mpz_t a, b, c, d; + unsigned long abits, bbits; + unsigned signs; + + mpz_init (a); + mpz_init (b); + mpz_init (c); + mpz_init (d); + + if (op == OP_POWM) + { + unsigned long cbits; + abits = gmp_urandomb_ui (state, 32) % maxbits; + bbits = 1 + gmp_urandomb_ui (state, 32) % maxbits; + cbits = 2 + gmp_urandomb_ui (state, 32) % maxbits; + + mpz_rrandomb (a, state, abits); + mpz_rrandomb (b, state, bbits); + mpz_rrandomb (c, state, cbits); + + signs = gmp_urandomb_ui (state, 3); + if (signs & 1) + mpz_neg (a, a); + if (signs & 2) + { + mpz_t g; + + /* If we negate the exponent, must make sure that gcd(a, c) = 1 */ + if (mpz_sgn (a) == 0) + mpz_set_ui (a, 1); + else + { + mpz_init (g); + + for (;;) + { + mpz_gcd (g, a, c); + if (mpz_cmp_ui (g, 1) == 0) + break; + mpz_divexact (a, a, g); + } + mpz_clear (g); + } + mpz_neg (b, b); + } + if (signs & 4) + mpz_neg (c, c); + + mpz_powm (d, a, b, c); + } + else + { + unsigned long qbits; + bbits = 1 + gmp_urandomb_ui (state, 32) % maxbits; + qbits = gmp_urandomb_ui (state, 32) % maxbits; + abits = bbits + qbits; + if (abits > 30) + abits -= 30; + else + abits = 0; + + mpz_rrandomb (a, state, abits); + mpz_rrandomb (b, state, bbits); + + signs = gmp_urandomb_ui (state, 2); + if (signs & 1) + mpz_neg (a, a); + if (signs & 2) + mpz_neg (b, b); + + switch (op) + { + default: + abort (); + case OP_CDIV: + mpz_cdiv_qr (c, d, a, b); + break; + case OP_FDIV: + mpz_fdiv_qr (c, d, a, b); + break; + case OP_TDIV: + mpz_tdiv_qr (c, d, a, b); + break; + } + } + gmp_asprintf (ap, "%Zx", a); + gmp_asprintf (bp, "%Zx", b); + gmp_asprintf (cp, "%Zx", c); + gmp_asprintf (dp, "%Zx", d); + + mpz_clear (a); + mpz_clear (b); + mpz_clear (c); + mpz_clear (d); +} + +void +hex_random_bit_op (enum hex_random_op op, unsigned long maxbits, + char **ap, unsigned long *b, char **rp) +{ + mpz_t a, r; + unsigned long abits, bbits; + unsigned signs; + + mpz_init (a); + mpz_init (r); + + abits = gmp_urandomb_ui (state, 32) % maxbits; + bbits = gmp_urandomb_ui (state, 32) % (maxbits + 100); + + mpz_rrandomb (a, state, abits); + + signs = gmp_urandomb_ui (state, 1); + if (signs & 1) + mpz_neg (a, a); + + switch (op) + { + default: + abort (); + + case OP_SETBIT: + mpz_set (r, a); + mpz_setbit (r, bbits); + break; + case OP_CLRBIT: + mpz_set (r, a); + mpz_clrbit (r, bbits); + break; + case OP_COMBIT: + mpz_set (r, a); + mpz_combit (r, bbits); + break; + case OP_CDIV_Q_2: + mpz_cdiv_q_2exp (r, a, bbits); + break; + case OP_CDIV_R_2: + mpz_cdiv_r_2exp (r, a, bbits); + break; + case OP_FDIV_Q_2: + mpz_fdiv_q_2exp (r, a, bbits); + break; + case OP_FDIV_R_2: + mpz_fdiv_r_2exp (r, a, bbits); + break; + case OP_TDIV_Q_2: + mpz_tdiv_q_2exp (r, a, bbits); + break; + case OP_TDIV_R_2: + mpz_tdiv_r_2exp (r, a, bbits); + break; + } + + gmp_asprintf (ap, "%Zx", a); + *b = bbits; + gmp_asprintf (rp, "%Zx", r); + + mpz_clear (a); + mpz_clear (r); +} + +void +hex_random_scan_op (enum hex_random_op op, unsigned long maxbits, + char **ap, unsigned long *b, unsigned long *r) +{ + mpz_t a; + unsigned long abits, bbits; + unsigned signs; + + mpz_init (a); + + abits = gmp_urandomb_ui (state, 32) % maxbits; + bbits = gmp_urandomb_ui (state, 32) % (maxbits + 100); + + mpz_rrandomb (a, state, abits); + + signs = gmp_urandomb_ui (state, 1); + if (signs & 1) + mpz_neg (a, a); + + switch (op) + { + default: + abort (); + + case OP_SCAN0: + *r = mpz_scan0 (a, bbits); + break; + case OP_SCAN1: + *r = mpz_scan1 (a, bbits); + break; + } + gmp_asprintf (ap, "%Zx", a); + *b = bbits; + + mpz_clear (a); +} + +void +hex_random_str_op (unsigned long maxbits, + int base, char **ap, char **rp) +{ + mpz_t a; + unsigned long abits; + unsigned signs; + + mpz_init (a); + + abits = gmp_urandomb_ui (state, 32) % maxbits; + + mpz_rrandomb (a, state, abits); + + signs = gmp_urandomb_ui (state, 2); + if (signs & 1) + mpz_neg (a, a); + + *ap = mpz_get_str (NULL, 16, a); + *rp = mpz_get_str (NULL, base, a); + + mpz_clear (a); +} + +void hex_random_lucm_op (unsigned long maxbits, + char **vp, char **qp, char **mp, + long *Q, unsigned long *b0, int *res) +{ + mpz_t m, v, q, t1, t2; + unsigned long mbits; + + mpz_init (m); + mpz_init (v); + mpz_init (q); + mpz_init (t1); + mpz_init (t2); + + *Q = gmp_urandomb_ui (state, 14) + 1; + + do + { + mbits = gmp_urandomb_ui (state, 32) % maxbits + 5; + + mpz_rrandomb (m, state, mbits); + *b0 = gmp_urandomb_ui (state, 32) % (mbits - 3) + 2; + /* The GMP implementation uses the exponent (m >> b0) + 1. */ + /* mini-gmp implementation uses the exponent (m >> b0) | 1. */ + /* They are the same (and are used) only when (m >> b0) is even */ + mpz_clrbit (m, *b0); + /* mini-gmp implementation only works if the modulus is odd. */ + mpz_setbit (m, 0); + } + while (mpz_gcd_ui (NULL, m, *Q) != 1); + + if (*Q == 1 || gmp_urandomb_ui (state, 1)) + *Q = - *Q; + +#if (__GNU_MP_VERSION == 6 && (__GNU_MP_VERSION_MINOR > 1 || __GNU_MP_VERSION_PATCHLEVEL > 9)) + *res = mpz_lucas_mod (v, q, *Q, *b0, m, t1, t2); +#else + *b0 = 0; +#endif + + gmp_asprintf (vp, "%Zx", v); + gmp_asprintf (qp, "%Zx", q); + gmp_asprintf (mp, "%Zx", m); + + mpz_clear (m); + mpz_clear (v); + mpz_clear (q); + mpz_clear (t1); + mpz_clear (t2); +} + +void +hex_mpq_random_str_op (unsigned long maxbits, + int base, char **ap, char **rp) +{ + mpq_t a; + unsigned long abits; + unsigned signs; + + mpq_init (a); + + abits = gmp_urandomb_ui (state, 32) % maxbits; + + mpz_rrandomb (mpq_numref (a), state, abits); + mpz_rrandomb (mpq_denref (a), state, abits); + mpz_add_ui (mpq_denref (a), mpq_denref (a), 1); + + mpq_canonicalize (a); + signs = gmp_urandomb_ui (state, 2); + if (signs & 1) + mpq_neg (a, a); + + *ap = mpq_get_str (NULL, 16, a); + *rp = mpq_get_str (NULL, base, a); + + mpq_clear (a); +} diff --git a/gmp-6.3.0/mini-gmp/tests/hex-random.h b/gmp-6.3.0/mini-gmp/tests/hex-random.h new file mode 100644 index 0000000..da44347 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/hex-random.h @@ -0,0 +1,55 @@ +/* + +Copyright 2011, 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/. */ + +enum hex_random_op + { + OP_ADD, OP_SUB, OP_MUL, OP_SQR, + OP_CDIV, OP_FDIV, OP_TDIV, + OP_CDIV_Q_2, OP_CDIV_R_2, + OP_FDIV_Q_2, OP_FDIV_R_2, + OP_TDIV_Q_2, OP_TDIV_R_2, + OP_GCD, OP_LCM, OP_POWM, OP_AND, OP_IOR, OP_XOR, + OP_SETBIT, OP_CLRBIT, OP_COMBIT, + OP_SCAN0, OP_SCAN1, + }; + +void hex_random_init (void); +char *hex_urandomb (unsigned long bits); +char *hex_rrandomb (unsigned long bits); +char *hex_rrandomb_export (void *dst, size_t *countp, + int order, size_t size, int endian, + unsigned long bits); + +void hex_random_op2 (enum hex_random_op op, unsigned long maxbits, + char **ap, char **rp); +void hex_random_op3 (enum hex_random_op op, unsigned long maxbits, + char **ap, char **bp, char **rp); +void hex_random_op4 (enum hex_random_op op, unsigned long maxbits, + char **ap, char **bp, char **rp, char **qp); +void hex_random_bit_op (enum hex_random_op op, unsigned long maxbits, + char **ap, unsigned long *b, char **rp); +void hex_random_scan_op (enum hex_random_op op, unsigned long maxbits, + char **ap, unsigned long *b, unsigned long *r); +void hex_random_str_op (unsigned long maxbits, + int base, char **ap, char **rp); +void hex_random_lucm_op (unsigned long maxbits, + char **vp, char **qp, char **mp, + long *Q, unsigned long *b0, int *res); +void hex_mpq_random_str_op (unsigned long maxbits, + int base, char **ap, char **rp); diff --git a/gmp-6.3.0/mini-gmp/tests/mini-random.c b/gmp-6.3.0/mini-gmp/tests/mini-random.c new file mode 100644 index 0000000..7504af3 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/mini-random.c @@ -0,0 +1,160 @@ +/* + +Copyright 2011, 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 +#include + +#include "mini-random.h" + +static void +set_str (mpz_t r, const char *s) +{ + if (mpz_set_str (r, s, 16) != 0) + { + fprintf (stderr, "mpz_set_str failed on input %s\n", s); + abort (); + } +} + +void +mini_urandomb (mpz_t r, unsigned long bits) +{ + char *s; + s = hex_urandomb (bits); + set_str (r, s); + free (s); +} + +void +mini_rrandomb (mpz_t r, unsigned long bits) +{ + char *s; + s = hex_rrandomb (bits); + set_str (r, s); + free (s); +} + +void +mini_rrandomb_export (mpz_t r, void *dst, size_t *countp, + int order, size_t size, int endian, unsigned long bits) +{ + char *s; + s = hex_rrandomb_export (dst, countp, order, size, endian, bits); + set_str (r, s); + free (s); +} + +void +mini_random_op2 (enum hex_random_op op, unsigned long maxbits, + mpz_t a, mpz_t r) +{ + char *ap; + char *rp; + + hex_random_op2 (op, maxbits, &ap, &rp); + set_str (a, ap); + set_str (r, rp); + + free (ap); + free (rp); +} + +void +mini_random_op3 (enum hex_random_op op, unsigned long maxbits, + mpz_t a, mpz_t b, mpz_t r) +{ + char *ap; + char *bp; + char *rp; + + hex_random_op3 (op, maxbits, &ap, &bp, &rp); + set_str (a, ap); + set_str (b, bp); + set_str (r, rp); + + free (ap); + free (bp); + free (rp); +} + +void +mini_random_op4 (enum hex_random_op op, unsigned long maxbits, + mpz_t a, mpz_t b, mpz_t c, mpz_t d) +{ + char *ap; + char *bp; + char *cp; + char *dp; + + hex_random_op4 (op, maxbits, &ap, &bp, &cp, &dp); + set_str (a, ap); + set_str (b, bp); + set_str (c, cp); + set_str (d, dp); + + free (ap); + free (bp); + free (cp); + free (dp); +} + +void +mini_random_bit_op (enum hex_random_op op, unsigned long maxbits, + mpz_t a, mp_bitcnt_t *b, mpz_t r) +{ + char *ap; + char *rp; + + hex_random_bit_op (op, maxbits, &ap, b, &rp); + set_str (a, ap); + set_str (r, rp); + + free (ap); + free (rp); +} + +void +mini_random_scan_op (enum hex_random_op op, unsigned long maxbits, + mpz_t a, mp_bitcnt_t *b, mp_bitcnt_t *r) +{ + char *ap; + + hex_random_scan_op (op, maxbits, &ap, b, r); + set_str (a, ap); + + free (ap); +} + +void +mini_random_lucm_op (unsigned long maxbits, mpz_t v, mpz_t q, mpz_t m, + long *Q, unsigned long *b0, int *res) +{ + char *vp; + char *qp; + char *mp; + + hex_random_lucm_op (maxbits, &vp, &qp, &mp, Q, b0, res); + set_str (v, vp); + set_str (q, qp); + set_str (m, mp); + + free (vp); + free (qp); + free (mp); +} diff --git a/gmp-6.3.0/mini-gmp/tests/mini-random.h b/gmp-6.3.0/mini-gmp/tests/mini-random.h new file mode 100644 index 0000000..2f54749 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/mini-random.h @@ -0,0 +1,35 @@ +/* + +Copyright 2011, 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 "../mini-gmp.h" +#include "hex-random.h" + +void mini_urandomb (mpz_t, unsigned long); +void mini_rrandomb (mpz_t, unsigned long); +void mini_rrandomb_export (mpz_t r, void *dst, size_t *countp, + int order, size_t size, int endian, + unsigned long bits); + +void mini_random_op2 (enum hex_random_op, unsigned long, mpz_t, mpz_t); +void mini_random_op3 (enum hex_random_op, unsigned long, mpz_t, mpz_t, mpz_t); +void mini_random_op4 (enum hex_random_op, unsigned long, mpz_t, mpz_t, mpz_t, mpz_t); +void mini_random_scan_op (enum hex_random_op, unsigned long, mpz_t, mp_bitcnt_t *, mp_bitcnt_t *); +void mini_random_bit_op (enum hex_random_op, unsigned long, mpz_t, mp_bitcnt_t *, mpz_t); +void mini_random_lucm_op (unsigned long, mpz_t, mpz_t, mpz_t, + long *, unsigned long *, int *); diff --git a/gmp-6.3.0/mini-gmp/tests/run-tests b/gmp-6.3.0/mini-gmp/tests/run-tests new file mode 100755 index 0000000..3ebc4ae --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/run-tests @@ -0,0 +1,143 @@ +#! /bin/sh + +# Copyright (C) 2000-2002, 2004, 2005, 2011, 2012, 2016, 2020 Niels Möller +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +failed=0 +all=0 + +debug='no' +testflags='' + +if [ -z "$srcdir" ] ; then + srcdir=`pwd` +fi + +export srcdir + +if [ -n "$TEST_SHLIB_DIR" ] ; then + # Prepend to LD_LIBRARY_PATH, if it is alredy set. + LD_LIBRARY_PATH="${TEST_SHLIB_DIR}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" + # For MACOS + DYLD_LIBRARY_PATH="$TEST_SHLIB_DIR" + # For Windows + PATH="${TEST_SHLIB_DIR}:${PATH}" + # For Wine + WINEPATH="${TEST_SHLIB_DIR}${WINEPATH:+;$WINEPATH}" + + export LD_LIBRARY_PATH + export DYLD_LIBRARY_PATH + export PATH + export WINEPATH +fi + +# When used in make rules, we sometimes get the filenames VPATH +# expanded, but usually not. +find_program () { + case "$1" in + */*) + echo "$1" + ;; + *) + if [ -x "$1" ] ; then + echo "./$1" + elif [ -x "$1.exe" ] ; then + echo "./$1.exe" + else + echo "$srcdir/$1" + fi + ;; + esac +} + +env_program () { + if [ -x "$1" ] ; then + if "$1"; then : ; else + echo FAIL: $1 + exit 1 + fi + fi +} + +test_program () { + testname=`basename "$1" .exe` + testname=`basename "$testname" -test` + if [ -z "$EMULATOR" ] || head -1 "$1" | grep '^#!' > /dev/null; then + "$1" $testflags + else + $EMULATOR "$1" $testflags + fi + case "$?" in + 0) + echo PASS: $testname + all=`expr $all + 1` + ;; + 77) + echo SKIP: $testname + ;; + *) + echo FAIL: $testname + failed=`expr $failed + 1` + all=`expr $all + 1` + ;; + esac +} + +env_program `find_program setup-env` + +while test $# != 0 +do + case "$1" in + --debug) + debug=yes + ;; + -v) + testflags='-v' + ;; + -*) + echo >&2 'Unknown option `'"$1'" + exit 1 + ;; + *) + break + ;; + esac + shift +done + +# Comment out special handling for zero arguments to support separate +# tests-build/tests-run. +#if [ $# -eq 0 ] ; then +# for f in *-test; do test_program "./$f"; done +#else + for f in "$@" ; do test_program `find_program "$f"`; done +#fi + +if [ $failed -eq 0 ] ; then + banner="All $all tests passed" +else + banner="$failed of $all tests failed" +fi +dashes=`echo "$banner" | sed s/./=/g` +echo "$dashes" +echo "$banner" +echo "$dashes" + +if [ "x$debug" = xno ] ; then + env_program `find_program teardown-env` +fi + +[ "$failed" -eq 0 ] diff --git a/gmp-6.3.0/mini-gmp/tests/t-add.c b/gmp-6.3.0/mini-gmp/tests/t-add.c new file mode 100644 index 0000000..0a093ef --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-add.c @@ -0,0 +1,57 @@ +/* + +Copyright 2012, 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 +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, b, res, ref; + + mpz_init (a); + mpz_init (b); + mpz_init (res); + mpz_init (ref); + + for (i = 0; i < COUNT; i++) + { + mini_random_op3 (OP_ADD, MAXBITS, a, b, ref); + mpz_add (res, a, b); + if (mpz_cmp (res, ref)) + { + fprintf (stderr, "mpz_add failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + } + mpz_clear (a); + mpz_clear (b); + mpz_clear (res); + mpz_clear (ref); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-aorsmul.c b/gmp-6.3.0/mini-gmp/tests/t-aorsmul.c new file mode 100644 index 0000000..eb275a8 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-aorsmul.c @@ -0,0 +1,77 @@ +/* + +Copyright 2012, 2014, 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 +#include +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT) +#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS) + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, b, res, ref; + + mpz_init (a); + mpz_init (b); + mpz_init_set_ui (res, 5); + mpz_init (ref); + + for (i = 0; i < COUNT; i++) + { + mini_random_op3 (OP_MUL, MAXBITS, a, b, ref); + if (i & 1) { + mpz_add (ref, ref, res); + if (mpz_fits_ulong_p (b)) + mpz_addmul_ui (res, a, mpz_get_ui (b)); + else + mpz_addmul (res, a, b); + } else { + mpz_sub (ref, res, ref); + if (mpz_fits_ulong_p (b)) + mpz_submul_ui (res, a, mpz_get_ui (b)); + else + mpz_submul (res, a, b); + } + if (mpz_cmp (res, ref)) + { + if (i & 1) + fprintf (stderr, "mpz_addmul failed:\n"); + else + fprintf (stderr, "mpz_submul failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + } + mpz_clear (a); + mpz_clear (b); + mpz_clear (res); + mpz_clear (ref); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-bitops.c b/gmp-6.3.0/mini-gmp/tests/t-bitops.c new file mode 100644 index 0000000..27d87ca --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-bitops.c @@ -0,0 +1,104 @@ +/* + +Copyright 2012, 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 +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, res, ref; + mp_bitcnt_t b; + + mpz_init (a); + mpz_init (res); + mpz_init (ref); + + for (i = 0; i < COUNT; i++) + { + mini_random_bit_op (OP_SETBIT, MAXBITS, a, &b, ref); + mpz_set (res, a); + mpz_setbit (res, b); + if (mpz_cmp (res, ref)) + { + fprintf (stderr, "mpz_setbit failed:\n"); + dump ("a", a); + fprintf (stderr, "b: %lu\n", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + if (!mpz_tstbit (res, b)) + { + fprintf (stderr, "mpz_tstbit failed (after mpz_setbit):\n"); + dump ("res", a); + fprintf (stderr, "b: %lu\n", b); + abort (); + } + mini_random_bit_op (OP_CLRBIT, MAXBITS, a, &b, ref); + mpz_set (res, a); + mpz_clrbit (res, b); + if (mpz_cmp (res, ref)) + { + fprintf (stderr, "mpz_clrbit failed:\n"); + dump ("a", a); + fprintf (stderr, "b: %lu\n", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + if (mpz_tstbit (res, b)) + { + fprintf (stderr, "mpz_tstbit failed (after mpz_clrbit):\n"); + dump ("res", a); + fprintf (stderr, "b: %lu\n", b); + abort (); + } + mini_random_bit_op (OP_COMBIT, MAXBITS, a, &b, ref); + mpz_set (res, a); + mpz_com (a, a); + mpz_combit (res, b); + if (mpz_cmp (res, ref)) + { + fprintf (stderr, "mpz_combit failed:\n"); + dump ("a", a); + fprintf (stderr, "b: %lu\n", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + if (mpz_tstbit (res, b) != mpz_tstbit (a, b)) + { + fprintf (stderr, "mpz_tstbit failed (after mpz_combit):\n"); + dump ("res", a); + fprintf (stderr, "b: %lu\n", b); + abort (); + } + } + mpz_clear (a); + mpz_clear (res); + mpz_clear (ref); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-cmp_d.c b/gmp-6.3.0/mini-gmp/tests/t-cmp_d.c new file mode 100644 index 0000000..09ca810 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-cmp_d.c @@ -0,0 +1,283 @@ +/* Test mpz_cmp_d and mpz_cmpabs_d. + +Copyright 2001-2003, 2005, 2013 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 + +#include "testutils.h" + +/* FIXME: Not sure if the tests here are exhaustive. Ought to try to get + each possible exit from mpz_cmp_d (and mpz_cmpabs_d) exercised. */ + + +#define SGN(n) ((n) > 0 ? 1 : (n) < 0 ? -1 : 0) + + +void +check_one (const char *name, mpz_srcptr x, double y, int cmp, int cmpabs) +{ + int got; + + got = mpz_cmp_d (x, y); + if (SGN(got) != cmp) + { + unsigned i; + printf ("mpz_cmp_d wrong (from %s)\n", name); + printf (" got %d\n", got); + printf (" want %d\n", cmp); + fail: + printf (" x="); + mpz_out_str (stdout, 10, x); + printf ("\n y %g\n", y); + printf (" x=0x"); + mpz_out_str (stdout, -16, x); + printf ("\n y %g\n", y); + printf (" y"); + for (i = 0; i < sizeof(y); i++) + printf (" %02X", (unsigned) ((unsigned char *) &y)[i]); + printf ("\n"); + abort (); + } + + got = mpz_cmpabs_d (x, y); + if (SGN(got) != cmpabs) + { + printf ("mpz_cmpabs_d wrong\n"); + printf (" got %d\n", got); + printf (" want %d\n", cmpabs); + goto fail; + } +} + +void +check_data (void) +{ + static const struct { + const char *x; + double y; + int cmp, cmpabs; + + } data[] = { + + { "0", 0.0, 0, 0 }, + + { "1", 0.0, 1, 1 }, + { "-1", 0.0, -1, 1 }, + + { "1", 0.5, 1, 1 }, + { "-1", -0.5, -1, 1 }, + + { "0", 1.0, -1, -1 }, + { "0", -1.0, 1, -1 }, + + { "0x1000000000000000000000000000000000000000000000000", 1.0, 1, 1 }, + { "-0x1000000000000000000000000000000000000000000000000", 1.0, -1, 1 }, + + { "0", 1e100, -1, -1 }, + { "0", -1e100, 1, -1 }, + + { "2", 1.5, 1, 1 }, + { "2", -1.5, 1, 1 }, + { "-2", 1.5, -1, 1 }, + { "-2", -1.5, -1, 1 }, + }; + + mpz_t x; + unsigned i; + + mpz_init (x); + + for (i = 0; i < numberof (data); i++) + { + mpz_set_str_or_abort (x, data[i].x, 0); + check_one ("check_data", x, data[i].y, data[i].cmp, data[i].cmpabs); + } + + mpz_clear (x); +} + + +/* Equality of integers with up to 53 bits */ +void +check_onebits (void) +{ + mpz_t x, x2; + double y; + int i; + + mpz_init_set_ui (x, 0L); + mpz_init (x2); + + for (i = 0; i < 512; i++) + { + mpz_mul_2exp (x, x, 1); + mpz_add_ui (x, x, 1L); + + y = mpz_get_d (x); + mpz_set_d (x2, y); + + /* stop if any truncation is occurring */ + if (mpz_cmp (x, x2) != 0) + break; + + check_one ("check_onebits", x, y, 0, 0); + check_one ("check_onebits", x, -y, 1, 0); + mpz_neg (x, x); + check_one ("check_onebits", x, y, -1, 0); + check_one ("check_onebits", x, -y, 0, 0); + mpz_neg (x, x); + } + + mpz_clear (x); + mpz_clear (x2); +} + + +/* With the mpz differing by 1, in a limb position possibly below the double */ +void +check_low_z_one (void) +{ + mpz_t x; + double y; + unsigned long i; + + mpz_init (x); + + /* FIXME: It'd be better to base this on the float format. */ +#if defined (__vax) || defined (__vax__) +#define LIM 127 /* vax fp numbers have limited range */ +#else +#define LIM 512 +#endif + + for (i = 1; i < LIM; i++) + { + mpz_set_ui (x, 1L); + mpz_mul_2exp (x, x, i); + y = mpz_get_d (x); + + check_one ("check_low_z_one", x, y, 0, 0); + check_one ("check_low_z_one", x, -y, 1, 0); + mpz_neg (x, x); + check_one ("check_low_z_one", x, y, -1, 0); + check_one ("check_low_z_one", x, -y, 0, 0); + mpz_neg (x, x); + + mpz_sub_ui (x, x, 1); + + check_one ("check_low_z_one", x, y, -1, -1); + check_one ("check_low_z_one", x, -y, 1, -1); + mpz_neg (x, x); + check_one ("check_low_z_one", x, y, -1, -1); + check_one ("check_low_z_one", x, -y, 1, -1); + mpz_neg (x, x); + + mpz_add_ui (x, x, 2); + + check_one ("check_low_z_one", x, y, 1, 1); + check_one ("check_low_z_one", x, -y, 1, 1); + mpz_neg (x, x); + check_one ("check_low_z_one", x, y, -1, 1); + check_one ("check_low_z_one", x, -y, -1, 1); + mpz_neg (x, x); + } + + mpz_clear (x); +} + +/* Comparing 1 and 1+2^-n. "y" is volatile to make gcc store and fetch it, + which forces it to a 64-bit double, whereas on x86 it would otherwise + remain on the float stack as an 80-bit long double. */ +void +check_one_2exp (void) +{ + double e; + mpz_t x; + volatile double y; + int i; + + mpz_init (x); + + e = 1.0; + for (i = 0; i < 128; i++) + { + e /= 2.0; + y = 1.0 + e; + if (y == 1.0) + break; + + mpz_set_ui (x, 1L); + check_one ("check_one_2exp", x, y, -1, -1); + check_one ("check_one_2exp", x, -y, 1, -1); + + mpz_set_si (x, -1L); + check_one ("check_one_2exp", x, y, -1, -1); + check_one ("check_one_2exp", x, -y, 1, -1); + } + + mpz_clear (x); +} + +void +check_infinity (void) +{ + mpz_t x; + double y = HUGE_VAL; + if (y != 2*y) + return; + + mpz_init (x); + + /* 0 cmp inf */ + mpz_set_ui (x, 0L); + check_one ("check_infinity", x, y, -1, -1); + check_one ("check_infinity", x, -y, 1, -1); + + /* 123 cmp inf */ + mpz_set_ui (x, 123L); + check_one ("check_infinity", x, y, -1, -1); + check_one ("check_infinity", x, -y, 1, -1); + + /* -123 cmp inf */ + mpz_set_si (x, -123L); + check_one ("check_infinity", x, y, -1, -1); + check_one ("check_infinity", x, -y, 1, -1); + + /* 2^5000 cmp inf */ + mpz_set_ui (x, 1L); + mpz_mul_2exp (x, x, 5000L); + check_one ("check_infinity", x, y, -1, -1); + check_one ("check_infinity", x, -y, 1, -1); + + /* -2^5000 cmp inf */ + mpz_neg (x, x); + check_one ("check_infinity", x, y, -1, -1); + check_one ("check_infinity", x, -y, 1, -1); + + mpz_clear (x); +} + +void +testmain (int argc, char *argv[]) +{ + check_data (); + check_onebits (); + check_low_z_one (); + check_one_2exp (); + check_infinity (); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-comb.c b/gmp-6.3.0/mini-gmp/tests/t-comb.c new file mode 100644 index 0000000..652bfcb --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-comb.c @@ -0,0 +1,175 @@ +/* Exercise mpz_fac_ui and mpz_bin_uiui. + +Copyright 2000-2002, 2012, 2013, 2017-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 +#include + +#include "testutils.h" + +/* Usage: t-fac_ui [x|num] + + With no arguments testing goes up to the initial value of "limit" below. + With a number argument tests are carried that far, or with a literal "x" + tests are continued without limit (this being meant only for development + purposes). */ + +void +try_mpz_bin_uiui (mpz_srcptr want, unsigned long n, unsigned long k) +{ + mpz_t got; + + mpz_init (got); + mpz_bin_uiui (got, n, k); + if (mpz_cmp (got, want) != 0) + { + printf ("mpz_bin_uiui wrong\n"); + printf (" n=%lu\n", n); + printf (" k=%lu\n", k); + printf (" got="); mpz_out_str (stdout, 10, got); printf ("\n"); + printf (" want="); mpz_out_str (stdout, 10, want); printf ("\n"); + abort(); + } + mpz_clear (got); +} + +/* Test all bin(n,k) cases, with 0 <= k <= n + 1 <= count. */ +void +bin_smallexaustive (unsigned int count) +{ + mpz_t want; + unsigned long n, k; + + mpz_init (want); + + for (n = 0; n < count; n++) + { + mpz_set_ui (want, 1); + for (k = 0; k <= n; k++) + { + try_mpz_bin_uiui (want, n, k); + mpz_mul_ui (want, want, n - k); + mpz_fdiv_q_ui (want, want, k + 1); + } + try_mpz_bin_uiui (want, n, k); + } + + mpz_clear (want); +} + +/* Test all fac(n) cases, with 0 <= n <= limit. */ +void +fac_smallexaustive (unsigned int limit) +{ + mpz_t f, r; + unsigned long n; + mpz_init_set_si (f, 1); /* 0! = 1 */ + mpz_init (r); + + for (n = 0; n < limit; n++) + { + mpz_fac_ui (r, n); + + if (mpz_cmp (f, r) != 0) + { + printf ("mpz_fac_ui(%lu) wrong\n", n); + printf (" got "); mpz_out_str (stdout, 10, r); printf("\n"); + printf (" want "); mpz_out_str (stdout, 10, f); printf("\n"); + abort (); + } + + mpz_mul_ui (f, f, n+1); /* (n+1)! = n! * (n+1) */ + } + + mpz_clear (f); + mpz_clear (r); +} + +void checkWilson (mpz_t f, unsigned long n) +{ + unsigned long m, a; + + mpz_2fac_ui (f, 2 * n - 1); + + a = mpz_fdiv_q_ui (f, f, n); + m = mpz_fdiv_ui (f, n); + if ((m != n - 1) || (a != 0)) + { + printf ("mpz_2fac_ui(%lu) wrong\n", 2 * n - 1); + printf (" Wilson's theorem not verified: got (%lu, %lu), expected (0, %lu).\n", a, m, n - 1); + abort (); + } + + mpz_fac_ui (f, n - 1); + m = mpz_fdiv_ui (f, n); + if ( m != n - 1) + { + printf ("mpz_fac_ui(%lu) wrong\n", n - 1); + printf (" Wilson's theorem not verified: got %lu, expected %lu.\n",m ,n - 1); + abort (); + } +} + +void +checkprimes (unsigned long p1, unsigned long p2, unsigned long p3) +{ + mpz_t b, f; + + if (p1 - 1 != p2 - 1 + p3 - 1) + { + printf ("checkprimes(%lu, %lu, %lu) wrong\n", p1, p2, p3); + printf (" %lu - 1 != %lu - 1 + %lu - 1 \n", p1, p2, p3); + abort (); + } + + mpz_init (b); + mpz_init (f); + + checkWilson (b, p1); /* b = (p1-1)! */ + checkWilson (f, p2); /* f = (p2-1)! */ + mpz_divexact (b, b, f); + checkWilson (f, p3); /* f = (p3-1)! */ + mpz_divexact (b, b, f); /* b = (p1-1)!/((p2-1)!(p3-1)!) */ + mpz_bin_uiui (f, p1 - 1, p2 - 1); + if (mpz_cmp (f, b) != 0) + { + printf ("checkprimes(%lu, %lu, %lu) wrong\n", p1, p2, p3); + printf (" got "); mpz_out_str (stdout, 10, b); printf("\n"); + printf (" want "); mpz_out_str (stdout, 10, f); printf("\n"); + abort (); + } + + mpz_clear (b); + mpz_clear (f); + +} + +void +testmain (int argc, char *argv[]) +{ + unsigned long limit = 128; + + if (argc > 1 && argv[1][0] == 'x') + limit = ~ limit; + else if (argc > 1) + limit = atoi (argv[1]); + + checkprimes(1009, 733, 277); + fac_smallexaustive (limit); + bin_smallexaustive (limit); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-cong.c b/gmp-6.3.0/mini-gmp/tests/t-cong.c new file mode 100644 index 0000000..92b6930 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-cong.c @@ -0,0 +1,212 @@ +/* test mpz_congruent_p + +Copyright 2001, 2002, 2012, 2014 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 "testutils.h" + +#define MPZ_SRCPTR_SWAP(x, y) \ + do { \ + mpz_srcptr __mpz_srcptr_swap__tmp = (x); \ + (x) = (y); \ + (y) = __mpz_srcptr_swap__tmp; \ + } while (0) + +void +check_one (mpz_srcptr a, mpz_srcptr c, mpz_srcptr d, int want) +{ + int got; + int swap; + + for (swap = 0; swap <= 1; swap++) + { + got = (mpz_congruent_p (a, c, d) != 0); + if (want != got) + { + printf ("mpz_congruent_p wrong\n"); + printf (" expected %d got %d\n", want, got); + dump (" a", a); + dump (" c", c); + dump (" d", d); + abort (); + } + +#if 0 + if (mpz_fits_ulong_p (c) && mpz_fits_ulong_p (d)) + { + unsigned long uc = mpz_get_ui (c); + unsigned long ud = mpz_get_ui (d); + got = (mpz_congruent_ui_p (a, uc, ud) != 0); + if (want != got) + { + printf ("mpz_congruent_ui_p wrong\n"); + printf (" expected %d got %d\n", want, got); + dump (" a", a); + printf (" c=%lu\n", uc); + printf (" d=%lu\n", ud); + abort (); + } + } +#endif + MPZ_SRCPTR_SWAP (a, c); + } +} + + +void +check_data (void) +{ + static const struct { + const char *a; + const char *c; + const char *d; + int want; + + } data[] = { + + /* strict equality mod 0 */ + { "0", "0", "0", 1 }, + { "11", "11", "0", 1 }, + { "3", "11", "0", 0 }, + + /* anything congruent mod 1 */ + { "0", "0", "1", 1 }, + { "1", "0", "1", 1 }, + { "0", "1", "1", 1 }, + { "123", "456", "1", 1 }, + { "0x123456789123456789", "0x987654321987654321", "1", 1 }, + + /* csize==1, dsize==2 changing to 1 after stripping 2s */ + { "0x3333333333333333", "0x33333333", + "0x180000000", 1 }, + { "0x33333333333333333333333333333333", "0x3333333333333333", + "0x18000000000000000", 1 }, + + /* another dsize==2 becoming 1, with opposite signs this time */ + { "0x444444441", + "-0x22222221F", + "0x333333330", 1 }, + { "0x44444444444444441", + "-0x2222222222222221F", + "0x33333333333333330", 1 }, + }; + + mpz_t a, c, d; + unsigned i; + + mpz_init (a); + mpz_init (c); + mpz_init (d); + + for (i = 0; i < numberof (data); i++) + { + mpz_set_str_or_abort (a, data[i].a, 0); + mpz_set_str_or_abort (c, data[i].c, 0); + mpz_set_str_or_abort (d, data[i].d, 0); + check_one (a, c, d, data[i].want); + } + + mpz_clear (a); + mpz_clear (c); + mpz_clear (d); +} + + +void +check_random (int argc, char *argv[]) +{ + mpz_t a, c, d, ra, rc; + int i; + int want; + int reps = 10000; + mpz_t bs; + unsigned long size_range, size; + + if (argc >= 2) + reps = atoi (argv[1]); + + mpz_init (bs); + + mpz_init (a); + mpz_init (c); + mpz_init (d); + mpz_init (ra); + mpz_init (rc); + + for (i = 0; i < reps; i++) + { + mini_urandomb (bs, 32); + size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */ + + mini_urandomb (bs, size_range); + size = mpz_get_ui (bs); + mini_rrandomb (a, size); + + mini_urandomb (bs, 32); + size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */ + + mini_urandomb (bs, size_range); + size = mpz_get_ui (bs); + mini_rrandomb (c, size); + + do + { + mini_urandomb (bs, 32); + size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */ + + mini_urandomb (bs, size_range); + size = mpz_get_ui (bs); + mini_rrandomb (d, size); + } + while (mpz_sgn(d) == 0); + + mini_urandomb (bs, 3); + if (mpz_tstbit (bs, 0)) + mpz_neg (a, a); + if (mpz_tstbit (bs, 1)) + mpz_neg (c, c); + if (mpz_tstbit (bs, 2)) + mpz_neg (d, d); + + mpz_fdiv_r (ra, a, d); + mpz_fdiv_r (rc, c, d); + + want = (mpz_cmp (ra, rc) == 0); + check_one (a, c, d, want); + + mpz_sub (ra, ra, rc); + mpz_sub (a, a, ra); + check_one (a, c, d, 1); + + } + + mpz_clear (bs); + + mpz_clear (a); + mpz_clear (c); + mpz_clear (d); + mpz_clear (ra); + mpz_clear (rc); +} + + +void +testmain (int argc, char *argv[]) +{ + check_data (); + check_random (argc, argv); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-div.c b/gmp-6.3.0/mini-gmp/tests/t-div.c new file mode 100644 index 0000000..be2f6b1 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-div.c @@ -0,0 +1,258 @@ +/* + +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 +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +typedef void div_qr_func (mpz_t, mpz_t, const mpz_t, const mpz_t); +typedef unsigned long div_qr_ui_func (mpz_t, mpz_t, const mpz_t, unsigned long); +typedef void div_func (mpz_t, const mpz_t, const mpz_t); +typedef unsigned long div_x_ui_func (mpz_t, const mpz_t, unsigned long); +typedef unsigned long div_ui_func (const mpz_t, unsigned long); + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, b, q, r, rq, rr; + int div_p; + + mpz_init (a); + mpz_init (b); + mpz_init (r); + mpz_init (q); + mpz_init (rr); + mpz_init (rq); + + for (i = 0; i < COUNT; i++) + { + unsigned j; + for (j = 0; j < 3; j++) + { + static const enum hex_random_op ops[3] = { OP_CDIV, OP_FDIV, OP_TDIV }; + static const char name[3] = { 'c', 'f', 't'}; + static div_qr_func * const div_qr [3] = + { + mpz_cdiv_qr, mpz_fdiv_qr, mpz_tdiv_qr + }; + static div_qr_ui_func * const div_qr_ui[3] = + { + mpz_cdiv_qr_ui, mpz_fdiv_qr_ui, mpz_tdiv_qr_ui + }; + static div_func * const div_q [3] = + { + mpz_cdiv_q, mpz_fdiv_q, mpz_tdiv_q + }; + static div_x_ui_func * const div_q_ui[3] = + { + mpz_cdiv_q_ui, mpz_fdiv_q_ui, mpz_tdiv_q_ui + }; + static div_func * const div_r [3] = + { + mpz_cdiv_r, mpz_fdiv_r, mpz_tdiv_r + }; + static div_x_ui_func * const div_r_ui[3] = + { + mpz_cdiv_r_ui, mpz_fdiv_r_ui, mpz_tdiv_r_ui + }; + static div_ui_func * const div_ui[3] = + { + mpz_cdiv_ui, mpz_fdiv_ui, mpz_tdiv_ui + }; + + mini_random_op4 (ops[j], MAXBITS, a, b, rq, rr); + div_qr[j] (q, r, a, b); + if (mpz_cmp (r, rr) || mpz_cmp (q, rq)) + { + fprintf (stderr, "mpz_%cdiv_qr failed:\n", name[j]); + dump ("a", a); + dump ("b", b); + dump ("r ", r); + dump ("rref", rr); + dump ("q ", q); + dump ("qref", rq); + abort (); + } + mpz_set_si (q, -5); + div_q[j] (q, a, b); + if (mpz_cmp (q, rq)) + { + fprintf (stderr, "mpz_%cdiv_q failed:\n", name[j]); + dump ("a", a); + dump ("b", b); + dump ("q ", q); + dump ("qref", rq); + abort (); + } + mpz_set_ui (r, ~5); + div_r[j] (r, a, b); + if (mpz_cmp (r, rr)) + { + fprintf (stderr, "mpz_%cdiv_r failed:\n", name[j]); + dump ("a", a); + dump ("b", b); + dump ("r ", r); + dump ("rref", rr); + abort (); + } + + if (j == 0) /* do this once, not for all roundings */ + { + div_p = mpz_divisible_p (a, b); + if ((mpz_sgn (r) == 0) ^ (div_p != 0)) + { + fprintf (stderr, "mpz_divisible_p failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r ", r); + abort (); + } + } + + mpz_set_si (r, -6); + if (j == 0 && mpz_sgn (b) < 0) /* ceil, negative divisor */ + { + mpz_mod (r, a, b); + if (mpz_cmp (r, rr)) + { + fprintf (stderr, "mpz_mod failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r ", r); + dump ("rref", rr); + abort (); + } + } + + if (j == 1 && mpz_sgn (b) > 0) /* floor, positive divisor */ + { + mpz_mod (r, a, b); + if (mpz_cmp (r, rr)) + { + fprintf (stderr, "mpz_mod failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r ", r); + dump ("rref", rr); + abort (); + } + } + + if (mpz_fits_ulong_p (b)) + { + unsigned long rl; + + mpz_set_si (r, -7); + mpz_set_ui (q, ~7); + rl = div_qr_ui[j] (q, r, a, mpz_get_ui (b)); + if (rl != mpz_get_ui (rr) + || mpz_cmp (r, rr) || mpz_cmp (q, rq)) + { + fprintf (stderr, "mpz_%cdiv_qr_ui failed:\n", name[j]); + dump ("a", a); + dump ("b", b); + fprintf(stderr, "rl = %lx\n", rl); + dump ("r ", r); + dump ("rref", rr); + dump ("q ", q); + dump ("qref", rq); + abort (); + } + + mpz_set_si (q, 3); + rl = div_q_ui[j] (q, a, mpz_get_ui (b)); + if (rl != mpz_get_ui (rr) || mpz_cmp (q, rq)) + { + fprintf (stderr, "mpz_%cdiv_q_ui failed:\n", name[j]); + dump ("a", a); + dump ("b", b); + fprintf(stderr, "rl = %lx\n", rl); + dump ("rref", rr); + dump ("q ", q); + dump ("qref", rq); + abort (); + } + + mpz_set_ui (r, 7); + rl = div_r_ui[j] (r, a, mpz_get_ui (b)); + if (rl != mpz_get_ui (rr) || mpz_cmp (r, rr)) + { + fprintf (stderr, "mpz_%cdiv_r_ui failed:\n", name[j]); + dump ("a", a); + dump ("b", b); + fprintf(stderr, "rl = %lx\n", rl); + dump ("r ", r); + dump ("rref", rr); + abort (); + } + + rl = div_ui[j] (a, mpz_get_ui (b)); + if (rl != mpz_get_ui (rr)) + { + fprintf (stderr, "mpz_%cdiv_ui failed:\n", name[j]); + dump ("a", a); + dump ("b", b); + fprintf(stderr, "rl = %lx\n", rl); + dump ("rref", rr); + abort (); + } + + if (j == 0) /* do this once, not for all roundings */ + { + div_p = mpz_divisible_ui_p (a, mpz_get_ui (b)); + if ((mpz_sgn (r) == 0) ^ (div_p != 0)) + { + fprintf (stderr, "mpz_divisible_ui_p failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r ", r); + abort (); + } + } + + if (j == 1) /* floor */ + { + mpz_set_si (r, -2); + mpz_mod_ui (r, a, mpz_get_ui (b)); + if (mpz_cmp (r, rr)) + { + fprintf (stderr, "mpz_mod failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r ", r); + dump ("rref", rr); + abort (); + } + } + } + } + } + mpz_clear (a); + mpz_clear (b); + mpz_clear (r); + mpz_clear (q); + mpz_clear (rr); + mpz_clear (rq); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-div_2exp.c b/gmp-6.3.0/mini-gmp/tests/t-div_2exp.c new file mode 100644 index 0000000..53d3f2b --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-div_2exp.c @@ -0,0 +1,82 @@ +/* + +Copyright 2012, 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 +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +typedef void div_func (mpz_t, const mpz_t, mp_bitcnt_t); + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, res, ref; + mp_bitcnt_t b; + + mpz_init (a); + mpz_init (res); + mpz_init (ref); + + for (i = 0; i < COUNT; i++) + { + unsigned j; + for (j = 0; j < 6; j++) + { + static const enum hex_random_op ops[6] = + { + OP_CDIV_Q_2, OP_CDIV_R_2, + OP_FDIV_Q_2, OP_FDIV_R_2, + OP_TDIV_Q_2, OP_TDIV_R_2 + }; + static const char *name[6] = + { + "cdiv_q", "cdiv_r", + "fdiv_q", "fdiv_r", + "tdiv_q", "tdiv_r" + }; + static div_func * const div [6] = + { + mpz_cdiv_q_2exp, mpz_cdiv_r_2exp, + mpz_fdiv_q_2exp, mpz_fdiv_r_2exp, + mpz_tdiv_q_2exp, mpz_tdiv_r_2exp + }; + + mini_random_bit_op (ops[j], MAXBITS, a, &b, ref); + div[j] (res, a, b); + if (mpz_cmp (ref, res)) + { + fprintf (stderr, "mpz_%s_2exp failed:\n", name[j]); + dump ("a", a); + fprintf (stderr, "b: %lu\n", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + } + } + mpz_clear (a); + mpz_clear (res); + mpz_clear (ref); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-double.c b/gmp-6.3.0/mini-gmp/tests/t-double.c new file mode 100644 index 0000000..48774b3 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-double.c @@ -0,0 +1,232 @@ +/* + +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 +#include +#include +#include +#include +#include + +#include "testutils.h" + +#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT) + +mp_bitcnt_t +mpz_mantissasizeinbits (const mpz_t z) +{ + return ! mpz_cmp_ui (z, 0) ? 0 : + mpz_sizeinbase (z, 2) - mpz_scan1 (z, 0); +} + +#if defined(DBL_MANT_DIG) && FLT_RADIX == 2 +int +mpz_get_d_exact_p (const mpz_t z) +{ + return mpz_mantissasizeinbits (z) <= DBL_MANT_DIG; +} +#define HAVE_EXACT_P 1 +#endif + +#define COUNT 10000 + +void +test_matissa (void) +{ + mpz_t x, y; + int i, c; + + mpz_init (x); + mpz_init (y); + + mini_urandomb (y, 4); + c = i = mpz_get_ui (y); + + do { + double d; + int cmp; + + mpz_setbit (x, c); + d = mpz_get_d (x); + mpz_set_d (y, d); + if (mpz_cmp_d (y, d) != 0) + { + fprintf (stderr, "mpz_cmp_d (y, d) failed:\n" + "d = %.20g\n" + "i = %i\n" + "c = %i\n", + d, i, c); + abort (); + } + + cmp = mpz_cmp (x, y); + +#if defined(HAVE_EXACT_P) + if ((mpz_get_d_exact_p (x) != 0) != (cmp == 0)) + { + fprintf (stderr, "Not all bits converted:\n" + "d = %.20g\n" + "i = %i\n" + "c = %i\n", + d, i, c); + abort (); + } +#endif + + if (cmp < 0) + { + fprintf (stderr, "mpz_get_d failed:\n" + "d = %.20g\n" + "i = %i\n" + "c = %i\n", + d, i, c); + abort (); + } + else if (cmp > 0) + { + if (mpz_cmp_d (x, d) <= 0) + { + fprintf (stderr, "mpz_cmp_d (x, d) failed:\n" + "d = %.20g\n" + "i = %i\n" + "c = %i\n", + d, i, c); + abort (); + } + break; + } + ++c; + } while (1); + + mpz_clear (x); + mpz_clear (y); +} + +#ifndef M_PI +#define M_PI 3.141592653589793238462643383279502884 +#endif + +static const struct +{ + double d; + const char *s; +} values[] = { + { 0.0, "0" }, + { 0.3, "0" }, + { -0.3, "0" }, + { M_PI, "3" }, + { M_PI*1e15, "b29430a256d21" }, + { -M_PI*1e15, "-b29430a256d21" }, + /* 17 * 2^{200} = + 27317946752402834684213355569799764242877450894307478200123392 */ + {0.2731794675240283468421335556979976424288e62, + "1100000000000000000000000000000000000000000000000000" }, + { 0.0, NULL } +}; + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t x; + + for (i = 0; values[i].s; i++) + { + char *s; + mpz_init_set_d (x, values[i].d); + s = mpz_get_str (NULL, 16, x); + if (strcmp (s, values[i].s) != 0) + { + fprintf (stderr, "mpz_set_d failed:\n" + "d = %.20g\n" + "s = %s\n" + "r = %s\n", + values[i].d, s, values[i].s); + abort (); + } + testfree (s, strlen(s) + 1); + mpz_clear (x); + } + + mpz_init (x); + + for (i = 0; i < COUNT; i++) + { + /* Use volatile, to avoid extended precision in floating point + registers, e.g., on m68k and 80387. */ + volatile double d, f; + unsigned long m; + int e; + + mini_rrandomb (x, GMP_LIMB_BITS); + m = mpz_get_ui (x); + mini_urandomb (x, 8); + e = mpz_get_ui (x) - 100; + + d = ldexp ((double) m, e); + mpz_set_d (x, d); + f = mpz_get_d (x); + if (f != floor (d)) + { + fprintf (stderr, "mpz_set_d/mpz_get_d failed:\n"); + goto dumperror; + } + if ((f == d) ? (mpz_cmp_d (x, d) != 0) : (mpz_cmp_d (x, d) >= 0)) + { + fprintf (stderr, "mpz_cmp_d (x, d) failed:\n"); + goto dumperror; + } + f = d + 1.0; + if (f > d && ! (mpz_cmp_d (x, f) < 0)) + { + fprintf (stderr, "mpz_cmp_d (x, f) failed:\n"); + goto dumperror; + } + + d = - d; + + mpz_set_d (x, d); + f = mpz_get_d (x); + if (f != ceil (d)) + { + fprintf (stderr, "mpz_set_d/mpz_get_d failed:\n"); + dumperror: + dump ("x", x); + fprintf (stderr, "m = %lx, e = %i\n", m, e); + fprintf (stderr, "d = %.15g\n", d); + fprintf (stderr, "f = %.15g\n", f); + fprintf (stderr, "f - d = %.5g\n", f - d); + abort (); + } + if ((f == d) ? (mpz_cmp_d (x, d) != 0) : (mpz_cmp_d (x, d) <= 0)) + { + fprintf (stderr, "mpz_cmp_d (x, d) failed:\n"); + goto dumperror; + } + f = d - 1.0; + if (f < d && ! (mpz_cmp_d (x, f) > 0)) + { + fprintf (stderr, "mpz_cmp_d (x, f) failed:\n"); + goto dumperror; + } + } + + mpz_clear (x); + test_matissa(); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-gcd.c b/gmp-6.3.0/mini-gmp/tests/t-gcd.c new file mode 100644 index 0000000..64f90f4 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-gcd.c @@ -0,0 +1,178 @@ +/* + +Copyright 2012, 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 +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +/* Called when g is supposed to be gcd(a,b), and g = s a + t b. */ +static int +gcdext_valid_p (const mpz_t a, const mpz_t b, + const mpz_t g, const mpz_t s, const mpz_t t) +{ + mpz_t ta, tb, r; + + /* It's not clear that gcd(0,0) is well defined, but we allow it and + require that gcd(0,0) = 0. */ + if (mpz_sgn (g) < 0) + return 0; + + if (mpz_sgn (a) == 0) + { + /* Must have g == abs (b). Any value for s is in some sense "correct", + but it makes sense to require that s == 0, t = sgn (b)*/ + return mpz_cmpabs (g, b) == 0 + && mpz_sgn (s) == 0 && mpz_cmp_si (t, mpz_sgn (b)) == 0; + } + else if (mpz_sgn (b) == 0) + { + /* Must have g == abs (a), s == sign (a), t = 0 */ + return mpz_cmpabs (g, a) == 0 + && mpz_cmp_si (s, mpz_sgn (a)) == 0 && mpz_sgn (t) == 0; + } + + if (mpz_sgn (g) <= 0) + return 0; + + mpz_init (ta); + mpz_init (tb); + mpz_init (r); + + mpz_mul (ta, s, a); + mpz_mul (tb, t, b); + mpz_add (ta, ta, tb); + + if (mpz_cmp (ta, g) != 0) + { + fail: + mpz_clear (ta); + mpz_clear (tb); + mpz_clear (r); + return 0; + } + mpz_tdiv_qr (ta, r, a, g); + if (mpz_sgn (r) != 0) + goto fail; + + mpz_tdiv_qr (tb, r, b, g); + if (mpz_sgn (r) != 0) + goto fail; + + /* Require that 2 |s| < |b/g|, or |s| == 1. */ + if (mpz_cmpabs_ui (s, 1) > 0) + { + mpz_mul_2exp (r, s, 1); + if (mpz_cmpabs (r, tb) > 0) + goto fail; + } + + /* Require that 2 |t| < |a/g| or |t| == 1*/ + if (mpz_cmpabs_ui (t, 1) > 0) + { + mpz_mul_2exp (r, t, 1); + if (mpz_cmpabs (r, ta) > 0) + return 0; + } + + mpz_clear (ta); + mpz_clear (tb); + mpz_clear (r); + + return 1; +} + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, b, g, s, t; + + mpz_init (a); + mpz_init (b); + mpz_init (g); + mpz_init (s); + mpz_init (t); + + for (i = 0; i < COUNT; i++) + { + mini_random_op3 (OP_GCD, MAXBITS, a, b, s); + mpz_gcd (g, a, b); + if (mpz_cmp (g, s)) + { + fprintf (stderr, "mpz_gcd failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", g); + dump ("ref", s); + abort (); + } + } + + for (i = 0; i < COUNT; i++) + { + unsigned flags; + mini_urandomb (a, 32); + flags = mpz_get_ui (a); + mini_rrandomb (a, MAXBITS); + mini_rrandomb (b, MAXBITS); + + if (flags % 37 == 0) + mpz_mul (a, a, b); + if (flags % 37 == 1) + mpz_mul (b, a, b); + + if (flags & 1) + mpz_neg (a, a); + if (flags & 2) + mpz_neg (b, b); + + mpz_gcdext (g, s, t, a, b); + if (!gcdext_valid_p (a, b, g, s, t)) + { + fprintf (stderr, "mpz_gcdext failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("g", g); + dump ("s", s); + dump ("t", t); + abort (); + } + + mpz_gcd (s, a, b); + if (mpz_cmp (g, s)) + { + fprintf (stderr, "mpz_gcd failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", g); + dump ("ref", s); + abort (); + } + } + mpz_clear (a); + mpz_clear (b); + mpz_clear (g); + mpz_clear (s); + mpz_clear (t); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-import.c b/gmp-6.3.0/mini-gmp/tests/t-import.c new file mode 100644 index 0000000..66c9d5e --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-import.c @@ -0,0 +1,99 @@ +/* + +Copyright 2013 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 +#include +#include + +#include "testutils.h" + +#define MAX_WORDS 20 +#define MAX_WORD_SIZE 10 + +static void +dump_bytes (const char *label, const unsigned char *s, size_t n) +{ + size_t i; + fprintf (stderr, "%s:", label); + for (i = 0; i < n; i++) + { + if (i && (i % 16) == 0) + fprintf (stderr, "\n"); + fprintf (stderr, " %02x", s[i]); + } + fprintf (stderr, "\n"); +} + +/* Tests both mpz_import and mpz_export. */ +void +testmain (int argc, char **argv) +{ + unsigned char input[MAX_WORDS * MAX_WORD_SIZE]; + unsigned char output[MAX_WORDS * MAX_WORD_SIZE + 2]; + size_t count, in_count, out_count, size; + int endian, order; + + mpz_t a, res; + + mpz_init (a); + mpz_init (res); + + for (size = 0; size <= MAX_WORD_SIZE; size++) + for (count = 0; count <= MAX_WORDS; count++) + for (endian = -1; endian <= 1; endian++) + for (order = -1; order <= 1; order += 2) + { + mini_rrandomb_export (a, input, &in_count, + order, size, endian, size*count * 8); + mpz_import (res, in_count, order, size, endian, 0, input); + if (mpz_cmp (a, res)) + { + fprintf (stderr, "mpz_import failed:\n" + "in_count %lu, out_count %lu, endian = %d, order = %d\n", + (unsigned long) in_count, (unsigned long) out_count, endian, order); + dump ("a", a); + dump ("res", res); + abort (); + } + output[0] = 17; + output[1+in_count*size] = 17; + + mpz_export (output+1, &out_count, order, size, endian, 0, a); + if (out_count != in_count + || memcmp (output+1, input, in_count * size) + || output[0] != 17 + || output[1+in_count*size] != 17) + { + fprintf (stderr, "mpz_export failed:\n" + "in_count %lu, out_count %lu, endian = %d, order = %d\n", + (unsigned long) in_count, (unsigned long) out_count, endian, order); + dump_bytes ("input", input, in_count * size); + dump_bytes ("output", output+1, out_count * size); + if (output[0] != 17) + fprintf (stderr, "Overwrite at -1, value %02x\n", output[0]); + if (output[1+in_count*size] != 17) + fprintf (stderr, "Overwrite at %lu, value %02x\n", + (unsigned long) (in_count*size), output[1+in_count*size]); + + abort (); + } + } + mpz_clear (a); + mpz_clear (res); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-invert.c b/gmp-6.3.0/mini-gmp/tests/t-invert.c new file mode 100644 index 0000000..02e1731 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-invert.c @@ -0,0 +1,141 @@ +/* + +Copyright 2012, 2016 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 +#include +#include +#include + +#include "testutils.h" + +#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT) + +#define COUNT 10000 + +static void +test_2by1(const mpz_t u) +{ + mpz_t m, p, t; + mp_limb_t tl; + + mpz_init (p); + + assert (mpz_size (u) == 1); + + tl = mpn_invert_limb (u->_mp_d[0]); + mpz_roinit_n (t, &tl, 1); + mpz_init_set (m, t); + mpz_setbit (m, GMP_LIMB_BITS); + + mpz_mul (p, m, u); + + mpz_init (t); + mpz_setbit (t, 2* GMP_LIMB_BITS); + mpz_sub (t, t, p); + + /* Should have 0 < B^2 - m u <= u */ + if (mpz_sgn (t) <= 0 || mpz_cmp (t, u) > 0) + { + fprintf (stderr, "mpn_invert_limb failed:\n"); + dump ("u", u); + dump ("m", m); + dump ("p", p); + dump ("t", t); + abort (); + } + mpz_clear (m); + mpz_clear (p); + mpz_clear (t); +} + +static void +test_3by2(const mpz_t u) +{ + mpz_t m, p, t; + mp_limb_t tl; + + mpz_init (p); + + assert (mpz_size (u) == 2); + + tl = mpn_invert_3by2 (u->_mp_d[1], u->_mp_d[0]); + mpz_roinit_n (t, &tl, 1); + mpz_init_set (m, t); + + mpz_setbit (m, GMP_LIMB_BITS); + + mpz_mul (p, m, u); + + mpz_init (t); + mpz_setbit (t, 3 * GMP_LIMB_BITS); + mpz_sub (t, t, p); + + /* Should have 0 < B^3 - m u <= u */ + if (mpz_sgn (t) <= 0 || mpz_cmp (t, u) > 0) + { + fprintf (stderr, "mpn_invert_3by2 failed:\n"); + dump ("u", u); + dump ("m", m); + dump ("p", p); + dump ("t", t); + abort (); + } + mpz_clear (m); + mpz_clear (p); + mpz_clear (t); +} + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t u, m, p, t; + + mpz_init (u); + mpz_init (m); + mpz_init (p); + mpz_init (t); + + /* These values trigger 32-bit overflow of ql in mpn_invert_3by2. */ + if (GMP_LIMB_BITS == 64) + { + mpz_set_str (u, "80007fff3ffe0000", 16); + test_2by1 (u); + mpz_set_str (u, "80007fff3ffe000000000000000003ff", 16); + test_3by2 (u); + } + + for (i = 0; i < COUNT; i++) + { + mini_urandomb (u, GMP_LIMB_BITS); + mpz_setbit (u, GMP_LIMB_BITS -1); + + test_2by1 (u); + } + + for (i = 0; i < COUNT; i++) + { + mini_urandomb (u, 2*GMP_LIMB_BITS); + mpz_setbit (u, 2*GMP_LIMB_BITS -1); + + test_3by2 (u); + } + + mpz_clear (u); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-lcm.c b/gmp-6.3.0/mini-gmp/tests/t-lcm.c new file mode 100644 index 0000000..f21a39a --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-lcm.c @@ -0,0 +1,73 @@ +/* + +Copyright 2012, 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 +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, b, g, s; + + mpz_init (a); + mpz_init (b); + mpz_init (g); + mpz_init (s); + + for (i = 0; i < COUNT; i++) + { + mini_random_op3 (OP_LCM, MAXBITS, a, b, s); + mpz_lcm (g, a, b); + if (mpz_cmp (g, s)) + { + fprintf (stderr, "mpz_lcm failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", g); + dump ("ref", s); + abort (); + } + if (mpz_fits_ulong_p (b)) + { + mpz_set_si (g, 0); + mpz_lcm_ui (g, a, mpz_get_ui (b)); + if (mpz_cmp (g, s)) + { + fprintf (stderr, "mpz_lcm_ui failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", g); + dump ("ref", s); + abort (); + } + } + } + + mpz_clear (a); + mpz_clear (b); + mpz_clear (g); + mpz_clear (s); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-limbs.c b/gmp-6.3.0/mini-gmp/tests/t-limbs.c new file mode 100644 index 0000000..f4e57dd --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-limbs.c @@ -0,0 +1,111 @@ +/* + +Copyright 2012, 2014, 2016, 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 +#include +#include +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 100 + +void +my_mpz_mul (mpz_t r, mpz_srcptr a, mpz_srcptr b) +{ + mp_limb_t *tp; + mp_size_t tn, an, bn; + + an = mpz_size (a); + bn = mpz_size (b); + + assert (an > 0); + assert (bn > 0); + + tn = an + bn; + tp = mpz_limbs_write (r, tn); + if (an > bn) + mpn_mul (tp, mpz_limbs_read (a), an, mpz_limbs_read (b), bn); + else + mpn_mul (tp, mpz_limbs_read (b), bn, mpz_limbs_read (a), an); + + if (mpz_sgn (a) != mpz_sgn(b)) + tn = - tn; + + mpz_limbs_finish (r, tn); +} + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, b, res, ref; + + mpz_init (a); + mpz_init (b); + mpz_init (res); + mpz_init (ref); + + for (i = 0; i < COUNT; i++) + { + mini_random_op3 (OP_MUL, MAXBITS, a, b, ref); + if (mpz_sgn(ref) == 0) + /* my_mpz_mul requires a != 0, b != 0 */ + continue; + my_mpz_mul (res, a, b); + if (mpz_cmp (res, ref)) + { + fprintf (stderr, "my_mpz_mul failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + /* The following test exploits a side-effect of my_mpz_mul: res + points to a buffer with at least an+bn limbs, and the limbs + above the result are zeroed. */ + if (mpz_size (b) > 0 && mpz_getlimbn (res, mpz_size(a)) != mpz_limbs_read (res) [mpz_size(a)]) + { + fprintf (stderr, "getlimbn - limbs_read differ.\n"); + abort (); + } + if ((i % 4 == 0) && mpz_size (res) > 1) + { + mpz_realloc2 (res, 1); + if (mpz_cmp_ui (res, 0)) + { + fprintf (stderr, "mpz_realloc2 did not clear res.\n"); + abort (); + } + mpz_limbs_finish (ref, 0); + if (mpz_cmp_d (ref, 0)) + { + fprintf (stderr, "mpz_limbs_finish did not clear res.\n"); + abort (); + } + } + } + mpz_clear (a); + mpz_clear (b); + mpz_clear (res); + mpz_clear (ref); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-logops.c b/gmp-6.3.0/mini-gmp/tests/t-logops.c new file mode 100644 index 0000000..b4e0239 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-logops.c @@ -0,0 +1,112 @@ +/* + +Copyright 2012, 2013 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 +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +void +testlogops (int count) +{ + int i; + mpz_t a, b, res, ref; + mp_bitcnt_t c; + + mpz_init (a); + mpz_init (b); + mpz_init (res); + mpz_init (ref); + + for (i = 0; i < count; i++) + { + mini_random_op3 (OP_AND, MAXBITS, a, b, ref); + mpz_and (res, a, b); + if (mpz_cmp (res, ref)) + { + fprintf (stderr, "mpz_and failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + + mini_random_op3 (OP_IOR, MAXBITS, a, b, ref); + mpz_ior (res, a, b); + if (mpz_cmp (res, ref)) + { + fprintf (stderr, "mpz_ior failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + + mini_random_op3 (OP_XOR, MAXBITS, a, b, ref); + mpz_xor (res, a, b); + if (mpz_cmp (res, ref)) + { + fprintf (stderr, "mpz_xor failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + + if (i % 8) { + c = 0; + mpz_mul_2exp (res, res, i % 8); + } else if (mpz_sgn (res) >= 0) { + c = mpz_odd_p (res) != 0; + mpz_tdiv_q_2exp (res, res, 1); + } else { + c = (~ (mp_bitcnt_t) 0) - 3; + mpz_set_ui (res, 11 << ((i >> 3)%4)); /* set 3 bits */ + } + + if (mpz_popcount (res) + c != mpz_hamdist (a, b)) + { + fprintf (stderr, "mpz_popcount(r) + %lu and mpz_hamdist(a,b) differ:\n", c); + dump ("a", a); + dump ("b", b); + dump ("r", res); + fprintf (stderr, "mpz_popcount(r) = %lu:\n", mpz_popcount (res)); + fprintf (stderr, "mpz_hamdist(a,b) = %lu:\n", mpz_hamdist (a, b)); + abort (); + } + } + mpz_clear (a); + mpz_clear (b); + mpz_clear (res); + mpz_clear (ref); +} + +void +testmain (int argc, char **argv) +{ + testhalves (COUNT*2/3, testlogops); + testlogops (COUNT/3); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-lucm.c b/gmp-6.3.0/mini-gmp/tests/t-lucm.c new file mode 100644 index 0000000..22ad575 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-lucm.c @@ -0,0 +1,98 @@ +/* Tests the (internal) function mpz_lucas_mod + +Copyright 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 +#include +#include +#include + +#include "testutils.h" + +#define MAXBITS 100 +#define COUNT 1000 + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t m, vr, qr, vm, qm, vt; + int resm, resr; + long Q; + unsigned long b0; + + mpz_init (m); + mpz_init (vr); + mpz_init (qr); + mpz_init (vm); + mpz_init (qm); + mpz_init (vt); + + for (i = 0; i < COUNT; i++) + { + mini_random_lucm_op (MAXBITS, vr, qr, m, &Q, &b0, &resr); + if (b0 == 0) + { + fprintf (stderr, "lucas_mod: test disabled (%u tests done).\n", i); + break; + } + resm = mpz_lucas_mod (vm, qm, Q, b0, m); + + if (resr != resm) + { + if (resm != 0 || mpz_cmp_ui (vm, 0) != 0) + { + fprintf (stderr, "mpz_lucas_mod wrong return value (%d != %d):\n", resr, resm); + fprintf (stderr, "Q = %ld , b0 = %lu\n", Q, b0); + dump ("m", m); + dump ("vm", vm); + dump ("qm", qm); + abort (); + } + } + else if (resm == 0) + { + mpz_abs (vr, vr); + mpz_sub (vt, m, vr); + mpz_abs (vm, vm); + mpz_mod (qm, qm, m); + if (mpz_cmp_ui (qr, 0) < 0) + mpz_add (qr, qr, m); + if (mpz_cmp (qm, qr) != 0 || + (mpz_cmp (vm, vr) != 0 && mpz_cmp (vm, vt) != 0)) + { + fprintf (stderr, "mpz_lucas_mod error:\n"); + fprintf (stderr, "Q = %ld , b0 = %lu\n", Q, b0); + dump ("m", m); + dump ("vm", vm); + dump ("vr", vr); + dump ("vt", vt); + dump ("qm", qm); + dump ("qr", qr); + abort (); + } + + } + } + mpz_clear (m); + mpz_clear (vr); + mpz_clear (qr); + mpz_clear (vm); + mpz_clear (qm); + mpz_clear (vt); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-mpq_addsub.c b/gmp-6.3.0/mini-gmp/tests/t-mpq_addsub.c new file mode 100644 index 0000000..de1461f --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-mpq_addsub.c @@ -0,0 +1,204 @@ +/* + +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 +#include +#include + +#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 +testcmpui () +{ + unsigned d1, d2, n1, n2; + mpq_t q1, q2; + + mpq_init (q1); + mpq_init (q2); + + for (d1 = 1; d1 < 6; d1 += 2) + for (n1 = 1; n1 < 6; n1 *= 2) + { + mpq_set_ui (q1, n1, d1); + for (d2 = 1; d2 < 6; d2 += 2) + for (n2 = 1; n2 < 6; n2 *= 2) + { + int fres = mpq_cmp_ui (q1, n2, d2); + int ref = (d1*n2 < d2*n1) - (d1*n2 > d2*n1); + + mpq_set_ui (q2, n2, d2); + + if ((!ref) != mpq_equal (q1, q2)) + { + fprintf (stderr, "mpz_equal failed: %i / %i = %i / %i ? %i\n", n1, d1, n2, d2, ref); + abort (); + } + + if (ref != fres) + { + fprintf (stderr, "mpz_cmp_ui failed: %i / %i = %i / %i ? %i != %i\n", n1, d1, n2, d2, ref, fres); + abort (); + } + } + } + + mpq_clear (q1); + mpq_clear (q2); +} + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, b, q, r, c; + mpq_t rr, ii, ff; + int tst; + + testcmpui (); + 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/gmp-6.3.0/mini-gmp/tests/t-mpq_double.c b/gmp-6.3.0/mini-gmp/tests/t-mpq_double.c new file mode 100644 index 0000000..3cfba60 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-mpq_double.c @@ -0,0 +1,211 @@ +/* Test mpq_set_d. + +Copyright 2001-2003, 2005, 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 +#include +#include + +#include "testutils.h" +#include "../mini-mpq.h" + +#define COUNT 2000 + +mp_bitcnt_t +mpz_mantissasizeinbits (const mpz_t z) +{ + return ! mpz_cmp_ui (z, 0) ? 0 : + mpz_sizeinbase (z, 2) - mpz_scan1 (z, 0); +} + +int +mpz_abspow2_p (const mpz_t z) +{ + return mpz_mantissasizeinbits (z) == 1; +} + +mp_bitcnt_t +mpq_mantissasizeinbits (const mpq_t q) +{ + if (! mpz_abspow2_p (mpq_denref (q))) + return ~ (mp_bitcnt_t) 0; + + return mpz_mantissasizeinbits (mpq_numref (q)); +} + +#if defined(DBL_MANT_DIG) && FLT_RADIX == 2 +int +mpz_get_d_exact_p (const mpz_t z) +{ + return mpz_mantissasizeinbits (z) <= DBL_MANT_DIG; +} + +int +mpq_get_d_exact_p (const mpq_t q) +{ + return mpq_mantissasizeinbits (q) <= DBL_MANT_DIG; +} +#define HAVE_EXACT_P 1 +#endif + +void +check_random (void) +{ + unsigned i; + mpz_t x; + mpq_t y, z; + + mpz_init (x); + mpq_init (y); + mpq_init (z); + + for (i = 0; i < COUNT; i++) + { + /* Use volatile, to avoid extended precision in floating point + registers, e.g., on m68k and 80387. */ + volatile double d, f; + unsigned long m; + int e, c; + + mini_rrandomb (x, CHAR_BIT * sizeof (unsigned long)); + m = mpz_get_ui (x); + mini_urandomb (x, 8); + e = mpz_get_ui (x) - 128; + + d = ldexp ((double) m, e); + mpq_set_d (y, d); + f = mpq_get_d (y); + if (f != d) + { + fprintf (stderr, "mpq_set_d/mpq_get_d failed:\n"); + goto dumperror; + } + + d = - d; + mpq_neg (y, y); + + mpq_set_d (z, d); + f = mpq_get_d (z); + if (f != d || !mpq_equal (y, z)) + { + fprintf (stderr, "mpq_set_d/mpq_get_d failed:\n"); + dumperror: + dump ("ny", mpq_numref (y)); + dump ("dy", mpq_denref (y)); + fprintf (stderr, "m = %lx, e = %i\n", m, e); + fprintf (stderr, "d = %.35g\n", d); + fprintf (stderr, "f = %.35g\n", f); + fprintf (stderr, "f - d = %.35g\n", f - d); + abort (); + } + + mini_rrandomb (x, CHAR_BIT * sizeof (unsigned long)); + m = mpz_get_ui (x); + mini_urandomb (x, 8); + e = mpz_get_ui (x) - 128; + + d = ldexp ((double) m, e); + mpq_set_d (y, d); + + if (i == 0) + mpq_neg (z, y); + + mpq_add (y, y, z); + mpq_set_d (z, mpq_get_d (y)); + f = mpq_get_d (z); + c = mpq_cmp (y, z); + +#if defined(HAVE_EXACT_P) + if (mpq_get_d_exact_p (y) ? c != 0 : (f > 0 ? c <= 0 : c >= 0)) +#else + if (f > 0 ? c < 0 : c > 0) +#endif + { + fprintf (stderr, "mpq_get_d/mpq_set_d failed: %i %i\n", i, c); + goto dumperror; + } + } + + mpz_clear (x); + mpq_clear (y); + mpq_clear (z); +} + + +void +check_data (void) +{ + static const struct { + double y; + long int n; + unsigned long d; + } data[] = { + { 0.0, 0, 1 }, + { 1.0, 1, 1 }, + { -1.0, -1, 1 }, + { -1.5, -3, 2 }, + {-1.25, -5, 4 }, + {0.125, 1, 8 }, + + {24685,24685,1}, + {-9876,-9876,1}, + {463.5, 927,2}, + + {1234.5/8192, 2469, 16384 }, + {-543.0/1024, -543, 1024 }, + {9876.5/ 512, 19753, 1024 }, + {9753.0/ 128, 9753, 128 }, + {-789.0/ 32, -789, 32 }, + {4.580078125, 2345, 512 }, + }; + + mpq_t x, r; + unsigned i; + double d; + + mpq_init (x); + mpq_init (r); + + for (i = 0; i < numberof (data); i++) + { + mpq_set_d (x, data[i].y); + mpq_set_si (r, data[i].n, data[i].d); + mpq_canonicalize (r); + if (!mpq_equal (x, r)) + { + fprintf (stderr, "mpq_set_d failed: %li / %lu != %g\n", data[i].n, data[i].d, data[i].y); + abort (); + } + d = mpq_get_d (r); + if (d != data[i].y) + { + fprintf (stderr, "mpq_get_d failed: %li / %lu != %g\n", data[i].n, data[i].d, data[i].y); + abort (); + } + } + + mpq_clear (x); + mpq_clear (r); +} + +void +testmain (int argc, char *argv[]) +{ + check_data (); + check_random (); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-mpq_muldiv.c b/gmp-6.3.0/mini-gmp/tests/t-mpq_muldiv.c new file mode 100644 index 0000000..8e7de8b --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-mpq_muldiv.c @@ -0,0 +1,176 @@ +/* + +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 +#include +#include + +#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; + + 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 (); + } + + mpq_mul (resq, aq, aq); + mpq_mul (refq, aq, bq); /* now bq = - aq */ + mpq_neg (refq, refq); + if (!mpq_equal (resq, refq)) + { + fprintf (stderr, "mpq_mul(sqr) 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 (); + } + } + + 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/gmp-6.3.0/mini-gmp/tests/t-mpq_muldiv_2exp.c b/gmp-6.3.0/mini-gmp/tests/t-mpq_muldiv_2exp.c new file mode 100644 index 0000000..46b2c0c --- /dev/null +++ b/gmp-6.3.0/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 +#include +#include + +#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 %zu\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/gmp-6.3.0/mini-gmp/tests/t-mpq_str.c b/gmp-6.3.0/mini-gmp/tests/t-mpq_str.c new file mode 100644 index 0000000..e2b740a --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-mpq_str.c @@ -0,0 +1,263 @@ +/* + +Copyright 2012-2014, 2016, 2018, 2020 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 +#include +#include +#include +#include + +#include "testutils.h" +#include "../mini-mpq.h" + +#define MAXBITS 400 +#define COUNT 2000 + +#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT) +#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS) + +static void +test_small (void) +{ + struct { + const char *input; + const char *decimal; + } data[] = { + { "1832407/3", "1832407/3" }, + { " 2763959/6", "2763959/6 " }, + { "4 981 999 / 1 8", "4981999/18" }, + { "10\t73981/30 ", "1073981/30" }, + { "958 544 /1", "00958544/01" }, + { "-0", "0000" }, + { " -000 ", "0/ 1" }, + { "0704436/011", "231710/9" }, + /* Check the case of large number of leading zeros. */ + { "0000000000000000000000000/1", "0/0000000000000000000000001" }, + { "000000000000000704436/000011", "0000000000000000231710/00009" }, + { " 012/ 02503517", "10/689999" }, + { "0b 10/0 1312143", "2/365667" }, + { "-03 274062/0x1", "-882738/1" }, + { "012\t242", "005282" }, + { "9/0b11010111110010001111", "9/883855" }, + { "022/ 0b11001010010100001", "18/103585" }, + { "-0b101010110011101111/0x12", "-175343/18" }, + { "-05/0b 111 1111 0110 1110 0110", "-5/521958" }, + { "0b 011 111 110 111 001 000 011/0b00110", "1044035/6" }, + { " 0x53dfc", "343548" }, + { "-0x00012/0x000fA019", "-18/1024025" }, + { "0x 642d1", "410321" }, + { "0x5 8067/0Xa", "360551/10" }, + { "-0xd6Be6/3", "-879590/3" }, + { "\t0B1110000100000000011", "460803" }, + { "0B\t1111110010010100101", "517285" }, + { "-0x 00 2d/0B1\t010111101101110100", "-45/359284" }, + { "-0B101\t1001101111111001", "-367609" }, + { "0B10001001010111110000/0xf", "562672/15" }, + { "0Xe4B7e/1", "936830" }, + { "0X1E4bf/0X1", "124095" }, + { "-0Xfdb90/05", "-1039248/5" }, + { "0b010/0X7fc47", "2/523335" }, + { "15/0X8167c", "15/530044" }, + /* Some invalid inputs */ + { "", NULL }, + { "0x", NULL }, + { "0b", NULL }, + { "0z", NULL }, + { "-", NULL }, + { "/0x ", NULL }, + { "0|1", NULL }, + { "/", NULL }, + { "0ab", NULL }, + { "10x0", NULL }, + { "1/0xxab", NULL }, + { "0/ab", NULL }, + { "0/#", NULL }, + { "$foo/1", NULL }, + { NULL, NULL } + }; + unsigned i; + mpq_t a, b; + mpq_init (a); + mpq_init (b); + + for (i = 0; data[i].input; i++) + { + int res = mpq_set_str (a, data[i].input, 0); + if (data[i].decimal) + { + if (res != 0) + { + fprintf (stderr, "mpq_set_str returned -1, input: %s\n", + data[i].input); + abort (); + } + if (mpq_set_str (b, data[i].decimal, 10) != 0) + { + fprintf (stderr, "mpq_set_str returned -1, decimal input: %s\n", + data[i].input); + abort (); + } + if (!mpq_equal (a, b)) + { + fprintf (stderr, "mpq_set_str failed for input: %s\n", + data[i].input); + + dump ("got_num", mpq_numref (a)); + dump ("got_den", mpq_denref (a)); + dump ("ref_num", mpq_numref (b)); + dump ("ref_den", mpq_denref (b)); + abort (); + } + } + else if (res != -1) + { + fprintf (stderr, "mpq_set_str returned %d, invalid input: %s\n", + res, data[i].input); + abort (); + } + } + + mpq_clear (a); + mpq_clear (b); +} + +void +testmain (int argc, char **argv) +{ + unsigned i; + char *ap; + char *bp; + char *rp; + size_t rn; + + mpq_t a, b; + + FILE *tmp; + + test_small (); + + mpq_init (a); + mpq_init (b); + + tmp = tmpfile (); + if (!tmp) + fprintf (stderr, + "Failed to create temporary file. Skipping mpq_out_str tests.\n"); + + if (mpq_out_str (tmp, 63, a) != 0) + { + printf ("mpq_out_str did not return 0 (error) with base > 62\n"); + abort (); + } + + if (mpq_out_str (tmp, -37, a) != 0) + { + printf ("mpq_out_str did not return 0 (error) with base < -37\n"); + abort (); + } + + for (i = 0; i < COUNT/60; i++) + { + int base; + for (base = 2; base <= 62; ++base) + { + hex_mpq_random_str_op (MAXBITS, (i&1 || base > 36) ? base: -base, &ap, &rp); + if (mpq_set_str (a, ap, 16) != 0) + { + fprintf (stderr, "mpq_set_str failed on input %s\n", ap); + abort (); + } + + rn = strlen (rp); + + bp = mpq_get_str (NULL, (i&1 || base > 36) ? base: -base, a); + if (strcmp (bp, rp)) + { + fprintf (stderr, "mpz_get_str failed:\n"); + dump ("a_num", mpq_numref (a)); + dump ("a_den", mpq_denref (a)); + fprintf (stderr, "b = %s\n", bp); + fprintf (stderr, " base = %d\n", base); + fprintf (stderr, "r = %s\n", rp); + abort (); + } + + /* Just a few tests with file i/o. */ + if (tmp && i < 20) + { + size_t tn; + rewind (tmp); + tn = mpq_out_str (tmp, (i&1 || base > 36) ? base: -base, a); + if (tn != rn) + { + fprintf (stderr, "mpq_out_str, bad return value:\n"); + dump ("a_num", mpq_numref (a)); + dump ("a_den", mpq_denref (a)); + fprintf (stderr, "r = %s\n", rp); + fprintf (stderr, " base %d, correct size %u, got %u\n", + base, (unsigned) rn, (unsigned)tn); + abort (); + } + rewind (tmp); + memset (bp, 0, rn); + tn = fread (bp, 1, rn, tmp); + if (tn != rn) + { + fprintf (stderr, + "fread failed, expected %lu bytes, got only %lu.\n", + (unsigned long) rn, (unsigned long) tn); + abort (); + } + + if (memcmp (bp, rp, rn) != 0) + { + fprintf (stderr, "mpq_out_str failed:\n"); + dump ("a_num", mpq_numref (a)); + dump ("a_den", mpq_denref (a)); + fprintf (stderr, "b = %s\n", bp); + fprintf (stderr, " base = %d\n", base); + fprintf (stderr, "r = %s\n", rp); + abort (); + } + } + + mpq_set_str (b, rp, base); + + if (!mpq_equal (a, b)) + { + fprintf (stderr, "mpq_set_str failed:\n"); + fprintf (stderr, "r = %s\n", rp); + fprintf (stderr, " base = %d\n", base); + fprintf (stderr, "r = %s\n", ap); + fprintf (stderr, " base = 16\n"); + dump ("b_num", mpq_numref (b)); + dump ("b_den", mpq_denref (b)); + dump ("r_num", mpq_numref (a)); + dump ("r_den", mpq_denref (a)); + abort (); + } + + free (ap); + free (rp); + testfree (bp, strlen(bp) + 1); + } + } + mpq_clear (a); + mpq_clear (b); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-mul.c b/gmp-6.3.0/mini-gmp/tests/t-mul.c new file mode 100644 index 0000000..57ec4ed --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-mul.c @@ -0,0 +1,113 @@ +/* + +Copyright 2012, 2014, 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 +#include +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT) +#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS) + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, b, res, res_ui, ref, tz; + mp_limb_t t[2*MAXLIMBS]; + mp_size_t an; + + mpz_init (a); + mpz_init (b); + mpz_init (res); + mpz_init (res_ui); + mpz_init (ref); + + for (i = 0; i < COUNT; i++) + { + mini_random_op3 (OP_MUL, MAXBITS, a, b, ref); + mpz_mul (res, a, b); + if (mpz_cmp (res, ref)) + { + fprintf (stderr, "mpz_mul failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + if (mpz_size (a) == mpz_size (b)) + { + memset (t, 0x55, sizeof(t)); + an = mpz_size (a); + if (an > 0) + { + mpn_mul_n (t, a->_mp_d, b->_mp_d, an); + + mpz_roinit_n (tz, t, 2*an); + if (mpz_cmpabs (tz, ref)) + { + fprintf (stderr, "mpn_mul_n failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("ref", ref); + abort (); + } + } + } + if (mpz_fits_slong_p (b)) { + mpz_mul_si (res_ui, a, mpz_get_si (b)); + if (mpz_cmp (res_ui, ref)) + { + fprintf (stderr, "mpz_mul_si failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", res_ui); + dump ("ref", ref); + abort (); + } + } + mini_random_op2 (OP_SQR, MAXBITS, a, ref); + an = mpz_size (a); + if (an > 0) + { + memset (t, 0x33, sizeof(t)); + mpn_sqr (t, mpz_limbs_read (a), an); + + mpz_roinit_n (tz, t, 2*an); + if (mpz_cmp (tz, ref)) + { + fprintf (stderr, "mpn (squaring) failed:\n"); + dump ("a", a); + dump ("ref", ref); + abort (); + } + } + } + mpz_clear (a); + mpz_clear (b); + mpz_clear (res); + mpz_clear (res_ui); + mpz_clear (ref); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-powm.c b/gmp-6.3.0/mini-gmp/tests/t-powm.c new file mode 100644 index 0000000..1cce9b5 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-powm.c @@ -0,0 +1,87 @@ +/* + +Copyright 2012, 2022, 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 +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 1000 + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t b, e, m, res, ref; + + mpz_init (b); + mpz_init (e); + mpz_init (m); + mpz_init (res); + mpz_init (ref); + + for (i = 0; i < COUNT; i++) + { + mini_random_op4 (OP_POWM, MAXBITS, b, e, m, ref); + mpz_powm (res, b, e, m); + if (mpz_cmp (res, ref)) + { + fprintf (stderr, "mpz_powm failed:\n"); + dump ("b", b); + dump ("e", e); + dump ("m", m); + dump ("r", res); + dump ("ref", ref); + abort (); + } + } + + /* res >= 0, come from the random choices above, */ + if (mpz_cmp_ui (res, 1) <= 0) /* if too small, */ + mpz_add_ui (res, res, 9); /* add an arbitrary value. */ + + mpz_set_ui (e, 0); + /* Test the case m^0 (mod m), expect 1 (m is greater than 1). */ + mpz_powm (res, res, e, res); + if (mpz_cmp_ui (res, 1) != 0) + { + fprintf (stderr, "mpz_powm failed: b=m, e=0; 1 expected,\n"); + dump ("m", res); + dump ("r", res); + abort (); + } + + /* Now res is 1. */ + /* Test the case 1^0 (mod 1), expect 0. */ + mpz_powm (res, res, e, res); + if (mpz_size (res)) + { + fprintf (stderr, "mpz_powm failed: b=1, e=0, m=1; 0 expected,\n"); + dump ("r", res); + abort (); + } + + mpz_clear (b); + mpz_clear (e); + mpz_clear (m); + mpz_clear (res); + mpz_clear (ref); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-pprime_p.c b/gmp-6.3.0/mini-gmp/tests/t-pprime_p.c new file mode 100644 index 0000000..6cf9b18 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-pprime_p.c @@ -0,0 +1,183 @@ +/* test mpz_probab_prime_p + +Copyright 2001, 2002, 2004, 2011, 2012, 2014, 2016 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 "testutils.h" + +static int +isprime (unsigned long int t) +{ + unsigned long int q, r, d; + + if (t < 32) + return (0xa08a28acUL >> t) & 1; + if ((t & 1) == 0) + return 0; + + if (t % 3 == 0) + return 0; + if (t % 5 == 0) + return 0; + if (t % 7 == 0) + return 0; + + for (d = 11;;) + { + q = t / d; + r = t - q * d; + if (q < d) + return 1; + if (r == 0) + break; + d += 2; + q = t / d; + r = t - q * d; + if (q < d) + return 1; + if (r == 0) + break; + d += 4; + } + return 0; +} + +static void +check_one (mpz_srcptr n, int want) +{ + int got; + + got = mpz_probab_prime_p (n, 25); + + /* "definitely prime" is fine if we only wanted "probably prime" */ + if (got == 2 && want == 1) + want = 2; + + if (got != want) + { + printf ("mpz_probab_prime_p\n"); + dump (" n ", n); + printf (" got =%d", got); + printf (" want=%d\n", want); + abort (); + } +} + +static void +check_pn (mpz_ptr n, int want) +{ + check_one (n, want); + mpz_neg (n, n); + check_one (n, want); +} + +static void +check_small (void) +{ + mpz_t n; + long i; + + mpz_init (n); + + for (i = 0; i < 1700; i++) + { + mpz_set_si (n, i); + check_pn (n, isprime (i)); + } + + mpz_clear (n); +} + +void +check_composites (void) +{ + int i; + int reps = 1000; + mpz_t a, b, n, bs; + unsigned long size_range, size; + + mpz_init (a); + mpz_init (b); + mpz_init (n); + mpz_init (bs); + + for (i = 0; i < reps; i++) + { + mini_urandomb (bs, 16); + size_range = mpz_get_ui (bs) % 10 + 1; /* 0..1024 bit operands */ + + mini_urandomb (bs, size_range); + size = mpz_get_ui (bs); + mini_rrandomb (a, size); + + mini_urandomb (bs, size_range); + size = mpz_get_ui (bs); + mini_rrandomb (b, size); + + /* Exclude trivial factors */ + if (mpz_cmp_ui (a, 1) == 0) + mpz_set_ui (a, 2); + if (mpz_cmp_ui (b, 1) == 0) + mpz_set_ui (b, 2); + + mpz_mul (n, a, b); + + check_pn (n, 0); + } + mpz_clear (a); + mpz_clear (b); + mpz_clear (n); + mpz_clear (bs); +} + +static void +check_primes (void) +{ + static const char * const primes[] = { + "2", "17", "65537", + /* diffie-hellman-group1-sha1, also "Well known group 2" in RFC + 2412, 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } */ + "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + "FFFFFFFFFFFFFFFF", + NULL + }; + + mpz_t n; + int i; + + mpz_init (n); + + for (i = 0; primes[i]; i++) + { + mpz_set_str_or_abort (n, primes[i], 0); + check_one (n, 1); + } + mpz_clear (n); +} + +void +testmain (int argc, char *argv[]) +{ + check_small (); + check_composites (); + check_primes (); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-reuse.c b/gmp-6.3.0/mini-gmp/tests/t-reuse.c new file mode 100644 index 0000000..09a5440 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-reuse.c @@ -0,0 +1,663 @@ +/* Test that routines allow reusing a source variable as destination. + +Copyright 1996, 1999-2002, 2009, 2012 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 +#include +#include + +#include "testutils.h" + +#define COUNT 100 + +void dump3 (const char *, mpz_t, mpz_t, mpz_t); +void mpz_check_format (const mpz_t); + +typedef void (*dss_func) (mpz_t, const mpz_t, const mpz_t); +typedef void (*dsi_func) (mpz_t, const mpz_t, unsigned long int); +typedef unsigned long int (*dsi_div_func) (mpz_t, const mpz_t, unsigned long int); +typedef unsigned long int (*ddsi_div_func) (mpz_t, mpz_t, const mpz_t, unsigned long int); +typedef void (*ddss_div_func) (mpz_t, mpz_t, const mpz_t, const mpz_t); +typedef void (*ds_func) (mpz_t, const mpz_t); + + +void +mpz_xinvert (mpz_t r, const mpz_t a, const mpz_t b) +{ + int res; + res = mpz_invert (r, a, b); + if (res == 0) + mpz_set_ui (r, 0); +} + +dss_func dss_funcs[] = +{ + mpz_add, mpz_sub, mpz_mul, + mpz_cdiv_q, mpz_cdiv_r, mpz_fdiv_q, mpz_fdiv_r, mpz_tdiv_q, mpz_tdiv_r, + mpz_xinvert, + mpz_gcd, mpz_lcm, mpz_and, mpz_ior, mpz_xor +}; +const char *dss_func_names[] = +{ + "mpz_add", "mpz_sub", "mpz_mul", + "mpz_cdiv_q", "mpz_cdiv_r", "mpz_fdiv_q", "mpz_fdiv_r", "mpz_tdiv_q", "mpz_tdiv_r", + "mpz_xinvert", + "mpz_gcd", "mpz_lcm", "mpz_and", "mpz_ior", "mpz_xor" +}; +char dss_func_division[] = {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; + +dsi_func dsi_funcs[] = +{ + /* Don't change order here without changing the code in main(). */ + mpz_add_ui, mpz_mul_ui, mpz_sub_ui, + mpz_fdiv_q_2exp, mpz_fdiv_r_2exp, + mpz_cdiv_q_2exp, mpz_cdiv_r_2exp, + mpz_tdiv_q_2exp, mpz_tdiv_r_2exp, + mpz_mul_2exp, + mpz_pow_ui +}; +const char *dsi_func_names[] = +{ + "mpz_add_ui", "mpz_mul_ui", "mpz_sub_ui", + "mpz_fdiv_q_2exp", "mpz_fdiv_r_2exp", + "mpz_cdiv_q_2exp", "mpz_cdiv_r_2exp", + "mpz_tdiv_q_2exp", "mpz_tdiv_r_2exp", + "mpz_mul_2exp", + "mpz_pow_ui" +}; + +dsi_div_func dsi_div_funcs[] = +{ + mpz_cdiv_q_ui, mpz_cdiv_r_ui, + mpz_fdiv_q_ui, mpz_fdiv_r_ui, + mpz_tdiv_q_ui, mpz_tdiv_r_ui +}; +const char *dsi_div_func_names[] = +{ + "mpz_cdiv_q_ui", "mpz_cdiv_r_ui", + "mpz_fdiv_q_ui", "mpz_fdiv_r_ui", + "mpz_tdiv_q_ui", "mpz_tdiv_r_ui" +}; + +ddsi_div_func ddsi_div_funcs[] = +{ + mpz_cdiv_qr_ui, + mpz_fdiv_qr_ui, + mpz_tdiv_qr_ui +}; +const char *ddsi_div_func_names[] = +{ + "mpz_cdiv_qr_ui", + "mpz_fdiv_qr_ui", + "mpz_tdiv_qr_ui" +}; + +ddss_div_func ddss_div_funcs[] = +{ + mpz_cdiv_qr, + mpz_fdiv_qr, + mpz_tdiv_qr +}; +const char *ddss_div_func_names[] = +{ + "mpz_cdiv_qr", + "mpz_fdiv_qr", + "mpz_tdiv_qr" +}; + +ds_func ds_funcs[] = +{ + mpz_abs, mpz_com, mpz_neg, mpz_sqrt +}; +const char *ds_func_names[] = +{ + "mpz_abs", "mpz_com", "mpz_neg", "mpz_sqrt" +}; + + +#define FAIL(class,indx,op1,op2,op3) \ + do { \ + class##_funcs[indx] = 0; \ + dump3 (class##_func_names[indx], op1, op2, op3); \ + failures++; \ + } while (0) +#define FAIL2(fname,op1,op2,op3) \ + do { \ + dump3 (#fname, op1, op2, op3); \ + failures++; \ + } while (0) + +void +testmain (int argc, char **argv) +{ + unsigned i; + int pass, reps = COUNT; + mpz_t in1, in2, in3; + unsigned long int in2i; + mp_size_t size; + mpz_t res1, res2, res3; + mpz_t ref1, ref2, ref3; + mpz_t t; + unsigned long int r1, r2; + long failures = 0; + mpz_t bs; + unsigned long bsi, size_range; + + mpz_init (bs); + + mpz_init (in1); + mpz_init (in2); + mpz_init (in3); + mpz_init (ref1); + mpz_init (ref2); + mpz_init (ref3); + mpz_init (res1); + mpz_init (res2); + mpz_init (res3); + mpz_init (t); + + for (pass = 1; pass <= reps; pass++) + { + mini_urandomb (bs, 32); + size_range = mpz_get_ui (bs) % 12 + 2; + + mini_urandomb (bs, size_range); + size = mpz_get_ui (bs); + mini_rrandomb (in1, size); + + mini_urandomb (bs, size_range); + size = mpz_get_ui (bs); + mini_rrandomb (in2, size); + + mini_urandomb (bs, size_range); + size = mpz_get_ui (bs); + mini_rrandomb (in3, size); + + mini_urandomb (bs, 3); + bsi = mpz_get_ui (bs); + if ((bsi & 1) != 0) + mpz_neg (in1, in1); + if ((bsi & 2) != 0) + mpz_neg (in2, in2); + if ((bsi & 4) != 0) + mpz_neg (in3, in3); + + for (i = 0; i < numberof (dss_funcs); i++) + { + if (dss_funcs[i] == 0) + continue; + if (dss_func_division[i] && mpz_sgn (in2) == 0) + continue; + + (dss_funcs[i]) (ref1, in1, in2); + mpz_check_format (ref1); + + mpz_set (res1, in1); + (dss_funcs[i]) (res1, res1, in2); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL (dss, i, in1, in2, NULL); + + mpz_set (res1, in2); + (dss_funcs[i]) (res1, in1, res1); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL (dss, i, in1, in2, NULL); + } + + for (i = 0; i < numberof (ddss_div_funcs); i++) + { + if (ddss_div_funcs[i] == 0) + continue; + if (mpz_sgn (in2) == 0) + continue; + + (ddss_div_funcs[i]) (ref1, ref2, in1, in2); + mpz_check_format (ref1); + mpz_check_format (ref2); + + mpz_set (res1, in1); + (ddss_div_funcs[i]) (res1, res2, res1, in2); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0) + FAIL (ddss_div, i, in1, in2, NULL); + + mpz_set (res2, in1); + (ddss_div_funcs[i]) (res1, res2, res2, in2); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0) + FAIL (ddss_div, i, in1, in2, NULL); + + mpz_set (res1, in2); + (ddss_div_funcs[i]) (res1, res2, in1, res1); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0) + FAIL (ddss_div, i, in1, in2, NULL); + + mpz_set (res2, in2); + (ddss_div_funcs[i]) (res1, res2, in1, res2); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0) + FAIL (ddss_div, i, in1, in2, NULL); + } + + for (i = 0; i < numberof (ds_funcs); i++) + { + if (ds_funcs[i] == 0) + continue; + if (strcmp (ds_func_names[i], "mpz_sqrt") == 0 + && mpz_sgn (in1) < 0) + continue; + + (ds_funcs[i]) (ref1, in1); + mpz_check_format (ref1); + + mpz_set (res1, in1); + (ds_funcs[i]) (res1, res1); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL (ds, i, in1, in2, NULL); + } + + in2i = mpz_get_ui (in2); + + for (i = 0; i < numberof (dsi_funcs); i++) + { + if (dsi_funcs[i] == 0) + continue; + if (strcmp (dsi_func_names[i], "mpz_fdiv_q_2exp") == 0) + /* Limit exponent to something reasonable for the division + functions. Without this, we'd normally shift things off + the end and just generate the trivial values 1, 0, -1. */ + in2i %= 0x1000; + if (strcmp (dsi_func_names[i], "mpz_mul_2exp") == 0) + /* Limit exponent more for mpz_mul_2exp to save time. */ + in2i %= 0x100; + if (strcmp (dsi_func_names[i], "mpz_pow_ui") == 0) + /* Limit exponent yet more for mpz_pow_ui to save time. */ + in2i %= 0x10; + + (dsi_funcs[i]) (ref1, in1, in2i); + mpz_check_format (ref1); + + mpz_set (res1, in1); + (dsi_funcs[i]) (res1, res1, in2i); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL (dsi, i, in1, in2, NULL); + } + + if (in2i != 0) /* Don't divide by 0. */ + { + for (i = 0; i < numberof (dsi_div_funcs); i++) + { + r1 = (dsi_div_funcs[i]) (ref1, in1, in2i); + mpz_check_format (ref1); + + mpz_set (res1, in1); + r2 = (dsi_div_funcs[i]) (res1, res1, in2i); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0 || r1 != r2) + FAIL (dsi_div, i, in1, in2, NULL); + } + + for (i = 0; i < numberof (ddsi_div_funcs); i++) + { + r1 = (ddsi_div_funcs[i]) (ref1, ref2, in1, in2i); + mpz_check_format (ref1); + + mpz_set (res1, in1); + r2 = (ddsi_div_funcs[i]) (res1, res2, res1, in2i); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2) + FAIL (ddsi_div, i, in1, in2, NULL); + + mpz_set (res2, in1); + (ddsi_div_funcs[i]) (res1, res2, res2, in2i); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2) + FAIL (ddsi_div, i, in1, in2, NULL); + } + } + + if (mpz_sgn (in1) >= 0) + { + mpz_sqrtrem (ref1, ref2, in1); + mpz_check_format (ref1); + mpz_check_format (ref2); + + mpz_set (res1, in1); + mpz_sqrtrem (res1, res2, res1); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0) + FAIL2 (mpz_sqrtrem, in1, NULL, NULL); + + mpz_set (res2, in1); + mpz_sqrtrem (res1, res2, res2); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0) + FAIL2 (mpz_sqrtrem, in1, NULL, NULL); + } + + if (mpz_sgn (in1) >= 0) + { + mpz_root (ref1, in1, in2i % 0x1000 + 1); + mpz_check_format (ref1); + + mpz_set (res1, in1); + mpz_root (res1, res1, in2i % 0x1000 + 1); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_root, in1, in2, NULL); + } + + if (mpz_sgn (in1) >= 0) + { + mpz_rootrem (ref1, ref2, in1, in2i % 0x1000 + 1); + mpz_check_format (ref1); + mpz_check_format (ref2); + + mpz_set (res1, in1); + mpz_rootrem (res1, res2, res1, in2i % 0x1000 + 1); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0) + FAIL2 (mpz_rootrem, in1, in2, NULL); + + mpz_set (res2, in1); + mpz_rootrem (res1, res2, res2, in2i % 0x1000 + 1); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0) + FAIL2 (mpz_rootrem, in1, in2, NULL); + } + + if (pass < reps / 2) /* run fewer tests since gcdext lots of time */ + { + mpz_gcdext (ref1, ref2, ref3, in1, in2); + mpz_check_format (ref1); + mpz_check_format (ref2); + mpz_check_format (ref3); + + mpz_set (res1, in1); + mpz_gcdext (res1, res2, res3, res1, in2); + mpz_check_format (res1); + mpz_check_format (res2); + mpz_check_format (res3); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 + || mpz_cmp (ref3, res3) != 0) + FAIL2 (mpz_gcdext, in1, in2, NULL); + + mpz_set (res2, in1); + mpz_gcdext (res1, res2, res3, res2, in2); + mpz_check_format (res1); + mpz_check_format (res2); + mpz_check_format (res3); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 + || mpz_cmp (ref3, res3) != 0) + FAIL2 (mpz_gcdext, in1, in2, NULL); + + mpz_set (res3, in1); + mpz_gcdext (res1, res2, res3, res3, in2); + mpz_check_format (res1); + mpz_check_format (res2); + mpz_check_format (res3); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 + || mpz_cmp (ref3, res3) != 0) + FAIL2 (mpz_gcdext, in1, in2, NULL); + + mpz_set (res1, in2); + mpz_gcdext (res1, res2, res3, in1, res1); + mpz_check_format (res1); + mpz_check_format (res2); + mpz_check_format (res3); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 + || mpz_cmp (ref3, res3) != 0) + FAIL2 (mpz_gcdext, in1, in2, NULL); + + mpz_set (res2, in2); + mpz_gcdext (res1, res2, res3, in1, res2); + mpz_check_format (res1); + mpz_check_format (res2); + mpz_check_format (res3); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 + || mpz_cmp (ref3, res3) != 0) + FAIL2 (mpz_gcdext, in1, in2, NULL); + + mpz_set (res3, in2); + mpz_gcdext (res1, res2, res3, in1, res3); + mpz_check_format (res1); + mpz_check_format (res2); + mpz_check_format (res3); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 + || mpz_cmp (ref3, res3) != 0) + FAIL2 (mpz_gcdext, in1, in2, NULL); + + mpz_set (res1, in1); + mpz_gcdext (res1, res2, NULL, res1, in2); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 + || mpz_cmp (ref3, res3) != 0) + FAIL2 (mpz_gcdext, in1, in2, NULL); + + mpz_set (res2, in1); + mpz_gcdext (res1, res2, NULL, res2, in2); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 + || mpz_cmp (ref3, res3) != 0) + FAIL2 (mpz_gcdext, in1, in2, NULL); + + mpz_set (res1, in2); + mpz_gcdext (res1, res2, NULL, in1, res1); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 + || mpz_cmp (ref3, res3) != 0) + FAIL2 (mpz_gcdext, in1, in2, NULL); + + mpz_set (res2, in2); + mpz_gcdext (res1, res2, NULL, in1, res2); + mpz_check_format (res1); + mpz_check_format (res2); + if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 + || mpz_cmp (ref3, res3) != 0) + FAIL2 (mpz_gcdext, in1, in2, NULL); + } + + /* Don't run mpz_powm for huge exponents or when undefined. */ + if (mpz_sizeinbase (in2, 2) < 250 && mpz_sgn (in3) != 0 + && (mpz_sgn (in2) >= 0 || mpz_invert (t, in1, in3))) + { + mpz_powm (ref1, in1, in2, in3); + mpz_check_format (ref1); + + mpz_set (res1, in1); + mpz_powm (res1, res1, in2, in3); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_powm, in1, in2, in3); + + mpz_set (res1, in2); + mpz_powm (res1, in1, res1, in3); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_powm, in1, in2, in3); + + mpz_set (res1, in3); + mpz_powm (res1, in1, in2, res1); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_powm, in1, in2, in3); + } + + /* Don't run mpz_powm_ui when undefined. */ + if (mpz_sgn (in3) != 0) + { + mpz_powm_ui (ref1, in1, in2i, in3); + mpz_check_format (ref1); + + mpz_set (res1, in1); + mpz_powm_ui (res1, res1, in2i, in3); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_powm_ui, in1, in2, in3); + + mpz_set (res1, in3); + mpz_powm_ui (res1, in1, in2i, res1); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_powm_ui, in1, in2, in3); + } + + { + r1 = mpz_gcd_ui (ref1, in1, in2i); + mpz_check_format (ref1); + + mpz_set (res1, in1); + r2 = mpz_gcd_ui (res1, res1, in2i); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_gcd_ui, in1, in2, NULL); + } +#if 0 + if (mpz_cmp_ui (in2, 1L) > 0 && mpz_sgn (in1) != 0) + { + /* Test mpz_remove */ + mpz_remove (ref1, in1, in2); + mpz_check_format (ref1); + + mpz_set (res1, in1); + mpz_remove (res1, res1, in2); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_remove, in1, in2, NULL); + + mpz_set (res1, in2); + mpz_remove (res1, in1, res1); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_remove, in1, in2, NULL); + } +#endif + if (mpz_sgn (in2) != 0) + { + /* Test mpz_divexact */ + mpz_mul (t, in1, in2); + mpz_divexact (ref1, t, in2); + mpz_check_format (ref1); + + mpz_set (res1, t); + mpz_divexact (res1, res1, in2); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_divexact, t, in2, NULL); + + mpz_set (res1, in2); + mpz_divexact (res1, t, res1); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_divexact, t, in2, NULL); + } + +#if 0 + if (mpz_sgn (in2) > 0) + { + /* Test mpz_divexact_gcd, same as mpz_divexact */ + mpz_mul (t, in1, in2); + mpz_divexact_gcd (ref1, t, in2); + mpz_check_format (ref1); + + mpz_set (res1, t); + mpz_divexact_gcd (res1, res1, in2); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_divexact_gcd, t, in2, NULL); + + mpz_set (res1, in2); + mpz_divexact_gcd (res1, t, res1); + mpz_check_format (res1); + if (mpz_cmp (ref1, res1) != 0) + FAIL2 (mpz_divexact_gcd, t, in2, NULL); + } +#endif + } + + if (failures != 0) + { + fprintf (stderr, "mpz/reuse: %ld error%s\n", failures, "s" + (failures == 1)); + exit (1); + } + + mpz_clear (bs); + mpz_clear (in1); + mpz_clear (in2); + mpz_clear (in3); + mpz_clear (ref1); + mpz_clear (ref2); + mpz_clear (ref3); + mpz_clear (res1); + mpz_clear (res2); + mpz_clear (res3); + mpz_clear (t); +} + +void +dump3 (const char *name, mpz_t in1, mpz_t in2, mpz_t in3) +{ + printf ("failure in %s (", name); + mpz_out_str (stdout, -16, in1); + if (in2 != NULL) + { + printf (" "); + mpz_out_str (stdout, -16, in2); + } + if (in3 != NULL) + { + printf (" "); + mpz_out_str (stdout, -16, in3); + } + printf (")\n"); +} + +void +mpz_check_format (const mpz_t x) +{ + mp_size_t n = x ->_mp_size; + if (n < 0) + n = - n; + + if (n > x->_mp_alloc) + { + fprintf (stderr, "mpz_t size exceeds allocation!\n"); + abort (); + } + + if (n > 0 && x->_mp_d[n-1] == 0) + { + fprintf (stderr, "Unnormalized mpz_t!\n"); + abort (); + } +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-root.c b/gmp-6.3.0/mini-gmp/tests/t-root.c new file mode 100644 index 0000000..1f46c43 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-root.c @@ -0,0 +1,95 @@ +/* + +Copyright 2012, 2013 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 +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +/* Called when s is supposed to be floor(root(u,z)), and r = u - s^z */ +static int +rootrem_valid_p (const mpz_t u, const mpz_t s, const mpz_t r, unsigned long z) +{ + mpz_t t; + + mpz_init (t); + if (mpz_fits_ulong_p (s)) + mpz_ui_pow_ui (t, mpz_get_ui (s), z); + else + mpz_pow_ui (t, s, z); + mpz_sub (t, u, t); + if ((mpz_sgn (t) != mpz_sgn(u) && mpz_sgn (t) != 0) || mpz_cmp (t, r) != 0) + { + mpz_clear (t); + return 0; + } + if (mpz_sgn (s) > 0) + mpz_add_ui (t, s, 1); + else + mpz_sub_ui (t, s, 1); + mpz_pow_ui (t, t, z); + if (mpz_cmpabs (t, u) <= 0) + { + mpz_clear (t); + return 0; + } + + mpz_clear (t); + return 1; +} + +void +testmain (int argc, char **argv) +{ + unsigned i; + unsigned long e; + mpz_t u, s, r, bs; + + mpz_init (u); + mpz_init (s); + mpz_init (r); + mpz_init (bs); + + for (i = 0; i < COUNT; i++) + { + mini_rrandomb (u, MAXBITS); + mini_rrandomb (bs, 12); + e = mpz_getlimbn (bs, 0) % mpz_sizeinbase (u, 2) + 1; + if ((e & 1) && (mpz_getlimbn (bs, 0) & (1L<<10))) + mpz_neg (u, u); + mpz_rootrem (s, r, u, e); + + if (!rootrem_valid_p (u, s, r, e)) + { + fprintf (stderr, "mpz_rootrem(%lu-th) failed:\n", e); + dump ("u", u); + dump ("root", s); + dump ("rem", r); + abort (); + } + } + mpz_clear (bs); + mpz_clear (u); + mpz_clear (s); + mpz_clear (r); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-scan.c b/gmp-6.3.0/mini-gmp/tests/t-scan.c new file mode 100644 index 0000000..39b1f35 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-scan.c @@ -0,0 +1,90 @@ +/* + +Copyright 2012, 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 +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a; + mp_bitcnt_t b, res, ref; + + mpz_init (a); + + for (i = 0; i < COUNT; i++) + { + mini_random_scan_op (OP_SCAN0, MAXBITS, a, &b, &ref); + res = mpz_scan0 (a, b); + if (res != ref) + { + fprintf (stderr, "mpz_scan0 failed:\n"); + dump ("a", a); + fprintf (stderr, "b: %lu\n", b); + fprintf (stderr, "r: %lu\n", res); + fprintf (stderr, "ref: %lu\n", ref); + abort (); + } + if (mpz_sgn (a) > 0 && ref < mpz_sizeinbase (a, 2)) + { + res = mpn_scan0 (a->_mp_d, b); + if (res != ref) + { + fprintf (stderr, "mpn_scan0 failed:\n"); + dump ("a", a); + fprintf (stderr, "b: %lu\n", b); + fprintf (stderr, "r: %lu\n", res); + fprintf (stderr, "ref: %lu\n", ref); + abort (); + } + } + mini_random_scan_op (OP_SCAN1, MAXBITS, a, &b, &ref); + res = mpz_scan1 (a, b); + if (res != ref) + { + fprintf (stderr, "mpz_scan1 failed:\n"); + dump ("a", a); + fprintf (stderr, "b: %lu\n", b); + fprintf (stderr, "r: %lu\n", res); + fprintf (stderr, "ref: %lu\n", ref); + abort (); + } + if (mpz_sgn (a) > 0 && ref != ~ (mp_bitcnt_t) 0) + { + res = mpn_scan1 (a->_mp_d, b); + if (res != ref) + { + fprintf (stderr, "mpn_scan1 failed:\n"); + dump ("a", a); + fprintf (stderr, "b: %lu\n", b); + fprintf (stderr, "r: %lu\n", res); + fprintf (stderr, "ref: %lu\n", ref); + abort (); + } + } + } + mpz_clear (a); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-signed.c b/gmp-6.3.0/mini-gmp/tests/t-signed.c new file mode 100644 index 0000000..cfa40d7 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-signed.c @@ -0,0 +1,348 @@ +/* Exercise some mpz_..._si functions. + +Copyright 2013, 2016, 2020 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 +#include +#include + +#include "testutils.h" + +/* Always called with sz fitting in a signed long, and si is the + corresponding value. */ +int +check_si (const mpz_t sz, long si) +{ + mpz_t t; + + /* Checks on sz/si */ + if ((mpz_cmp_si (sz, si)) != 0) + { + printf ("mpz_cmp_si (sz, %ld) != 0.\n", si); + return 0; + } + if (mpz_get_si (sz) != si) + { + printf ("mpz_get_si (sz) != %ld.\n", si); + return 0; + } + + mpz_init_set_si (t, si); + + if (mpz_cmp (t, sz) != 0) + { + printf ("mpz_init_set_si (%ld) failed.\n", si); + printf (" got="); mpz_out_str (stdout, 10, t); printf ("\n"); + return 0; + } + + mpz_clear (t); + return 1; +} + +/* Called with mpz_cmp (sz, oz) == c. If sz fits in a signed long, + si is the coresponding value, and similarly for oz and oi. */ +void +check_si_cmp (const mpz_t sz, const mpz_t oz, long si, long oi, int c) +{ + if (mpz_cmp (sz, oz) != c) + { + printf ("mpz_cmp (sz, oz) != %i.\n", c); + goto fail; + } + + if (mpz_fits_slong_p (sz)) + { + if (!check_si (sz, si)) + goto fail; + if (mpz_cmp_si (oz, si) != -c) + { + printf ("mpz_cmp_si (oz, %ld) != %i.\n", si, -c); + goto fail; + } + } + else + { + if (mpz_cmp_si (sz, si) != c) + { + printf ("mpz_cmp_si (sz, %ld) != %i.\n", si, c); + goto fail; + } + if (mpz_cmp_si (sz, -c) != c) + { + printf ("mpz_cmp_si (sz, %i) != %i.\n", -c, c); + goto fail; + } + } + if (mpz_fits_slong_p (oz)) + { + if (!check_si (oz, oi)) + goto fail; + if (mpz_cmp_si (sz, oi) != c) + { + printf ("mpz_cmp_si (sz, %ld) != %i.\n", oi, c); + goto fail; + } + } + return; + + fail: + printf (" sz="); mpz_out_str (stdout, 10, sz); printf ("\n"); + printf (" si=%ld\n", si); + printf (" oz="); mpz_out_str (stdout, 10, oz); printf ("\n"); + printf (" oi=%ld\n", si); + abort (); +} + +void +try_op_si (int c) +{ + long si, oi; + mpz_t sz, oz; + unsigned overflow_count; + + si = c; + mpz_init_set_si (sz, si); + + oi = si; + mpz_init_set (oz, sz); + + /* To get a few tests with operands straddling the border, don't + stop at the very first operand exceeding a signed long. */ + for (overflow_count = 0; overflow_count < 10; ) + { + /* c * 2^k */ + mpz_mul_2exp (sz, sz, 1); + if (mpz_fits_slong_p (sz)) + si *= 2; + else + overflow_count++; + + check_si_cmp (sz, oz, si, oi, c); + + /* c * (2^k + 1) */ + if (c == -1) + mpz_sub_ui (oz, sz, 1); + else + mpz_add_ui (oz, sz, 1); + if (mpz_fits_slong_p (oz)) + oi = si + c; + else + overflow_count++; + check_si_cmp (oz, sz, oi, si, c); + + /* c * (2^K - 1) */ + mpz_mul_si (oz, sz, 2*c); + if (c == -1) + mpz_ui_sub (oz, 1, oz); /* oz = sz * 2 + 1 */ + else + mpz_sub_ui (oz, oz, 1); /* oz = sz * 2 - 1 */ + if (mpz_fits_slong_p (oz)) + oi = (si - c) * 2 + c; + else + overflow_count++; + + check_si_cmp (oz, sz, oi, si, c); + }; + + mpz_clear (sz); + mpz_clear (oz); +} + +void +try_fits_slong_p (void) +{ + mpz_t x; + mpz_init_set_si (x, LONG_MAX); + if (!mpz_fits_slong_p (x)) + { + printf ("mpz_fits_slong_p (LONG_MAX) false!\n"); + abort (); + } + mpz_add_ui (x, x, 1); + if (mpz_fits_slong_p (x)) + { + printf ("mpz_fits_slong_p (LONG_MAX + 1) true!\n"); + abort (); + } + mpz_set_si (x, LONG_MIN); + if (!mpz_fits_slong_p (x)) + { + printf ("mpz_fits_slong_p (LONG_MIN) false!\n"); + abort (); + } + mpz_sub_ui (x, x, 1); + if (mpz_fits_slong_p (x)) + { + printf ("mpz_fits_slong_p (LONG_MIN - 1) true!\n"); + abort (); + } + + mpz_clear (x); +} + +void +try_fits_utype_p (void) +{ + mpz_t x; + mpz_init (x); + if (!mpz_fits_ulong_p (x)) + { + printf ("mpz_fits_ulong_p (0) false!\n"); + abort (); + } + if (!mpz_fits_uint_p (x)) + { + printf ("mpz_fits_uint_p (0) false!\n"); + abort (); + } + if (!mpz_fits_ushort_p (x)) + { + printf ("mpz_fits_udhort_p (0) false!\n"); + abort (); + } + mpz_set_si (x, -1); + if (mpz_fits_ulong_p (x)) + { + printf ("mpz_fits_ulong_p (- 1) true!\n"); + abort (); + } + if (mpz_fits_uint_p (x)) + { + printf ("mpz_fits_uint_p (- 1) true!\n"); + abort (); + } + if (mpz_fits_ushort_p (x)) + { + printf ("mpz_fits_ushort_p (- 1) true!\n"); + abort (); + } + mpz_set_ui (x, ULONG_MAX); + if (!mpz_fits_ulong_p (x)) + { + printf ("mpz_fits_ulong_p (ULONG_MAX) false!\n"); + abort (); + } + mpz_add_ui (x, x, 1); + if (mpz_fits_ulong_p (x)) + { + printf ("mpz_fits_ulong_p (ULONG_MAX + 1) true!\n"); + abort (); + } + mpz_set_ui (x, UINT_MAX); + if (!mpz_fits_uint_p (x)) + { + printf ("mpz_fits_uint_p (UINT_MAX) false!\n"); + abort (); + } + mpz_add_ui (x, x, 1); + if (mpz_fits_uint_p (x)) + { + printf ("mpz_fits_uint_p (UINT_MAX + 1) true!\n"); + abort (); + } + mpz_set_ui (x, USHRT_MAX); + if (!mpz_fits_ushort_p (x)) + { + printf ("mpz_fits_ushort_p (USHRT_MAX) false!\n"); + abort (); + } + mpz_add_ui (x, x, 1); + if (mpz_fits_ushort_p (x)) + { + printf ("mpz_fits_ushort_p (USHRT_MAX + 1) true!\n"); + abort (); + } + + mpz_clear (x); +} + +void +try_fits_sint_p (void) +{ + mpz_t x; + mpz_init_set_si (x, INT_MAX); + if (!mpz_fits_sint_p (x)) + { + printf ("mpz_fits_sint_p (INT_MAX) false!\n"); + abort (); + } + mpz_add_ui (x, x, 1); + if (mpz_fits_sint_p (x)) + { + printf ("mpz_fits_sint_p (INT_MAX + 1) true!\n"); + abort (); + } + mpz_set_si (x, INT_MIN); + if (!mpz_fits_sint_p (x)) + { + printf ("mpz_fits_sint_p (INT_MIN) false!\n"); + abort (); + } + mpz_sub_ui (x, x, 1); + if (mpz_fits_sint_p (x)) + { + printf ("mpz_fits_sint_p (INT_MIN - 1) true!\n"); + abort (); + } + + mpz_clear (x); +} + +void +try_fits_sshort_p (void) +{ + mpz_t x; + mpz_init_set_si (x, SHRT_MAX); + if (!mpz_fits_sshort_p (x)) + { + printf ("mpz_fits_sshort_p (SHRT_MAX) false!\n"); + abort (); + } + mpz_add_ui (x, x, 1); + if (mpz_fits_sshort_p (x)) + { + printf ("mpz_fits_sshort_p (SHRT_MAX + 1) true!\n"); + abort (); + } + mpz_set_si (x, SHRT_MIN); + if (!mpz_fits_sshort_p (x)) + { + printf ("mpz_fits_sshort_p (SHRT_MIN) false!\n"); + abort (); + } + mpz_sub_ui (x, x, 1); + if (mpz_fits_sshort_p (x)) + { + printf ("mpz_fits_sshort_p (SHRT_MIN - 1) true!\n"); + abort (); + } + + mpz_clear (x); +} + +void +testmain (int argc, char *argv[]) +{ + try_fits_slong_p (); + try_fits_sint_p (); + try_fits_sshort_p (); + try_fits_utype_p (); + try_op_si (-1); + try_op_si (1); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-sqrt.c b/gmp-6.3.0/mini-gmp/tests/t-sqrt.c new file mode 100644 index 0000000..dd4c83a --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-sqrt.c @@ -0,0 +1,181 @@ +/* + +Copyright 2012, 2014, 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 +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 9000 + +/* Called when s is supposed to be floor(sqrt(u)), and r = u - s^2 */ +static int +sqrtrem_valid_p (const mpz_t u, const mpz_t s, const mpz_t r) +{ + mpz_t t; + + mpz_init (t); + mpz_mul (t, s, s); + mpz_sub (t, u, t); + if (mpz_sgn (t) < 0 || mpz_cmp (t, r) != 0) + { + mpz_clear (t); + return 0; + } + mpz_add_ui (t, s, 1); + mpz_mul (t, t, t); + if (mpz_cmp (t, u) <= 0) + { + mpz_clear (t); + return 0; + } + + mpz_clear (t); + return 1; +} + +void +mpz_mpn_sqrtrem (mpz_t s, mpz_t r, const mpz_t u) +{ + mp_limb_t *sp, *rp; + mp_size_t un, sn, ret; + + un = mpz_size (u); + + mpz_xor (s, s, u); + sn = (un + 1) / 2; + sp = mpz_limbs_write (s, sn + 1); + sp [sn] = 11; + + if (un & 1) + rp = NULL; /* Exploits the fact that r already is correct. */ + else { + mpz_add (r, u, s); + rp = mpz_limbs_write (r, un + 1); + rp [un] = 19; + } + + ret = mpn_sqrtrem (sp, rp, mpz_limbs_read (u), un); + + if (sp [sn] != 11) + { + fprintf (stderr, "mpn_sqrtrem buffer overrun on sp.\n"); + abort (); + } + if (un & 1) { + if ((ret != 0) != (mpz_size (r) != 0)) { + fprintf (stderr, "mpn_sqrtrem wrong return value with NULL.\n"); + abort (); + } + } else { + mpz_limbs_finish (r, ret); + if ((size_t) ret != mpz_size (r)) { + fprintf (stderr, "mpn_sqrtrem wrong return value.\n"); + abort (); + } + if (rp [un] != 19) + { + fprintf (stderr, "mpn_sqrtrem buffer overrun on rp.\n"); + abort (); + } + } + + mpz_limbs_finish (s, (un + 1) / 2); +} + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t u, s, r; + + mpz_init (s); + mpz_init (r); + + mpz_init_set_si (u, -1); + if (mpz_perfect_square_p (u)) + { + fprintf (stderr, "mpz_perfect_square_p failed on -1.\n"); + abort (); + } + + if (!mpz_perfect_square_p (s)) + { + fprintf (stderr, "mpz_perfect_square_p failed on 0.\n"); + abort (); + } + + for (i = 0; i < COUNT; i++) + { + mini_rrandomb (u, MAXBITS - (i & 0xFF)); + mpz_sqrtrem (s, r, u); + + if (!sqrtrem_valid_p (u, s, r)) + { + fprintf (stderr, "mpz_sqrtrem failed:\n"); + dump ("u", u); + dump ("sqrt", s); + dump ("rem", r); + abort (); + } + + mpz_mpn_sqrtrem (s, r, u); + + if (!sqrtrem_valid_p (u, s, r)) + { + fprintf (stderr, "mpn_sqrtrem failed:\n"); + dump ("u", u); + dump ("sqrt", s); + dump ("rem", r); + abort (); + } + + if (mpz_sgn (r) == 0) { + mpz_neg (u, u); + mpz_sub_ui (u, u, 1); + } + + if ((mpz_sgn (u) <= 0 || (i & 1)) ? + mpz_perfect_square_p (u) : + mpn_perfect_square_p (mpz_limbs_read (u), mpz_size (u))) + { + fprintf (stderr, "mp%s_perfect_square_p failed on non square:\n", + (mpz_sgn (u) <= 0 || (i & 1)) ? "z" : "n"); + dump ("u", u); + abort (); + } + + mpz_mul (u, s, s); + if (!((mpz_sgn (u) <= 0 || (i & 1)) ? + mpz_perfect_square_p (u) : + mpn_perfect_square_p (mpz_limbs_read (u), mpz_size (u)))) + { + fprintf (stderr, "mp%s_perfect_square_p failed on square:\n", + (mpz_sgn (u) <= 0 || (i & 1)) ? "z" : "n"); + dump ("u", u); + abort (); + } + + } + mpz_clear (u); + mpz_clear (s); + mpz_clear (r); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-str.c b/gmp-6.3.0/mini-gmp/tests/t-str.c new file mode 100644 index 0000000..d4dce1e --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-str.c @@ -0,0 +1,332 @@ +/* + +Copyright 2012-2014, 2016 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 +#include +#include +#include +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 2000 + +#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT) +#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS) + +static void +test_small (void) +{ + struct { + const char *input; + const char *decimal; + } data[] = { + { "183407", "183407" }, + { " 763959", "763959 " }, + { "9 81999", "981999" }, + { "10\t7398 ", "107398" }, + { "-9585 44", "-00958544" }, + { "-0", "0000" }, + { " -000 ", "0" }, + { "0704436", "231710" }, + /* Check the case of large number of leading zeros. */ + { "0000000000000000000000000", "0000000000000000000000000" }, + { "000000000000000000000000704436", "000000000000000000000000231710" }, + { " 02503517", "689999" }, + { "0 1312143", "365667" }, + { "-03 274062", "-882738" }, + { "012\t242", "005282" }, + { "0b11010111110010001111", "883855" }, + { " 0b11001010010100001", "103585" }, + { "-0b101010110011101111", "-175343" }, + { "0b 1111111011011100110", "521958" }, + { "0b1 1111110111001000011", "1044035" }, + { " 0x53dfc", "343548" }, + { "0xfA019", "1024025" }, + { "0x 642d1", "410321" }, + { "0x5 8067", "360551" }, + { "-0xd6Be6", "-879590" }, + { "\t0B1110000100000000011", "460803" }, + { "0B\t1111110010010100101", "517285" }, + { "0B1\t010111101101110100", "359284" }, + { "-0B101\t1001101111111001", "-367609" }, + { "0B10001001010111110000", "562672" }, + { "0Xe4B7e", "936830" }, + { "0X1E4bf", "124095" }, + { "-0Xfdb90", "-1039248" }, + { "0X7fc47", "523335" }, + { "0X8167c", "530044" }, + /* Some invalid inputs */ + { "", NULL }, + { "0x", NULL }, + { "0b", NULL }, + { "0z", NULL }, + { "-", NULL }, + { "-0x ", NULL }, + { "0|1", NULL }, + { "4+4", NULL }, + { "0ab", NULL }, + { "10x0", NULL }, + { "0xxab", NULL }, + { "ab", NULL }, + { "0%#", NULL }, + { "$foo", NULL }, + { NULL, NULL } + }; + unsigned i; + mpz_t a, b; + mpz_init (b); + + for (i = 0; data[i].input; i++) + { + int res = mpz_init_set_str (a, data[i].input, 0); + if (data[i].decimal) + { + if (res != 0) + { + fprintf (stderr, "mpz_set_str returned -1, input: %s\n", + data[i].input); + abort (); + } + if (mpz_set_str (b, data[i].decimal, 10) != 0) + { + fprintf (stderr, "mpz_set_str returned -1, decimal input: %s\n", + data[i].input); + abort (); + } + if (mpz_cmp (a, b) != 0) + { + fprintf (stderr, "mpz_set_str failed for input: %s\n", + data[i].input); + + dump ("got", a); + dump ("ref", b); + abort (); + } + } + else if (res != -1) + { + fprintf (stderr, "mpz_set_str returned %d, invalid input: %s\n", + res, data[i].input); + abort (); + } + mpz_clear (a); + } + + mpz_clear (b); +} + +void +testmain (int argc, char **argv) +{ + unsigned i; + char *ap; + char *bp; + char *rp; + size_t bn, rn, arn, bps; + + mpz_t a, b; + + FILE *tmp; + + test_small (); + + mpz_init (a); + mpz_init (b); + + tmp = tmpfile (); + if (!tmp) + fprintf (stderr, + "Failed to create temporary file. Skipping mpz_out_str tests.\n"); + + if (mpz_out_str (tmp, 63, a) != 0) + { + printf ("mpz_out_str did not return 0 (error) with base > 62\n"); + abort (); + } + + if (mpz_out_str (tmp, -37, a) != 0) + { + printf ("mpz_out_str did not return 0 (error) with base < -37\n"); + abort (); + } + + for (i = 0; i < COUNT; i++) + { + int base; + for (base = 0; base <= 62; base += 1 + (base == 0)) + { + hex_random_str_op (MAXBITS, (i&1 || base > 36) ? base: -base, &ap, &rp); + if (mpz_set_str (a, ap, 16) != 0) + { + fprintf (stderr, "mpz_set_str failed on input %s\n", ap); + abort (); + } + + rn = strlen (rp); + arn = rn - (rp[0] == '-'); + + bn = mpz_sizeinbase (a, base ? base : 10); + if (bn < arn || bn > (arn + 1)) + { + fprintf (stderr, "mpz_sizeinbase failed:\n"); + dump ("a", a); + fprintf (stderr, "r = %s\n", rp); + fprintf (stderr, " base %d, correct size %u, got %u\n", + base, (unsigned) arn, (unsigned)bn); + abort (); + } + bp = mpz_get_str (NULL, (i&1 || base > 36) ? base: -base, a); + bps = strlen(bp) + 1; + if (strcmp (bp, rp)) + { + fprintf (stderr, "mpz_get_str failed:\n"); + dump ("a", a); + fprintf (stderr, "b = %s\n", bp); + fprintf (stderr, " base = %d\n", base); + fprintf (stderr, "r = %s\n", rp); + abort (); + } + + /* Just a few tests with file i/o. */ + if (tmp && i < 20) + { + size_t tn; + rewind (tmp); + tn = mpz_out_str (tmp, (i&1 || base > 36) ? base: -base, a); + if (tn != rn) + { + fprintf (stderr, "mpz_out_str, bad return value:\n"); + dump ("a", a); + fprintf (stderr, "r = %s\n", rp); + fprintf (stderr, " base %d, correct size %u, got %u\n", + base, (unsigned) rn, (unsigned)tn); + abort (); + } + rewind (tmp); + memset (bp, 0, rn); + tn = fread (bp, 1, rn, tmp); + if (tn != rn) + { + fprintf (stderr, + "fread failed, expected %lu bytes, got only %lu.\n", + (unsigned long) rn, (unsigned long) tn); + abort (); + } + + if (memcmp (bp, rp, rn) != 0) + { + fprintf (stderr, "mpz_out_str failed:\n"); + dump ("a", a); + fprintf (stderr, "b = %s\n", bp); + fprintf (stderr, " base = %d\n", base); + fprintf (stderr, "r = %s\n", rp); + abort (); + } + } + + mpz_set_str (b, rp, base); + + if (mpz_cmp (a, b)) + { + fprintf (stderr, "mpz_set_str failed:\n"); + fprintf (stderr, "r = %s\n", rp); + fprintf (stderr, " base = %d\n", base); + fprintf (stderr, "r = %s\n", ap); + fprintf (stderr, " base = 16\n"); + dump ("b", b); + dump ("r", a); + abort (); + } + + /* Test mpn interface */ + if (base && mpz_sgn (a)) + { + size_t i; + const char *absr; + mp_limb_t t[MAXLIMBS]; + size_t tn = mpz_size (a); + + assert (tn <= MAXLIMBS); + mpn_copyi (t, a->_mp_d, tn); + + bn = mpn_get_str ((unsigned char *) bp, base, t, tn); + if (bn != arn) + { + fprintf (stderr, "mpn_get_str failed:\n"); + fprintf (stderr, "returned length: %lu (bad)\n", (unsigned long) bn); + fprintf (stderr, "expected: %lu\n", (unsigned long) arn); + fprintf (stderr, " base = %d\n", base); + fprintf (stderr, "r = %s\n", ap); + fprintf (stderr, " base = 16\n"); + dump ("b", b); + dump ("r", a); + abort (); + } + absr = rp + (rp[0] == '-'); + + for (i = 0; i < bn; i++) + { + unsigned char digit = absr[i]; + char value; + if (digit >= '0' && digit <= '9') + value = digit - '0'; + else if (digit >= 'a' && digit <= 'z') + value = digit - 'a' + ((base > 36) ? 36 : 10); + else if (digit >= 'A' && digit <= 'Z') + value = digit - 'A' + 10; + else + { + fprintf (stderr, "Internal error in test.\n"); + abort(); + } + if (bp[i] != value) + { + fprintf (stderr, "mpn_get_str failed:\n"); + fprintf (stderr, "digit %lu: %d (bad)\n", (unsigned long) i, bp[i]); + fprintf (stderr, "expected: %d\n", value); + fprintf (stderr, " base = %d\n", base); + fprintf (stderr, "r = %s\n", ap); + fprintf (stderr, " base = 16\n"); + dump ("b", b); + dump ("r", a); + abort (); + } + } + tn = mpn_set_str (t, (unsigned char *) bp, bn, base); + if (tn != mpz_size (a) || mpn_cmp (t, a->_mp_d, tn)) + { + fprintf (stderr, "mpn_set_str failed:\n"); + fprintf (stderr, "r = %s\n", rp); + fprintf (stderr, " base = %d\n", base); + fprintf (stderr, "r = %s\n", ap); + fprintf (stderr, " base = 16\n"); + dump ("r", a); + abort (); + } + } + free (ap); + free (rp); + testfree (bp, bps); + } + } + mpz_clear (a); + mpz_clear (b); +} diff --git a/gmp-6.3.0/mini-gmp/tests/t-sub.c b/gmp-6.3.0/mini-gmp/tests/t-sub.c new file mode 100644 index 0000000..e230fda --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/t-sub.c @@ -0,0 +1,71 @@ +/* + +Copyright 2012, 2013 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 +#include + +#include "testutils.h" + +#define MAXBITS 400 +#define COUNT 10000 + +void +testmain (int argc, char **argv) +{ + unsigned i; + mpz_t a, b, res, res_ui, ref; + + mpz_init (a); + mpz_init (b); + mpz_init (res); + mpz_init (res_ui); + mpz_init (ref); + + for (i = 0; i < COUNT; i++) + { + mini_random_op3 (OP_SUB, MAXBITS, a, b, ref); + mpz_sub (res, a, b); + if (mpz_cmp (res, ref)) + { + fprintf (stderr, "mpz_sub failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", res); + dump ("ref", ref); + abort (); + } + if (mpz_fits_ulong_p (a)) { + mpz_ui_sub (res_ui, mpz_get_ui (a), b); + if (mpz_cmp (res_ui, ref)) + { + fprintf (stderr, "mpz_ui_sub failed:\n"); + dump ("a", a); + dump ("b", b); + dump ("r", res_ui); + dump ("ref", ref); + abort (); + } + } + } + mpz_clear (a); + mpz_clear (b); + mpz_clear (res); + mpz_clear (res_ui); + mpz_clear (ref); +} diff --git a/gmp-6.3.0/mini-gmp/tests/testutils.c b/gmp-6.3.0/mini-gmp/tests/testutils.c new file mode 100644 index 0000000..46e368a --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/testutils.c @@ -0,0 +1,196 @@ +/* + +Copyright 2013-2015, 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 "testutils.h" + +/* 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; + +/* Custom memory allocation to track memory usage, and add a small red + zone. + + About alignment: In general, getting a block from malloc, and + incrementing it by sizeof(size_t), like we do here, might give a + pointer which is not properly aligned for all types. But the + largest type we allocate space for is unsigned long (mp_limb_t), + which shouldn't have stricter alignment requirements than + size_t. */ + +static unsigned char block_end[8] = + { 0x7c, 0x37, 0xd6, 0x12, 0xa8, 0x6c, 0x01, 0xd1 }; + +static void * +block_init (size_t *block, size_t size) +{ + char *p; + *block++ = size; + + p = (char *) block; + memcpy (p + size, block_end, sizeof(block_end)); + + total_alloc += size; + return p; +} + +/* Check small redzone, return pointer to malloced block. */ +static size_t * +block_check (void *p) +{ + size_t *block = (size_t *) p - 1; + size_t size = block[0]; + + if (memcmp ((char *)p + size, block_end, sizeof(block_end)) != 0) + { + fprintf (stderr, "red zone overwritten.\n"); + abort (); + } + total_alloc -= size; + return block; +} + +static void * +tu_alloc (size_t size) +{ + size_t *block = (size_t *) malloc (sizeof(size_t) + size + sizeof(block_end)); + if (!block) + { + fprintf (stderr, "Virtual memory exhausted.\n"); + abort (); + } + + return block_init (block, size); +} + +static void * +tu_realloc (void *p, size_t old_size, size_t new_size) +{ + size_t *block; + size_t *old_block = block_check (p); + if (old_block[0] != old_size) + { + fprintf (stderr, "%s:%d: bad old_size: want %ld, got %ld.\n", __FILE__, __LINE__, + (long)old_block[0], (long)old_size); + abort (); + } + + block = (size_t *) realloc (old_block, sizeof(size_t) + new_size + sizeof(block_end)); + if (!block) + { + fprintf (stderr, "Virtual memory exhausted.\n"); + abort (); + } + + return block_init (block, new_size); +} + +static void +tu_free (void *p, size_t old_size) +{ + size_t *old_block = block_check (p); + if (old_block[0] != old_size && old_size != 0) + { + fprintf (stderr, "%s:%d: bad old_size: want %ld, got %ld.\n", __FILE__, __LINE__, + (long)old_block[0], (long)old_size); + abort (); + } + free (old_block); +} + +/* Free memory allocated via mini-gmp allocation function. */ +void +testfree (void *p, size_t size) +{ + void (*freefunc) (void *, size_t); + mp_get_memory_functions (NULL, NULL, &freefunc); + + freefunc (p, size); +} + +int +main (int argc, char **argv) +{ + hex_random_init (); + + mp_set_memory_functions (tu_alloc, tu_realloc, tu_free); + + /* Currently, t-comb seems to be the only program accepting any + arguments. It might make sense to parse common arguments here. */ + testmain (argc, argv); + + if (total_alloc != 0) + { + fprintf (stderr, "Memory leaked: %lu bytes.\n", + (unsigned long) total_alloc); + abort (); + } + return 0; +} + +void +testhalves (int count, void (*tested_fun) (int)) +{ + void (*freefunc) (void *, size_t); + void *(*reallocfunc) (void *, size_t, size_t); + void *(*allocfunc) (size_t); + size_t initial_alloc; + + mp_get_memory_functions (&allocfunc, &reallocfunc, &freefunc); + initial_alloc = total_alloc; + (*tested_fun) (count / 2); + if (initial_alloc != total_alloc) + { + fprintf (stderr, "First half, memory leaked: %lu bytes.\n", + (unsigned long) total_alloc - initial_alloc); + abort (); + } + mp_set_memory_functions (NULL, NULL, NULL); + (*tested_fun) (count / 2); + mp_set_memory_functions (allocfunc, reallocfunc, freefunc); +} + +void +dump (const char *label, const mpz_t x) +{ + char *buf = mpz_get_str (NULL, 16, x); + fprintf (stderr, "%s: %s\n", label, buf); + testfree (buf, strlen(buf) + 1); +} + +void +mpz_set_str_or_abort (mpz_ptr z, const char *str, int base) +{ + if (mpz_set_str (z, str, base) != 0) + { + fprintf (stderr, "ERROR: mpz_set_str failed\n"); + fprintf (stderr, " str = \"%s\"\n", str); + fprintf (stderr, " base = %d\n", base); + abort(); + } +} + +int +mpz_lucas_mod (mpz_t V, mpz_t Qk, long Q, + mp_bitcnt_t b0, const mpz_t n) +{ + return gmp_lucas_mod (V, Qk, Q, b0, n); +} diff --git a/gmp-6.3.0/mini-gmp/tests/testutils.h b/gmp-6.3.0/mini-gmp/tests/testutils.h new file mode 100644 index 0000000..bcc08c5 --- /dev/null +++ b/gmp-6.3.0/mini-gmp/tests/testutils.h @@ -0,0 +1,42 @@ +/* + +Copyright 2013, 2014, 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 +#include + +#include "mini-random.h" + +#define numberof(x) (sizeof (x) / sizeof ((x)[0])) + +void testmain (int argc, char **argv); + +void testhalves (int count, void (*tested_fun) (int)); + +void testfree (void *p, size_t size); + +void +dump (const char *label, const mpz_t x); + +void +mpz_set_str_or_abort (mpz_ptr z, const char *str, int base); + +/* Prototype for wrappers to internal functions to be tested. */ +int +mpz_lucas_mod (mpz_t V, mpz_t Qk, long Q, + mp_bitcnt_t b0, const mpz_t n); -- cgit v1.2.3