3 Copyright 1991, 1993, 1994, 1996, 1997, 2000-2004 Free Software Foundation,
6 This file is part of the GNU MP Library test suite.
8 The GNU MP Library test suite is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 3 of the License,
11 or (at your option) any later version.
13 The GNU MP Library test suite is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16 Public License for more details.
18 You should have received a copy of the GNU General Public License along with
19 the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
28 static mp_size_t one_test (mpz_t, mpz_t, int);
29 static void debug_mp (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 (struct hgcd_ref *);
54 static void hgcd_ref_clear (struct hgcd_ref *);
55 static int hgcd_ref (struct hgcd_ref *, mpz_t, mpz_t);
56 static int hgcd_ref_equal (const struct hgcd_matrix *, const struct hgcd_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
102 mpz_urandomb (bs, rands, 32);
103 size_range = mpz_get_ui (bs) % 13 + 2;
105 mpz_urandomb (bs, rands, size_range);
106 mpz_rrandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
107 mpz_urandomb (bs, rands, size_range);
108 mpz_rrandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
110 if (mpz_cmp (op1, op2) < 0)
113 if (mpz_size (op1) > 0)
114 one_test (op1, op2, i);
116 /* Generate a division chain backwards, allowing otherwise
117 unlikely huge quotients. */
120 mpz_urandomb (bs, rands, 32);
121 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 16 + 1);
122 mpz_rrandomb (op2, rands, mpz_get_ui (bs));
123 mpz_add_ui (op2, op2, 1);
128 mpz_urandomb (bs, rands, 32);
129 chain_len = mpz_get_ui (bs) % (GMP_NUMB_BITS * GCD_DC_THRESHOLD / 256);
132 for (j = 0; j < chain_len; j++)
134 mpz_urandomb (bs, rands, 32);
135 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
136 mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
137 mpz_add_ui (temp2, temp2, 1);
138 mpz_mul (temp1, op2, temp2);
139 mpz_add (op1, op1, temp1);
141 /* Don't generate overly huge operands. */
142 if (SIZ (op1) > 3 * GCD_DC_THRESHOLD)
145 mpz_urandomb (bs, rands, 32);
146 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
147 mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
148 mpz_add_ui (temp2, temp2, 1);
149 mpz_mul (temp1, op1, temp2);
150 mpz_add (op2, op2, temp1);
152 /* Don't generate overly huge operands. */
153 if (SIZ (op2) > 3 * GCD_DC_THRESHOLD)
156 if (mpz_cmp (op1, op2) < 0)
159 if (mpz_size (op1) > 0)
160 one_test (op1, op2, i);
174 debug_mp (mpz_t x, int base)
176 mpz_out_str (stderr, base, x); fputc ('\n', stderr);
180 mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize);
183 one_test (mpz_t a, mpz_t b, int i)
185 struct hgcd_matrix hgcd;
197 mp_size_t hgcd_init_scratch;
198 mp_size_t hgcd_scratch;
206 ASSERT (asize >= bsize);
208 hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize);
209 hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch);
210 mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp);
212 hgcd_scratch = mpn_hgcd_itch (asize);
213 hgcd_tp = refmpn_malloc_limbs (hgcd_scratch);
217 "one_test: i = %d asize = %d, bsize = %d\n",
218 i, a->_mp_size, b->_mp_size);
226 hgcd_ref_init (&ref);
228 mpz_init_set (ref_r0, a);
229 mpz_init_set (ref_r1, b);
230 res[0] = hgcd_ref (&ref, ref_r0, ref_r1);
232 mpz_init_set (hgcd_r0, a);
233 mpz_init_set (hgcd_r1, b);
236 _mpz_realloc (hgcd_r1, asize);
237 MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize);
239 res[1] = mpn_hgcd (hgcd_r0->_mp_d,
244 if (res[0] != res[1])
246 fprintf (stderr, "ERROR in test %d\n", i);
247 fprintf (stderr, "Different return value from hgcd and hgcd_ref\n");
248 fprintf (stderr, "op1="); debug_mp (a, -16);
249 fprintf (stderr, "op2="); debug_mp (b, -16);
250 fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]);
251 fprintf (stderr, "mpn_hgcd: %ld\n", (long) res[1]);
256 if (!hgcd_ref_equal (&hgcd, &ref)
257 || !mpz_mpn_equal (ref_r0, hgcd_r0->_mp_d, res[1])
258 || !mpz_mpn_equal (ref_r1, hgcd_r1->_mp_d, res[1]))
260 fprintf (stderr, "ERROR in test %d\n", i);
261 fprintf (stderr, "mpn_hgcd and hgcd_ref returned different values\n");
262 fprintf (stderr, "op1="); debug_mp (a, -16);
263 fprintf (stderr, "op2="); debug_mp (b, -16);
268 refmpn_free_limbs (hgcd_init_tp);
269 refmpn_free_limbs (hgcd_tp);
270 hgcd_ref_clear (&ref);
280 hgcd_ref_init (struct hgcd_ref *hgcd)
283 for (i = 0; i<2; i++)
286 for (j = 0; j<2; j++)
287 mpz_init (hgcd->m[i][j]);
292 hgcd_ref_clear (struct hgcd_ref *hgcd)
295 for (i = 0; i<2; i++)
298 for (j = 0; j<2; j++)
299 mpz_clear (hgcd->m[i][j]);
305 sdiv_qr (mpz_t q, mpz_t r, mp_size_t s, const mpz_t a, const mpz_t b)
307 mpz_fdiv_qr (q, r, a, b);
308 if (mpz_size (r) <= s)
311 mpz_sub_ui (q, q, 1);
314 return (mpz_sgn (q) > 0);
318 hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b)
320 mp_size_t n = MAX (mpz_size (a), mpz_size (b));
321 mp_size_t s = n/2 + 1;
327 if (mpz_size (a) <= s || mpz_size (b) <= s)
330 res = mpz_cmp (a, b);
334 if (mpz_size (b) <= s)
337 mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 0);
338 mpz_set_ui (hgcd->m[1][0], 1); mpz_set_ui (hgcd->m[1][1], 1);
343 if (mpz_size (a) <= s)
346 mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 1);
347 mpz_set_ui (hgcd->m[1][0], 0); mpz_set_ui (hgcd->m[1][1], 1);
356 ASSERT (mpz_size (a) > s);
357 ASSERT (mpz_size (b) > s);
359 if (mpz_cmp (a, b) > 0)
361 if (!sdiv_qr (q, a, s, a, b))
363 mpz_addmul (hgcd->m[0][1], q, hgcd->m[0][0]);
364 mpz_addmul (hgcd->m[1][1], q, hgcd->m[1][0]);
368 if (!sdiv_qr (q, b, s, b, a))
370 mpz_addmul (hgcd->m[0][0], q, hgcd->m[0][1]);
371 mpz_addmul (hgcd->m[1][0], q, hgcd->m[1][1]);
377 asize = mpz_size (a);
378 bsize = mpz_size (b);
379 return MAX (asize, bsize);
383 mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize)
385 mp_srcptr ap = a->_mp_d;
386 mp_size_t asize = a->_mp_size;
388 MPN_NORMALIZE (bp, bsize);
389 return asize == bsize && mpn_cmp (ap, bp, asize) == 0;
393 hgcd_ref_equal (const struct hgcd_matrix *hgcd, const struct hgcd_ref *ref)
397 for (i = 0; i<2; i++)
401 for (j = 0; j<2; j++)
402 if (!mpz_mpn_equal (ref->m[i][j], hgcd->p[i][j], hgcd->n))