1 /* Test mpz_perfect_power_p.
2 
3    Contributed to the GNU project by Torbjorn Granlund and Martin Boij.
4 
5 Copyright 2008-2010, 2014 Free Software Foundation, Inc.
6 
7 This file is part of the GNU MP Library test suite.
8 
9 The GNU MP Library test suite is free software; you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 3 of the License,
12 or (at your option) any later version.
13 
14 The GNU MP Library test suite is distributed in the hope that it will be
15 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
17 Public License for more details.
18 
19 You should have received a copy of the GNU General Public License along with
20 the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 #include "gmp-impl.h"
26 #include "tests.h"
27 
28 struct
29 {
30   const char *num_as_str;
31   char want;
32 } static tests[] =
33   {
34     { "0", 1},
35     { "1", 1},
36     {"-1", 1},
37     { "2", 0},
38     {"-2", 0},
39     { "3", 0},
40     {"-3", 0},
41     { "4", 1},
42     {"-4", 0},
43     { "64", 1},
44     {"-64", 1},
45     { "128", 1},
46     {"-128", 1},
47     { "256", 1},
48     {"-256", 0},
49     { "512", 1},
50     {"-512", 1},
51     { "0x4000000", 1},
52     {"-0x4000000", 1},
53     { "0x3cab640", 1},
54     {"-0x3cab640", 0},
55     { "0x3e23840", 1},
56     {"-0x3e23840", 0},
57     { "0x3d3a7ed1", 1},
58     {"-0x3d3a7ed1", 1},
59     { "0x30a7a6000", 1},
60     {"-0x30a7a6000", 1},
61     { "0xf33e5a5a59", 1},
62     {"-0xf33e5a5a59", 0},
63     { "0xed1b1182118135d", 1},
64     {"-0xed1b1182118135d", 1},
65     { "0xe71f6eb7689cc276b2f1", 1},
66     {"-0xe71f6eb7689cc276b2f1", 0},
67     { "0x12644507fe78cf563a4b342c92e7da9fe5e99cb75a01", 1},
68     {"-0x12644507fe78cf563a4b342c92e7da9fe5e99cb75a01", 0},
69     { "0x1ff2e7c581bb0951df644885bd33f50e472b0b73a204e13cbe98fdb424d66561e4000000", 1},
70     {"-0x1ff2e7c581bb0951df644885bd33f50e472b0b73a204e13cbe98fdb424d66561e4000000", 1},
71     { "0x2b9b44db2d91a6f8165c8c7339ef73633228ea29e388592e80354e4380004aad84000000", 1},
72     {"-0x2b9b44db2d91a6f8165c8c7339ef73633228ea29e388592e80354e4380004aad84000000", 1},
73     { "0x28d5a2b8f330910a9d3cda06036ae0546442e5b1a83b26a436efea5b727bf1bcbe7e12b47d81", 1},
74     {"-0x28d5a2b8f330910a9d3cda06036ae0546442e5b1a83b26a436efea5b727bf1bcbe7e12b47d81", 1},
75     {NULL, 0}
76   };
77 
78 
79 void
check_tests()80 check_tests ()
81 {
82   mpz_t x;
83   int i;
84   int got, want;
85 
86   mpz_init (x);
87 
88   for (i = 0; tests[i].num_as_str != NULL; i++)
89     {
90       mpz_set_str (x, tests[i].num_as_str, 0);
91       got = mpz_perfect_power_p (x);
92       want = tests[i].want;
93       if (got != want)
94 	{
95 	  fprintf (stderr, "mpz_perfect_power_p returns %d when %d was expected\n", got, want);
96 	  fprintf (stderr, "fault operand: %s\n", tests[i].num_as_str);
97 	  abort ();
98 	}
99     }
100 
101   mpz_clear (x);
102 }
103 
104 #define NRP 15
105 
106 void
check_random(int reps)107 check_random (int reps)
108 {
109   mpz_t n, np, temp, primes[NRP];
110   int i, j, k, unique, destroy, res;
111   unsigned long int nrprimes, primebits;
112   mp_limb_t g, exp[NRP], e;
113   gmp_randstate_ptr rands;
114 
115   rands = RANDS;
116 
117   mpz_init (n);
118   mpz_init (np);
119   mpz_init (temp);
120 
121   for (i = 0; i < NRP; i++)
122     mpz_init (primes[i]);
123 
124   for (i = 0; i < reps; i++)
125     {
126       mpz_urandomb (np, rands, 32);
127       nrprimes = mpz_get_ui (np) % NRP + 1; /* 1-NRP unique primes */
128 
129       mpz_urandomb (np, rands, 32);
130       g = mpz_get_ui (np) % 32 + 2; /* gcd 2-33 */
131 
132       for (j = 0; j < nrprimes;)
133 	{
134 	  mpz_urandomb (np, rands, 32);
135 	  primebits = mpz_get_ui (np) % 100 + 3; /* 3-102 bit primes */
136 	  mpz_urandomb (primes[j], rands, primebits);
137 	  mpz_nextprime (primes[j], primes[j]);
138 	  unique = 1;
139 	  for (k = 0; k < j; k++)
140 	    {
141 	      if (mpz_cmp (primes[j], primes[k]) == 0)
142 		{
143 		  unique = 0;
144 		  break;
145 		}
146 	    }
147 	  if (unique)
148 	    {
149 	      mpz_urandomb (np, rands, 32);
150 	      e = 371 / (10 * primebits) + mpz_get_ui (np) % 11 + 1; /* Magic constants */
151 	      exp[j++] = g * e;
152 	    }
153 	}
154 
155       if (nrprimes > 1)
156 	{
157 	  /* Destroy d exponents, d in [1, nrprimes - 1] */
158 	  if (nrprimes == 2)
159 	    {
160 	      destroy = 1;
161 	    }
162 	  else
163 	    {
164 	      mpz_urandomb (np, rands, 32);
165 	      destroy = mpz_get_ui (np) % (nrprimes - 2);
166 	    }
167 
168 	  g = exp[destroy];
169 	  for (k = destroy + 1; k < nrprimes; k++)
170 	    g = mpn_gcd_1 (&g, 1, exp[k]);
171 
172 	  for (j = 0; j < destroy; j++)
173 	    {
174 	      mpz_urandomb (np, rands, 32);
175 	      e = mpz_get_ui (np) % 50 + 1;
176 	      while (mpn_gcd_1 (&g, 1, e) > 1)
177 		e++;
178 
179 	      exp[j] = e;
180 	    }
181 	}
182 
183       /* Compute n */
184       mpz_pow_ui (n, primes[0], exp[0]);
185       for (j = 1; j < nrprimes; j++)
186 	{
187 	  mpz_pow_ui (temp, primes[j], exp[j]);
188 	  mpz_mul (n, n, temp);
189 	}
190 
191       res = mpz_perfect_power_p (n);
192 
193       if (nrprimes == 1)
194 	{
195 	if (res == 0 && exp[0] > 1)
196 	  {
197 	    printf("n is a perfect power, perfpow_p disagrees\n");
198 	    gmp_printf("n = %Zu\nprimes[0] = %Zu\nexp[0] = %lu\n", n, primes[0], exp[0]);
199 	    abort ();
200 	  }
201 	else if (res == 1 && exp[0] == 1)
202 	  {
203 	    gmp_printf("n = %Zu\n", n);
204 	    printf("n is now a prime number, but perfpow_p still believes n is a perfect power\n");
205 	    abort ();
206 	  }
207 	}
208       else
209 	{
210 	  if (res == 1 && destroy != 0)
211 	    {
212 	      gmp_printf("n = %Zu\nn was destroyed, but perfpow_p still believes n is a perfect power\n", n);
213 	      abort ();
214 	    }
215 	  else if (res == 0 && destroy == 0)
216 	    {
217 	      gmp_printf("n = %Zu\nn is a perfect power, perfpow_p disagrees\n", n);
218 	      abort ();
219 	    }
220 	}
221     }
222 
223   mpz_clear (n);
224   mpz_clear (np);
225   mpz_clear (temp);
226   for (i = 0; i < NRP; i++)
227     mpz_clear (primes[i]);
228 }
229 
230 int
main(int argc,char ** argv)231 main (int argc, char **argv)
232 {
233   int n_tests;
234 
235   tests_start ();
236   mp_trace_base = -16;
237 
238   check_tests ();
239 
240   n_tests = 500;
241   if (argc == 2)
242     n_tests = atoi (argv[1]);
243   check_random (n_tests);
244 
245   tests_end ();
246   exit (0);
247 }
248