xref: /netbsd-src/external/lgpl3/gmp/dist/tests/mpz/t-bin.c (revision 72c7faa4dbb41dbb0238d6b4a109da0d4b236dd4)
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