Line | Count | Source (jump to first uncovered line) |
1 | | /* mpz/gcd.c: Calculate the greatest common divisor of two integers. |
2 | | |
3 | | Copyright 1991, 1993, 1994, 1996, 2000-2002, 2005, 2010, 2015, 2016 |
4 | | Free Software Foundation, Inc. |
5 | | |
6 | | This file is part of the GNU MP Library. |
7 | | |
8 | | The GNU MP Library is free software; you can redistribute it and/or modify |
9 | | it under the terms of either: |
10 | | |
11 | | * the GNU Lesser General Public License as published by the Free |
12 | | Software Foundation; either version 3 of the License, or (at your |
13 | | option) any later version. |
14 | | |
15 | | or |
16 | | |
17 | | * the GNU General Public License as published by the Free Software |
18 | | Foundation; either version 2 of the License, or (at your option) any |
19 | | later version. |
20 | | |
21 | | or both in parallel, as here. |
22 | | |
23 | | The GNU MP Library is distributed in the hope that it will be useful, but |
24 | | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
25 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
26 | | for more details. |
27 | | |
28 | | You should have received copies of the GNU General Public License and the |
29 | | GNU Lesser General Public License along with the GNU MP Library. If not, |
30 | | see https://www.gnu.org/licenses/. */ |
31 | | |
32 | | #include "gmp-impl.h" |
33 | | #include "longlong.h" |
34 | | |
35 | | |
36 | | void |
37 | | mpz_gcd (mpz_ptr g, mpz_srcptr u, mpz_srcptr v) |
38 | 0 | { |
39 | 0 | unsigned long int g_zero_bits, u_zero_bits, v_zero_bits; |
40 | 0 | mp_size_t g_zero_limbs, u_zero_limbs, v_zero_limbs; |
41 | 0 | mp_ptr tp; |
42 | 0 | mp_ptr up; |
43 | 0 | mp_size_t usize; |
44 | 0 | mp_ptr vp; |
45 | 0 | mp_size_t vsize; |
46 | 0 | mp_size_t gsize; |
47 | 0 | TMP_DECL; |
48 | |
|
49 | 0 | up = PTR(u); |
50 | 0 | usize = ABSIZ (u); |
51 | 0 | vp = PTR(v); |
52 | 0 | vsize = ABSIZ (v); |
53 | | /* GCD(0, V) == V. */ |
54 | 0 | if (usize == 0) |
55 | 0 | { |
56 | 0 | SIZ (g) = vsize; |
57 | 0 | if (g == v) |
58 | 0 | return; |
59 | 0 | tp = MPZ_NEWALLOC (g, vsize); |
60 | 0 | MPN_COPY (tp, vp, vsize); |
61 | 0 | return; |
62 | 0 | } |
63 | | |
64 | | /* GCD(U, 0) == U. */ |
65 | 0 | if (vsize == 0) |
66 | 0 | { |
67 | 0 | SIZ (g) = usize; |
68 | 0 | if (g == u) |
69 | 0 | return; |
70 | 0 | tp = MPZ_NEWALLOC (g, usize); |
71 | 0 | MPN_COPY (tp, up, usize); |
72 | 0 | return; |
73 | 0 | } |
74 | | |
75 | 0 | if (usize == 1) |
76 | 0 | { |
77 | 0 | SIZ (g) = 1; |
78 | 0 | MPZ_NEWALLOC (g, 1)[0] = mpn_gcd_1 (vp, vsize, up[0]); |
79 | 0 | return; |
80 | 0 | } |
81 | | |
82 | 0 | if (vsize == 1) |
83 | 0 | { |
84 | 0 | SIZ(g) = 1; |
85 | 0 | MPZ_NEWALLOC (g, 1)[0] = mpn_gcd_1 (up, usize, vp[0]); |
86 | 0 | return; |
87 | 0 | } |
88 | | |
89 | 0 | TMP_MARK; |
90 | | |
91 | | /* Eliminate low zero bits from U and V and move to temporary storage. */ |
92 | 0 | tp = up; |
93 | 0 | while (*tp == 0) |
94 | 0 | tp++; |
95 | 0 | u_zero_limbs = tp - up; |
96 | 0 | usize -= u_zero_limbs; |
97 | 0 | count_trailing_zeros (u_zero_bits, *tp); |
98 | 0 | up = TMP_ALLOC_LIMBS (usize); |
99 | 0 | if (u_zero_bits != 0) |
100 | 0 | { |
101 | 0 | mpn_rshift (up, tp, usize, u_zero_bits); |
102 | 0 | usize -= up[usize - 1] == 0; |
103 | 0 | } |
104 | 0 | else |
105 | 0 | MPN_COPY (up, tp, usize); |
106 | |
|
107 | 0 | tp = vp; |
108 | 0 | while (*tp == 0) |
109 | 0 | tp++; |
110 | 0 | v_zero_limbs = tp - vp; |
111 | 0 | vsize -= v_zero_limbs; |
112 | 0 | count_trailing_zeros (v_zero_bits, *tp); |
113 | 0 | vp = TMP_ALLOC_LIMBS (vsize); |
114 | 0 | if (v_zero_bits != 0) |
115 | 0 | { |
116 | 0 | mpn_rshift (vp, tp, vsize, v_zero_bits); |
117 | 0 | vsize -= vp[vsize - 1] == 0; |
118 | 0 | } |
119 | 0 | else |
120 | 0 | MPN_COPY (vp, tp, vsize); |
121 | |
|
122 | 0 | if (u_zero_limbs > v_zero_limbs) |
123 | 0 | { |
124 | 0 | g_zero_limbs = v_zero_limbs; |
125 | 0 | g_zero_bits = v_zero_bits; |
126 | 0 | } |
127 | 0 | else |
128 | 0 | { |
129 | 0 | g_zero_limbs = u_zero_limbs; |
130 | 0 | if (u_zero_limbs < v_zero_limbs) |
131 | 0 | g_zero_bits = u_zero_bits; |
132 | 0 | else /* Equal. */ |
133 | 0 | g_zero_bits = MIN (u_zero_bits, v_zero_bits); |
134 | 0 | } |
135 | | |
136 | | /* Call mpn_gcd. The 2nd argument must not have more bits than the 1st. */ |
137 | 0 | vsize = (usize < vsize || (usize == vsize && up[usize-1] < vp[vsize-1])) |
138 | 0 | ? mpn_gcd (vp, vp, vsize, up, usize) |
139 | 0 | : mpn_gcd (vp, up, usize, vp, vsize); |
140 | | |
141 | | /* Here G <-- V << (g_zero_limbs*GMP_LIMB_BITS + g_zero_bits). */ |
142 | 0 | gsize = vsize + g_zero_limbs; |
143 | 0 | if (g_zero_bits != 0) |
144 | 0 | { |
145 | 0 | mp_limb_t cy_limb; |
146 | 0 | gsize += (vp[vsize - 1] >> (GMP_NUMB_BITS - g_zero_bits)) != 0; |
147 | 0 | tp = MPZ_NEWALLOC (g, gsize); |
148 | 0 | MPN_ZERO (tp, g_zero_limbs); |
149 | |
|
150 | 0 | tp = tp + g_zero_limbs; |
151 | 0 | cy_limb = mpn_lshift (tp, vp, vsize, g_zero_bits); |
152 | 0 | if (cy_limb != 0) |
153 | 0 | tp[vsize] = cy_limb; |
154 | 0 | } |
155 | 0 | else |
156 | 0 | { |
157 | 0 | tp = MPZ_NEWALLOC (g, gsize); |
158 | 0 | MPN_ZERO (tp, g_zero_limbs); |
159 | 0 | MPN_COPY (tp + g_zero_limbs, vp, vsize); |
160 | 0 | } |
161 | |
|
162 | 0 | SIZ (g) = gsize; |
163 | 0 | TMP_FREE; |
164 | 0 | } |