1 /* Exercise mpz_bin_ui and mpz_bin_uiui.
2
3 Copyright 2000, 2001, 2010, 2012, 2018 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 #include "gmp-impl.h"
23 #include "tests.h"
24
25 /* Default number of generated tests. */
26 #define COUNT 700
27
28 void
try_mpz_bin_ui(mpz_srcptr want,mpz_srcptr n,unsigned long k)29 try_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
49 void
try_mpz_bin_uiui(mpz_srcptr want,unsigned long n,unsigned long k)50 try_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
70 void
samples(void)71 samples (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. */
139 void
twos(int count)140 twos (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. */
165 void
randomwalk(int count)166 randomwalk (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. */
236 void
randomwalk_down(int count)237 randomwalk_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. */
282 void
smallexaustive(unsigned int count)283 smallexaustive (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
310 int
main(int argc,char ** argv)311 main (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 }
329