blob: 1faa2e84ada621a2fddd3fef3f52a4c0aa219932 [file] [log] [blame]
Austin Schuhbb1338c2024-06-15 19:31:16 -07001/* Exercise mpz_bin_ui and mpz_bin_uiui.
2
3Copyright 2000, 2001, 2010, 2012, 2018 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 <stdio.h>
21#include <stdlib.h>
22#include "gmp-impl.h"
23#include "tests.h"
24
25/* Default number of generated tests. */
26#define COUNT 700
27
28void
29try_mpz_bin_ui (mpz_srcptr want, mpz_srcptr n, unsigned long k)
30{
31 mpz_t got;
32
33 mpz_init (got);
34 mpz_bin_ui (got, n, k);
35 MPZ_CHECK_FORMAT (got);
36 if (mpz_cmp (got, want) != 0)
37 {
38 printf ("mpz_bin_ui wrong\n");
39 printf (" n="); mpz_out_str (stdout, 10, n); printf ("\n");
40 printf (" k=%lu\n", k);
41 printf (" got="); mpz_out_str (stdout, 10, got); printf ("\n");
42 printf (" want="); mpz_out_str (stdout, 10, want); printf ("\n");
43 abort();
44 }
45 mpz_clear (got);
46}
47
48
49void
50try_mpz_bin_uiui (mpz_srcptr want, unsigned long n, unsigned long k)
51{
52 mpz_t got;
53
54 mpz_init (got);
55 mpz_bin_uiui (got, n, k);
56 MPZ_CHECK_FORMAT (got);
57 if (mpz_cmp (got, want) != 0)
58 {
59 printf ("mpz_bin_uiui wrong\n");
60 printf (" n=%lu\n", n);
61 printf (" k=%lu\n", k);
62 printf (" got="); mpz_out_str (stdout, 10, got); printf ("\n");
63 printf (" want="); mpz_out_str (stdout, 10, want); printf ("\n");
64 abort();
65 }
66 mpz_clear (got);
67}
68
69
70void
71samples (void)
72{
73 static const struct {
74 const char *n;
75 unsigned long k;
76 const char *want;
77 } data[] = {
78
79 { "0", 123456, "0" },
80 { "1", 543210, "0" },
81 { "2", 123321, "0" },
82 { "3", 234567, "0" },
83 { "10", 23456, "0" },
84
85 /* negatives, using bin(-n,k)=bin(n+k-1,k) */
86 { "-1", 0, "1" },
87 { "-1", 1, "-1" },
88 { "-1", 2, "1" },
89 { "-1", 3, "-1" },
90 { "-1", 4, "1" },
91
92 { "-2", 0, "1" },
93 { "-2", 1, "-2" },
94 { "-2", 2, "3" },
95 { "-2", 3, "-4" },
96 { "-2", 4, "5" },
97 { "-2", 5, "-6" },
98 { "-2", 6, "7" },
99
100 { "-3", 0, "1" },
101 { "-3", 1, "-3" },
102 { "-3", 2, "6" },
103 { "-3", 3, "-10" },
104 { "-3", 4, "15" },
105 { "-3", 5, "-21" },
106 { "-3", 6, "28" },
107
108 /* A few random values */
109 { "41", 20, "269128937220" },
110 { "62", 37, "147405545359541742" },
111 { "50", 18, "18053528883775" },
112 { "149", 21, "19332950844468483467894649" },
113 };
114
115 mpz_t n, want;
116 int i;
117
118 mpz_init (n);
119 mpz_init (want);
120
121 for (i = 0; i < numberof (data); i++)
122 {
123 mpz_set_str_or_abort (n, data[i].n, 0);
124 mpz_set_str_or_abort (want, data[i].want, 0);
125
126 try_mpz_bin_ui (want, n, data[i].k);
127
128 if (mpz_fits_ulong_p (n))
129 try_mpz_bin_uiui (want, mpz_get_ui (n), data[i].k);
130 }
131
132 mpz_clear (n);
133 mpz_clear (want);
134}
135
136
137/* Test some bin(2k,k) cases. This produces some biggish numbers to
138 exercise the limb accumulating code. */
139void
140twos (int count)
141{
142 mpz_t n, want;
143 unsigned long k;
144
145 mpz_init (n);
146
147 mpz_init_set_ui (want, (unsigned long) 2);
148 for (k = 1; k < count; k++)
149 {
150 mpz_set_ui (n, 2*k);
151 try_mpz_bin_ui (want, n, k);
152
153 try_mpz_bin_uiui (want, 2*k, k);
154
155 mpz_mul_ui (want, want, 2*(2*k+1));
156 mpz_fdiv_q_ui (want, want, k+1);
157 }
158
159 mpz_clear (n);
160 mpz_clear (want);
161}
162
163/* Test some random bin(n,k) cases. This produces some biggish
164 numbers to exercise the limb accumulating code. */
165void
166randomwalk (int count)
167{
168 mpz_t n_z, want, tmp;
169 unsigned long n, k, i, r;
170 int tests;
171 gmp_randstate_ptr rands;
172
173 rands = RANDS;
174 mpz_init (n_z);
175
176 k = 3;
177 n = 12;
178 mpz_init_set_ui (want, (unsigned long) 220); /* binomial(12,3) = 220 */
179
180 for (tests = 1; tests < count; tests++)
181 {
182 r = gmp_urandomm_ui (rands, 62) + 1;
183 for (i = r & 7; i > 0; i--)
184 {
185 n++; k++;
186 mpz_mul_ui (want, want, n);
187 mpz_fdiv_q_ui (want, want, k);
188 }
189 for (i = r >> 3; i > 0; i--)
190 {
191 n++;
192 mpz_mul_ui (want, want, n);
193 mpz_fdiv_q_ui (want, want, n - k);
194 }
195
196 mpz_set_ui (n_z, n);
197 try_mpz_bin_ui (want, n_z, k);
198
199 try_mpz_bin_uiui (want, n, k);
200 }
201
202 k = 2;
203 mpz_urandomb (n_z, rands, 200);
204 mpz_mul (want, n_z, n_z); /* want = n_z ^ 2 */
205 mpz_sub (want, want, n_z); /* want = n_z ^ 2 - n_z = n_z (n_z- 1) */
206 mpz_tdiv_q_2exp (want, want, 1); /* want = n_z (n_z- 1) / 2 = binomial (n_z, 2) */
207 mpz_init (tmp);
208 for (tests = 1; tests < count; tests++)
209 {
210 r = gmp_urandomm_ui (rands, 62) + 1;
211 for (i = r & 7; i > 0; i--)
212 {
213 k++;
214 mpz_add_ui (n_z, n_z, 1);
215 mpz_mul (want, want, n_z);
216 mpz_tdiv_q_ui (want, want, k);
217 }
218 for (i = r >> 3; i > 0; i--)
219 {
220 mpz_add_ui (n_z, n_z, 1);
221 mpz_mul (want, want, n_z);
222 mpz_sub_ui (tmp, n_z, k);
223 mpz_tdiv_q (want, want, tmp);
224 }
225
226 try_mpz_bin_ui (want, n_z, k);
227 }
228
229 mpz_clear (tmp);
230 mpz_clear (n_z);
231 mpz_clear (want);
232}
233
234/* Test some random bin(n,k) cases. This produces some biggish
235 numbers to exercise the limb accumulating code. */
236void
237randomwalk_down (int count)
238{
239 mpz_t n_z, want, tmp;
240 unsigned long n, k, i, r;
241 int tests;
242 gmp_randstate_ptr rands;
243
244 rands = RANDS;
245 mpz_init (n_z);
246 mpz_init (tmp);
247
248 k = 2;
249 n = ULONG_MAX;
250 mpz_init_set_ui (want, n);
251 mpz_mul_ui (want, want, n >> 1);
252
253 for (tests = 1; tests < count; tests++)
254 {
255 r = gmp_urandomm_ui (rands, 62) + 1;
256 for (i = r & 7; i > 0; i--)
257 {
258 mpz_mul_ui (want, want, n - k);
259 ++k;
260 mpz_tdiv_q_ui (want, want, k);
261 }
262 for (i = r >> 3; i > 0; i--)
263 {
264 mpz_mul_ui (want, want, n - k);
265 mpz_tdiv_q_ui (want, want, n);
266 --n;
267 }
268
269 mpz_set_ui (n_z, n);
270 try_mpz_bin_ui (want, n_z, n - k);
271
272 try_mpz_bin_uiui (want, n, n - k);
273 }
274
275 mpz_clear (tmp);
276 mpz_clear (n_z);
277 mpz_clear (want);
278}
279
280
281/* Test all bin(n,k) cases, with 0 <= k <= n + 1 <= count. */
282void
283smallexaustive (unsigned int count)
284{
285 mpz_t n_z, want;
286 unsigned long n, k;
287
288 mpz_init (n_z);
289 mpz_init (want);
290
291 for (n = 0; n < count; n++)
292 {
293 mpz_set_ui (want, (unsigned long) 1);
294 mpz_set_ui (n_z, n);
295 for (k = 0; k <= n; k++)
296 {
297 try_mpz_bin_ui (want, n_z, k);
298 try_mpz_bin_uiui (want, n, k);
299 mpz_mul_ui (want, want, n - k);
300 mpz_fdiv_q_ui (want, want, k + 1);
301 }
302 try_mpz_bin_ui (want, n_z, k);
303 try_mpz_bin_uiui (want, n, k);
304 }
305
306 mpz_clear (n_z);
307 mpz_clear (want);
308}
309
310int
311main (int argc, char **argv)
312{
313 int count;
314
315 count = COUNT;
316 TESTS_REPS (count, argv, argc);
317
318 tests_start ();
319
320 samples ();
321 smallexaustive (count >> 4);
322 twos (count >> 1);
323 randomwalk (count - (count >> 1));
324 randomwalk_down (count >> 1);
325
326 tests_end ();
327 exit (0);
328}