Austin Schuh | bb1338c | 2024-06-15 19:31:16 -0700 | [diff] [blame] | 1 | /* mpz_gcdext(g, s, t, a, b) -- Set G to gcd(a, b), and S and T such that |
| 2 | g = as + bt. |
| 3 | |
| 4 | Copyright 1991, 1993-1997, 2000, 2001, 2005, 2011, 2012, 2015 Free |
| 5 | Software Foundation, Inc. |
| 6 | |
| 7 | This file is part of the GNU MP Library. |
| 8 | |
| 9 | The GNU MP Library is free software; you can redistribute it and/or modify |
| 10 | it under the terms of either: |
| 11 | |
| 12 | * the GNU Lesser General Public License as published by the Free |
| 13 | Software Foundation; either version 3 of the License, or (at your |
| 14 | option) any later version. |
| 15 | |
| 16 | or |
| 17 | |
| 18 | * the GNU General Public License as published by the Free Software |
| 19 | Foundation; either version 2 of the License, or (at your option) any |
| 20 | later version. |
| 21 | |
| 22 | or both in parallel, as here. |
| 23 | |
| 24 | The GNU MP Library is distributed in the hope that it will be useful, but |
| 25 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 26 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 27 | for more details. |
| 28 | |
| 29 | You should have received copies of the GNU General Public License and the |
| 30 | GNU Lesser General Public License along with the GNU MP Library. If not, |
| 31 | see https://www.gnu.org/licenses/. */ |
| 32 | |
| 33 | #include <stdio.h> /* for NULL */ |
| 34 | #include "gmp-impl.h" |
| 35 | |
| 36 | void |
| 37 | mpz_gcdext (mpz_ptr g, mpz_ptr s, mpz_ptr t, mpz_srcptr a, mpz_srcptr b) |
| 38 | { |
| 39 | mp_size_t asize, bsize; |
| 40 | mp_ptr tmp_ap, tmp_bp; |
| 41 | mp_size_t gsize, ssize, tmp_ssize; |
| 42 | mp_ptr gp, tmp_gp, tmp_sp; |
| 43 | TMP_DECL; |
| 44 | |
| 45 | /* mpn_gcdext requires that Usize >= Vsize. Therefore, we often |
| 46 | have to swap U and V. The computed cofactor will be the |
| 47 | "smallest" one, which is faster to produce. The wanted one will |
| 48 | be computed here; this is needed anyway when both are requested. */ |
| 49 | |
| 50 | asize = ABSIZ (a); |
| 51 | bsize = ABSIZ (b); |
| 52 | |
| 53 | ASSERT (s != NULL); |
| 54 | |
| 55 | if (asize < bsize) |
| 56 | { |
| 57 | MPZ_SRCPTR_SWAP (a, b); |
| 58 | MP_SIZE_T_SWAP (asize, bsize); |
| 59 | MPZ_PTR_SWAP (s, t); |
| 60 | } |
| 61 | |
| 62 | if (bsize == 0) |
| 63 | { |
| 64 | /* g = |a|, s = sgn(a), t = 0. */ |
| 65 | ssize = SIZ (a) >= 0 ? (asize != 0) : -1; |
| 66 | |
| 67 | if (g != NULL) |
| 68 | { |
| 69 | /* If g == a, then ALLOC(g) == ALLOC(a) >= asize, i.e. |
| 70 | the next MPZ_NEWALLOC returns the old PTR(a) .*/ |
| 71 | gp = MPZ_NEWALLOC (g, asize); |
| 72 | MPN_COPY (gp, PTR (a), asize); |
| 73 | SIZ (g) = asize; |
| 74 | } |
| 75 | if (t != NULL) |
| 76 | SIZ (t) = 0; |
| 77 | if (s != NULL) |
| 78 | { |
| 79 | SIZ (s) = ssize; |
| 80 | MPZ_NEWALLOC (s, 1)[0] = 1; |
| 81 | } |
| 82 | return; |
| 83 | } |
| 84 | |
| 85 | TMP_MARK; |
| 86 | |
| 87 | TMP_ALLOC_LIMBS_2 (tmp_gp, bsize, tmp_sp, asize + bsize + bsize + 1); |
| 88 | tmp_bp = tmp_sp + bsize + 1; |
| 89 | tmp_ap = tmp_bp + bsize; |
| 90 | MPN_COPY (tmp_ap, PTR (a), asize); |
| 91 | MPN_COPY (tmp_bp, PTR (b), bsize); |
| 92 | |
| 93 | gsize = mpn_gcdext (tmp_gp, tmp_sp, &tmp_ssize, tmp_ap, asize, tmp_bp, bsize); |
| 94 | |
| 95 | ssize = ABS (tmp_ssize); |
| 96 | tmp_ssize = SIZ (a) >= 0 ? tmp_ssize : -tmp_ssize; |
| 97 | |
| 98 | if (t != NULL) |
| 99 | { |
| 100 | mpz_t x; |
| 101 | mpz_t gtmp, stmp; |
| 102 | |
| 103 | PTR (gtmp) = tmp_gp; |
| 104 | SIZ (gtmp) = gsize; |
| 105 | |
| 106 | PTR (stmp) = tmp_sp; |
| 107 | SIZ (stmp) = tmp_ssize; |
| 108 | |
| 109 | ASSERT (ssize <= bsize); /* ssize*2 + asize + 1 <= asize + bsize*2 + 1 */ |
| 110 | PTR (x) = tmp_sp + ssize; |
| 111 | ALLOC (x) = ssize + asize + 1; |
| 112 | |
| 113 | mpz_mul (x, stmp, a); |
| 114 | mpz_sub (x, gtmp, x); |
| 115 | mpz_divexact (t, x, b); |
| 116 | } |
| 117 | |
| 118 | if (s != NULL) |
| 119 | { |
| 120 | mp_ptr sp; |
| 121 | |
| 122 | sp = MPZ_NEWALLOC (s, ssize); |
| 123 | MPN_COPY (sp, tmp_sp, ssize); |
| 124 | SIZ (s) = tmp_ssize; |
| 125 | } |
| 126 | |
| 127 | if (g != NULL) |
| 128 | { |
| 129 | gp = MPZ_NEWALLOC (g, gsize); |
| 130 | MPN_COPY (gp, tmp_gp, gsize); |
| 131 | SIZ (g) = gsize; |
| 132 | } |
| 133 | |
| 134 | TMP_FREE; |
| 135 | } |