blob: 64f90f4cfa81ee963e90ea8437540bd772635e24 [file] [log] [blame]
Austin Schuhdace2a62020-08-18 10:56:48 -07001/*
2
3Copyright 2012, Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
19
20#include <limits.h>
21#include <stdlib.h>
22#include <stdio.h>
23
24#include "testutils.h"
25
26#define MAXBITS 400
27#define COUNT 10000
28
29/* Called when g is supposed to be gcd(a,b), and g = s a + t b. */
30static int
31gcdext_valid_p (const mpz_t a, const mpz_t b,
32 const mpz_t g, const mpz_t s, const mpz_t t)
33{
34 mpz_t ta, tb, r;
35
36 /* It's not clear that gcd(0,0) is well defined, but we allow it and
37 require that gcd(0,0) = 0. */
38 if (mpz_sgn (g) < 0)
39 return 0;
40
41 if (mpz_sgn (a) == 0)
42 {
43 /* Must have g == abs (b). Any value for s is in some sense "correct",
44 but it makes sense to require that s == 0, t = sgn (b)*/
45 return mpz_cmpabs (g, b) == 0
46 && mpz_sgn (s) == 0 && mpz_cmp_si (t, mpz_sgn (b)) == 0;
47 }
48 else if (mpz_sgn (b) == 0)
49 {
50 /* Must have g == abs (a), s == sign (a), t = 0 */
51 return mpz_cmpabs (g, a) == 0
52 && mpz_cmp_si (s, mpz_sgn (a)) == 0 && mpz_sgn (t) == 0;
53 }
54
55 if (mpz_sgn (g) <= 0)
56 return 0;
57
58 mpz_init (ta);
59 mpz_init (tb);
60 mpz_init (r);
61
62 mpz_mul (ta, s, a);
63 mpz_mul (tb, t, b);
64 mpz_add (ta, ta, tb);
65
66 if (mpz_cmp (ta, g) != 0)
67 {
68 fail:
69 mpz_clear (ta);
70 mpz_clear (tb);
71 mpz_clear (r);
72 return 0;
73 }
74 mpz_tdiv_qr (ta, r, a, g);
75 if (mpz_sgn (r) != 0)
76 goto fail;
77
78 mpz_tdiv_qr (tb, r, b, g);
79 if (mpz_sgn (r) != 0)
80 goto fail;
81
82 /* Require that 2 |s| < |b/g|, or |s| == 1. */
83 if (mpz_cmpabs_ui (s, 1) > 0)
84 {
85 mpz_mul_2exp (r, s, 1);
86 if (mpz_cmpabs (r, tb) > 0)
87 goto fail;
88 }
89
90 /* Require that 2 |t| < |a/g| or |t| == 1*/
91 if (mpz_cmpabs_ui (t, 1) > 0)
92 {
93 mpz_mul_2exp (r, t, 1);
94 if (mpz_cmpabs (r, ta) > 0)
95 return 0;
96 }
97
98 mpz_clear (ta);
99 mpz_clear (tb);
100 mpz_clear (r);
101
102 return 1;
103}
104
105void
106testmain (int argc, char **argv)
107{
108 unsigned i;
109 mpz_t a, b, g, s, t;
110
111 mpz_init (a);
112 mpz_init (b);
113 mpz_init (g);
114 mpz_init (s);
115 mpz_init (t);
116
117 for (i = 0; i < COUNT; i++)
118 {
119 mini_random_op3 (OP_GCD, MAXBITS, a, b, s);
120 mpz_gcd (g, a, b);
121 if (mpz_cmp (g, s))
122 {
123 fprintf (stderr, "mpz_gcd failed:\n");
124 dump ("a", a);
125 dump ("b", b);
126 dump ("r", g);
127 dump ("ref", s);
128 abort ();
129 }
130 }
131
132 for (i = 0; i < COUNT; i++)
133 {
134 unsigned flags;
135 mini_urandomb (a, 32);
136 flags = mpz_get_ui (a);
137 mini_rrandomb (a, MAXBITS);
138 mini_rrandomb (b, MAXBITS);
139
140 if (flags % 37 == 0)
141 mpz_mul (a, a, b);
142 if (flags % 37 == 1)
143 mpz_mul (b, a, b);
144
145 if (flags & 1)
146 mpz_neg (a, a);
147 if (flags & 2)
148 mpz_neg (b, b);
149
150 mpz_gcdext (g, s, t, a, b);
151 if (!gcdext_valid_p (a, b, g, s, t))
152 {
153 fprintf (stderr, "mpz_gcdext failed:\n");
154 dump ("a", a);
155 dump ("b", b);
156 dump ("g", g);
157 dump ("s", s);
158 dump ("t", t);
159 abort ();
160 }
161
162 mpz_gcd (s, a, b);
163 if (mpz_cmp (g, s))
164 {
165 fprintf (stderr, "mpz_gcd failed:\n");
166 dump ("a", a);
167 dump ("b", b);
168 dump ("r", g);
169 dump ("ref", s);
170 abort ();
171 }
172 }
173 mpz_clear (a);
174 mpz_clear (b);
175 mpz_clear (g);
176 mpz_clear (s);
177 mpz_clear (t);
178}