1/* Exercise mpz_fac_ui and mpz_bin_uiui.
2
3Copyright 2000-2002, 2012, 2013, 2017-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
23#include "testutils.h"
24
25/* Usage: t-fac_ui [x|num]
26
27   With no arguments testing goes up to the initial value of "limit" below.
28   With a number argument tests are carried that far, or with a literal "x"
29   tests are continued without limit (this being meant only for development
30   purposes).  */
31
32void
33try_mpz_bin_uiui (mpz_srcptr want, unsigned long n, unsigned long k)
34{
35  mpz_t  got;
36
37  mpz_init (got);
38  mpz_bin_uiui (got, n, k);
39  if (mpz_cmp (got, want) != 0)
40    {
41      printf ("mpz_bin_uiui wrong\n");
42      printf ("  n=%lu\n", n);
43      printf ("  k=%lu\n", k);
44      printf ("  got="); mpz_out_str (stdout, 10, got); printf ("\n");
45      printf ("  want="); mpz_out_str (stdout, 10, want); printf ("\n");
46      abort();
47    }
48  mpz_clear (got);
49}
50
51/* Test all bin(n,k) cases, with 0 <= k <= n + 1 <= count.  */
52void
53bin_smallexaustive (unsigned int count)
54{
55  mpz_t          want;
56  unsigned long  n, k;
57
58  mpz_init (want);
59
60  for (n = 0; n < count; n++)
61    {
62      mpz_set_ui (want, 1);
63      for (k = 0; k <= n; k++)
64	{
65	  try_mpz_bin_uiui (want, n, k);
66	  mpz_mul_ui (want, want, n - k);
67	  mpz_fdiv_q_ui (want, want, k + 1);
68	}
69      try_mpz_bin_uiui (want, n, k);
70    }
71
72  mpz_clear (want);
73}
74
75/* Test all fac(n) cases, with 0 <= n <= limit.  */
76void
77fac_smallexaustive (unsigned int limit)
78{
79  mpz_t          f, r;
80  unsigned long  n;
81  mpz_init_set_si (f, 1);  /* 0! = 1 */
82  mpz_init (r);
83
84  for (n = 0; n < limit; n++)
85    {
86      mpz_fac_ui (r, n);
87
88      if (mpz_cmp (f, r) != 0)
89        {
90          printf ("mpz_fac_ui(%lu) wrong\n", n);
91          printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
92          printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
93          abort ();
94        }
95
96      mpz_mul_ui (f, f, n+1);  /* (n+1)! = n! * (n+1) */
97    }
98
99  mpz_clear (f);
100  mpz_clear (r);
101}
102
103void checkWilson (mpz_t f, unsigned long n)
104{
105  unsigned long m, a;
106
107  mpz_2fac_ui (f, 2 * n - 1);
108
109  a = mpz_fdiv_q_ui (f, f, n);
110  m = mpz_fdiv_ui (f, n);
111  if ((m != n - 1) || (a != 0))
112    {
113      printf ("mpz_2fac_ui(%lu) wrong\n", 2 * n - 1);
114      printf ("  Wilson's theorem not verified: got (%lu, %lu), expected (0, %lu).\n", a, m, n - 1);
115      abort ();
116    }
117
118  mpz_fac_ui (f, n - 1);
119  m = mpz_fdiv_ui (f, n);
120  if ( m != n - 1)
121    {
122      printf ("mpz_fac_ui(%lu) wrong\n", n - 1);
123      printf ("  Wilson's theorem not verified: got %lu, expected %lu.\n",m ,n - 1);
124      abort ();
125    }
126}
127
128void
129checkprimes (unsigned long p1, unsigned long p2, unsigned long p3)
130{
131  mpz_t          b, f;
132
133  if (p1 - 1 != p2 - 1 + p3 - 1)
134    {
135      printf ("checkprimes(%lu, %lu, %lu) wrong\n", p1, p2, p3);
136      printf (" %lu - 1 != %lu - 1 + %lu - 1 \n", p1, p2, p3);
137      abort ();
138    }
139
140  mpz_init (b);
141  mpz_init (f);
142
143  checkWilson (b, p1); /* b = (p1-1)! */
144  checkWilson (f, p2); /* f = (p2-1)! */
145  mpz_divexact (b, b, f);
146  checkWilson (f, p3); /* f = (p3-1)! */
147  mpz_divexact (b, b, f); /* b = (p1-1)!/((p2-1)!(p3-1)!) */
148  mpz_bin_uiui (f, p1 - 1, p2 - 1);
149  if (mpz_cmp (f, b) != 0)
150    {
151      printf ("checkprimes(%lu, %lu, %lu) wrong\n", p1, p2, p3);
152      printf ("  got  "); mpz_out_str (stdout, 10, b); printf("\n");
153      printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
154      abort ();
155    }
156
157  mpz_clear (b);
158  mpz_clear (f);
159
160}
161
162void
163testmain (int argc, char *argv[])
164{
165  unsigned long  limit = 128;
166
167  if (argc > 1 && argv[1][0] == 'x')
168    limit = ~ limit;
169  else if (argc > 1)
170    limit = atoi (argv[1]);
171
172  checkprimes(1009, 733, 277);
173  fac_smallexaustive (limit);
174  bin_smallexaustive (limit);
175}
176