1 /* Test mpz_gcd, mpz_gcdext, and mpz_gcd_ui.
3 Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2002, 2003, 2004 Free
4 Software Foundation, Inc.
6 This file is part of the GNU MP Library.
8 The GNU MP Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
13 The GNU MP Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
28 static mp_size_t one_test __GMP_PROTO ((mpz_t, mpz_t, int));
29 static void debug_mp __GMP_PROTO ((mpz_t, int));
31 #define MIN_OPERAND_SIZE 2
33 /* Fixed values, for regression testing of mpn_hgcd. */
34 struct value { int res; const char *a; const char *b; };
35 static const struct value hgcd_values[] = {
36 #if GMP_NUMB_BITS == 32
38 "0x1bddff867272a9296ac493c251d7f46f09a5591fe",
39 "0xb55930a2a68a916450a7de006031068c5ddb0e5c" },
41 "0x2f0ece5b1ee9c15e132a01d55768dc13",
42 "0x1c6f4fd9873cdb24466e6d03e1cc66e7" },
43 { 3, "0x7FFFFC003FFFFFFFFFC5", "0x3FFFFE001FFFFFFFFFE3"},
53 static void hgcd_ref_init __GMP_PROTO ((struct hgcd_ref *hgcd));
54 static void hgcd_ref_clear __GMP_PROTO ((struct hgcd_ref *hgcd));
55 static int hgcd_ref __GMP_PROTO ((struct hgcd_ref *hgcd, mpz_t a, mpz_t b));
56 static int hgcd_ref_equal __GMP_PROTO ((const struct hgcd_matrix *hgcd, const struct hgcd_ref *ref));
59 main (int argc, char **argv)
61 mpz_t op1, op2, temp1, temp2;
63 gmp_randstate_ptr rands;
65 unsigned long size_range;
76 for (i = 0; hgcd_values[i].res >= 0; i++)
80 mpz_set_str (op1, hgcd_values[i].a, 0);
81 mpz_set_str (op2, hgcd_values[i].b, 0);
83 res = one_test (op1, op2, -1-i);
84 if (res != hgcd_values[i].res)
86 fprintf (stderr, "ERROR in test %d\n", -1-i);
87 fprintf (stderr, "Bad return code from hgcd\n");
88 fprintf (stderr, "op1="); debug_mp (op1, -16);
89 fprintf (stderr, "op2="); debug_mp (op2, -16);
90 fprintf (stderr, "expected: %d\n", hgcd_values[i].res);
91 fprintf (stderr, "hgcd: %d\n", (int) res);
96 for (i = 0; i < 15; i++)
98 /* Generate plain operands with unknown gcd. These types of operands
99 have proven to trigger certain bugs in development versions of the
100 gcd code. The "hgcd->row[3].rsize > M" ASSERT is not triggered by
101 the division chain code below, but that is most likely just a result
102 of that other ASSERTs are triggered before it. */
104 mpz_urandomb (bs, rands, 32);
105 size_range = mpz_get_ui (bs) % 13 + 2;
107 mpz_urandomb (bs, rands, size_range);
108 mpz_urandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
109 mpz_urandomb (bs, rands, size_range);
110 mpz_urandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
112 if (mpz_cmp (op1, op2) < 0)
115 if (mpz_size (op1) > 0)
116 one_test (op1, op2, i);
118 /* Generate a division chain backwards, allowing otherwise
119 unlikely huge quotients. */
122 mpz_urandomb (bs, rands, 32);
123 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 16 + 1);
124 mpz_rrandomb (op2, rands, mpz_get_ui (bs));
125 mpz_add_ui (op2, op2, 1);
130 mpz_urandomb (bs, rands, 32);
131 chain_len = mpz_get_ui (bs) % (GMP_NUMB_BITS * GCD_DC_THRESHOLD / 256);
134 for (j = 0; j < chain_len; j++)
136 mpz_urandomb (bs, rands, 32);
137 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
138 mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
139 mpz_add_ui (temp2, temp2, 1);
140 mpz_mul (temp1, op2, temp2);
141 mpz_add (op1, op1, temp1);
143 /* Don't generate overly huge operands. */
144 if (SIZ (op1) > 3 * GCD_DC_THRESHOLD)
147 mpz_urandomb (bs, rands, 32);
148 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
149 mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
150 mpz_add_ui (temp2, temp2, 1);
151 mpz_mul (temp1, op1, temp2);
152 mpz_add (op2, op2, temp1);
154 /* Don't generate overly huge operands. */
155 if (SIZ (op2) > 3 * GCD_DC_THRESHOLD)
158 if (mpz_cmp (op1, op2) < 0)
161 if (mpz_size (op1) > 0)
162 one_test (op1, op2, i);
176 debug_mp (mpz_t x, int base)
178 mpz_out_str (stderr, base, x); fputc ('\n', stderr);
182 mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize);
185 one_test (mpz_t a, mpz_t b, int i)
187 struct hgcd_matrix hgcd;
199 mp_size_t hgcd_init_scratch;
200 mp_size_t hgcd_scratch;
208 ASSERT (asize >= bsize);
210 hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize);
211 hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch);
212 mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp);
214 hgcd_scratch = mpn_hgcd_itch (asize);
215 hgcd_tp = refmpn_malloc_limbs (hgcd_scratch);
219 "one_test: i = %d asize = %d, bsize = %d\n",
220 i, a->_mp_size, b->_mp_size);
228 hgcd_ref_init (&ref);
230 mpz_init_set (ref_r0, a);
231 mpz_init_set (ref_r1, b);
232 res[0] = hgcd_ref (&ref, ref_r0, ref_r1);
234 mpz_init_set (hgcd_r0, a);
235 mpz_init_set (hgcd_r1, b);
238 _mpz_realloc (hgcd_r1, asize);
239 MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize);
241 res[1] = mpn_hgcd (hgcd_r0->_mp_d,
246 if (res[0] != res[1])
248 fprintf (stderr, "ERROR in test %d\n", i);
249 fprintf (stderr, "Different return value from hgcd and hgcd_ref\n");
250 fprintf (stderr, "op1="); debug_mp (a, -16);
251 fprintf (stderr, "op2="); debug_mp (b, -16);
252 fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]);
253 fprintf (stderr, "mpn_hgcd: %ld\n", (long) res[1]);
258 if (!hgcd_ref_equal (&hgcd, &ref)
259 || !mpz_mpn_equal (ref_r0, hgcd_r0->_mp_d, res[1])
260 || !mpz_mpn_equal (ref_r1, hgcd_r1->_mp_d, res[1]))
262 fprintf (stderr, "ERROR in test %d\n", i);
263 fprintf (stderr, "mpn_hgcd and hgcd_ref returned different values\n");
264 fprintf (stderr, "op1="); debug_mp (a, -16);
265 fprintf (stderr, "op2="); debug_mp (b, -16);
270 refmpn_free_limbs (hgcd_init_tp);
271 refmpn_free_limbs (hgcd_tp);
272 hgcd_ref_clear (&ref);
282 hgcd_ref_init (struct hgcd_ref *hgcd)
285 for (i = 0; i<2; i++)
288 for (j = 0; j<2; j++)
289 mpz_init (hgcd->m[i][j]);
294 hgcd_ref_clear (struct hgcd_ref *hgcd)
297 for (i = 0; i<2; i++)
300 for (j = 0; j<2; j++)
301 mpz_clear (hgcd->m[i][j]);
307 sdiv_qr (mpz_t q, mpz_t r, mp_size_t s, const mpz_t a, const mpz_t b)
309 mpz_fdiv_qr (q, r, a, b);
310 if (mpz_size (r) <= s)
313 mpz_sub_ui (q, q, 1);
316 return (mpz_sgn (q) > 0);
320 hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b)
322 mp_size_t n = MAX (mpz_size (a), mpz_size (b));
323 mp_size_t s = n/2 + 1;
329 if (mpz_size (a) <= s || mpz_size (b) <= s)
332 res = mpz_cmp (a, b);
336 if (mpz_size (b) <= s)
339 mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 0);
340 mpz_set_ui (hgcd->m[1][0], 1); mpz_set_ui (hgcd->m[1][1], 1);
345 if (mpz_size (a) <= s)
348 mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 1);
349 mpz_set_ui (hgcd->m[1][0], 0); mpz_set_ui (hgcd->m[1][1], 1);
358 ASSERT (mpz_size (a) > s);
359 ASSERT (mpz_size (b) > s);
361 if (mpz_cmp (a, b) > 0)
363 if (!sdiv_qr (q, a, s, a, b))
365 mpz_addmul (hgcd->m[0][1], q, hgcd->m[0][0]);
366 mpz_addmul (hgcd->m[1][1], q, hgcd->m[1][0]);
370 if (!sdiv_qr (q, b, s, b, a))
372 mpz_addmul (hgcd->m[0][0], q, hgcd->m[0][1]);
373 mpz_addmul (hgcd->m[1][0], q, hgcd->m[1][1]);
379 asize = mpz_size (a);
380 bsize = mpz_size (b);
381 return MAX (asize, bsize);
385 mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize)
387 mp_srcptr ap = a->_mp_d;
388 mp_size_t asize = a->_mp_size;
390 MPN_NORMALIZE (bp, bsize);
391 return asize == bsize && mpn_cmp (ap, bp, asize) == 0;
395 hgcd_ref_equal (const struct hgcd_matrix *hgcd, const struct hgcd_ref *ref)
399 for (i = 0; i<2; i++)
403 for (j = 0; j<2; j++)
404 if (!mpz_mpn_equal (ref->m[i][j], hgcd->p[i][j], hgcd->n))