1 /* Test mpz_[cft]div_[qr]_2exp.
2
3 Copyright 2001 Free Software Foundation, Inc.
4
5 This file is part of the GNU MP Library test suite.
6
7 The GNU MP Library test suite is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11
12 The GNU MP Library test suite is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 Public License for more details.
16
17 You should have received a copy of the GNU General Public License along with
18 the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #include "gmp-impl.h"
24 #include "tests.h"
25
26
27 /* If the remainder is in the correct range and q*d+r is correct, then q
28 must have rounded correctly. */
29
30 void
31 check_one (mpz_srcptr a, unsigned long d)
32 {
33 mpz_t q, r, p, d2exp;
34 int inplace;
35
36 mpz_init (d2exp);
37 mpz_init (q);
38 mpz_init (r);
39 mpz_init (p);
40
41 mpz_set_ui (d2exp, 1L);
42 mpz_mul_2exp (d2exp, d2exp, d);
43
44 #define INPLACE(fun,dst,src,d) \
45 if (inplace) \
46 { \
47 mpz_set (dst, src); \
48 fun (dst, dst, d); \
49 } \
50 else \
51 fun (dst, src, d);
52
53 for (inplace = 0; inplace <= 1; inplace++)
54 {
55 INPLACE (mpz_fdiv_q_2exp, q, a, d);
56 INPLACE (mpz_fdiv_r_2exp, r, a, d);
57
58 mpz_mul_2exp (p, q, d);
59 mpz_add (p, p, r);
60 if (mpz_sgn (r) < 0 || mpz_cmp (r, d2exp) >= 0)
61 {
62 printf ("mpz_fdiv_r_2exp result out of range\n");
63 goto error;
64 }
65 if (mpz_cmp (p, a) != 0)
66 {
67 printf ("mpz_fdiv_[qr]_2exp doesn't multiply back\n");
68 goto error;
69 }
70
71
72 INPLACE (mpz_cdiv_q_2exp, q, a, d);
73 INPLACE (mpz_cdiv_r_2exp, r, a, d);
74
75 mpz_mul_2exp (p, q, d);
76 mpz_add (p, p, r);
77 if (mpz_sgn (r) > 0 || mpz_cmpabs (r, d2exp) >= 0)
78 {
79 printf ("mpz_cdiv_r_2exp result out of range\n");
80 goto error;
81 }
82 if (mpz_cmp (p, a) != 0)
83 {
84 printf ("mpz_cdiv_[qr]_2exp doesn't multiply back\n");
85 goto error;
86 }
87
88
89 INPLACE (mpz_tdiv_q_2exp, q, a, d);
90 INPLACE (mpz_tdiv_r_2exp, r, a, d);
91
92 mpz_mul_2exp (p, q, d);
93 mpz_add (p, p, r);
94 if (mpz_sgn (r) != 0 && mpz_sgn (r) != mpz_sgn (a))
95 {
96 printf ("mpz_tdiv_r_2exp result wrong sign\n");
97 goto error;
98 }
99 if (mpz_cmpabs (r, d2exp) >= 0)
100 {
101 printf ("mpz_tdiv_r_2exp result out of range\n");
102 goto error;
103 }
104 if (mpz_cmp (p, a) != 0)
105 {
106 printf ("mpz_tdiv_[qr]_2exp doesn't multiply back\n");
107 goto error;
108 }
109 }
110
111 mpz_clear (d2exp);
112 mpz_clear (q);
113 mpz_clear (r);
114 mpz_clear (p);
115 return;
116
117
118 error:
119 mpz_trace ("a", a);
120 printf ("d=%lu\n", d);
121 mpz_trace ("q", q);
122 mpz_trace ("r", r);
123 mpz_trace ("p", p);
124
125 mp_trace_base = -16;
126 mpz_trace ("a", a);
127 printf ("d=0x%lX\n", d);
128 mpz_trace ("q", q);
129 mpz_trace ("r", r);
130 mpz_trace ("p", p);
131
132 abort ();
133 }
134
135
136 void
137 check_all (mpz_ptr a, unsigned long d)
138 {
139 check_one (a, d);
140 mpz_neg (a, a);
141 check_one (a, d);
142 }
143
144
145 void
146 check_various (void)
147 {
148 static const unsigned long table[] = {
149 0, 1, 2, 3, 4, 5,
150 GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
151 2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
152 3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1,
153 4*GMP_NUMB_BITS-1, 4*GMP_NUMB_BITS, 4*GMP_NUMB_BITS+1
154 };
155
156 int i, j;
157 unsigned long n, d;
158 mpz_t a;
159
160 mpz_init (a);
161
162 /* a==0, and various d */
163 mpz_set_ui (a, 0L);
164 for (i = 0; i < numberof (table); i++)
165 check_one (a, table[i]);
166
167 /* a==2^n, and various d */
168 for (i = 0; i < numberof (table); i++)
169 {
170 n = table[i];
171 mpz_set_ui (a, 1L);
172 mpz_mul_2exp (a, a, n);
173
174 for (j = 0; j < numberof (table); j++)
175 {
176 d = table[j];
177 check_all (a, d);
178 }
179 }
180
181 mpz_clear (a);
182 }
183
184
185 void
186 check_random (int argc, char *argv[])
187 {
188 gmp_randstate_ptr rands = RANDS;
189 int reps = 100;
190 mpz_t a;
191 unsigned long d;
192 int i;
193
194 if (argc == 2)
195 reps = atoi (argv[1]);
196
197 mpz_init (a);
198
199 for (i = 0; i < reps; i++)
200 {
201 /* exponentially within 2 to 257 bits */
202 mpz_erandomb (a, rands, urandom () % 8 + 2);
203
204 d = urandom () % 256;
205
206 check_all (a, d);
207 }
208
209 mpz_clear (a);
210 }
211
212
213 int
214 main (int argc, char *argv[])
215 {
216 tests_start ();
217
218 check_various ();
219 check_random (argc, argv);
220
221 tests_end ();
222 exit (0);
223 }