1221807Sstas/* Test mpz_pow_ui and mpz_ui_pow_ui.
2221807Sstas
3221807SstasCopyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
4221807Sstas
5221807SstasThis file is part of the GNU MP Library.
6221807Sstas
7221807SstasThe GNU MP Library is free software; you can redistribute it and/or modify
8221807Sstasit under the terms of the GNU Lesser General Public License as published by
9221807Sstasthe Free Software Foundation; either version 3 of the License, or (at your
10221807Sstasoption) any later version.
11221807Sstas
12221807SstasThe GNU MP Library is distributed in the hope that it will be useful, but
13221807SstasWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14221807Sstasor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15221807SstasLicense for more details.
16221807Sstas
17221807SstasYou should have received a copy of the GNU Lesser General Public License
18221807Sstasalong with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
19221807Sstas
20221807Sstas#include <stdio.h>
21221807Sstas#include <stdlib.h>
22221807Sstas
23221807Sstas#include "gmp.h"
24221807Sstas#include "gmp-impl.h"
25221807Sstas#include "tests.h"
26221807Sstas
27221807Sstas
28221807Sstasvoid
29221807Sstascheck_one (mpz_srcptr want, mpz_srcptr base, unsigned long exp)
30221807Sstas{
31221807Sstas  mpz_t  got;
32221807Sstas
33221807Sstas  mpz_init (got);
34221807Sstas
35221807Sstas  MPZ_CHECK_FORMAT (want);
36221807Sstas
37249679Strociny  mpz_pow_ui (got, base, exp);
38249679Strociny  if (mpz_cmp (got, want))
39249666Strociny    {
40221807Sstas      printf ("mpz_pow_ui wrong\n");
41221807Sstas      mpz_trace ("  base", base);
42221807Sstas      printf    ("  exp = %lu (0x%lX)\n", exp, exp);
43      mpz_trace ("  got ", got);
44      mpz_trace ("  want", want);
45      abort ();
46    }
47
48  mpz_set (got, base);
49  mpz_pow_ui (got, got, exp);
50  if (mpz_cmp (got, want))
51    {
52      printf ("mpz_pow_ui wrong\n");
53      mpz_trace ("  base", base);
54      printf    ("  exp = %lu (0x%lX)\n", exp, exp);
55      mpz_trace ("  got ", got);
56      mpz_trace ("  want", want);
57      abort ();
58    }
59
60  if (mpz_fits_ulong_p (base))
61    {
62      unsigned long  base_u = mpz_get_ui (base);
63      mpz_ui_pow_ui (got, base_u, exp);
64      if (mpz_cmp (got, want))
65	{
66	  printf    ("mpz_ui_pow_ui wrong\n");
67	  printf    ("  base=%lu (0x%lX)\n", base_u, base_u);
68	  printf    ("  exp = %lu (0x%lX)\n", exp, exp);
69	  mpz_trace ("  got ", got);
70	  mpz_trace ("  want", want);
71	  abort ();
72	}
73    }
74
75  mpz_clear (got);
76}
77
78void
79check_base (mpz_srcptr base)
80{
81  unsigned long  exp;
82  mpz_t          want;
83
84  mpz_init (want);
85  mpz_set_ui (want, 1L);
86
87  for (exp = 0; exp < 20; exp++)
88    {
89      check_one (want, base, exp);
90      mpz_mul (want, want, base);
91    }
92
93  mpz_clear (want);
94}
95
96void
97check_various (void)
98{
99  static const struct {
100    const char *base;
101  } data[] = {
102    { "0" },
103    { "1" },
104    { "2" },
105    { "3" },
106    { "4" },
107    { "5" },
108    { "6" },
109    { "10" },
110    { "15" },
111    { "16" },
112
113    { "0x1F" },
114    { "0xFF" },
115    { "0x1001" },
116    { "0xFFFF" },
117    { "0x10000001" },
118    { "0x1000000000000001" },
119
120    /* actual size closest to estimate */
121    { "0xFFFFFFFF" },
122    { "0xFFFFFFFFFFFFFFFF" },
123
124    /* same after rshift */
125    { "0xFFFFFFFF0" },
126    { "0xFFFFFFFF00" },
127    { "0xFFFFFFFFFFFFFFFF0" },
128    { "0xFFFFFFFFFFFFFFFF00" },
129
130    /* change from 2 limbs to 1 after rshift */
131    { "0x180000000" },
132    { "0x18000000000000000" },
133
134    /* change from 3 limbs to 2 after rshift */
135    { "0x18000000100000000" },
136    { "0x180000000000000010000000000000000" },
137
138    /* handling of absolute value */
139    { "-0x80000000" },
140    { "-0x8000000000000000" },
141
142    /* low zero limb, and size>2, checking argument overlap detection */
143    { "0x3000000000000000300000000000000030000000000000000" },
144  };
145
146  mpz_t  base;
147  int    i;
148
149  mpz_init (base);
150
151  for (i = 0; i < numberof (data); i++)
152    {
153      mpz_set_str_or_abort (base, data[i].base, 0);
154      check_base (base);
155    }
156
157  mpz_clear (base);
158}
159
160void
161check_random (int reps)
162{
163  mpz_t              base, want;
164  mp_size_t          base_size;
165  int                i;
166  unsigned long      size_range, exp;
167  gmp_randstate_ptr  rands = RANDS;
168
169  mpz_init (base);
170  mpz_init (want);
171
172  for (i = 0; i < reps; i++)
173    {
174      /* exponentially random 0 to 2^13 bits for base */
175      mpz_urandomb (want, rands, 32);
176      size_range = mpz_get_ui (want) % 12 + 2;
177      mpz_urandomb (want, rands, size_range);
178      base_size = mpz_get_ui (want);
179      mpz_rrandomb (base, rands, base_size);
180
181      /* randomly signed base */
182      mpz_urandomb (want, rands, 2);
183      if ((mpz_get_ui (want) & 1) != 0)
184	mpz_neg (base, base);
185
186      /* random 5 bits for exponent */
187      mpz_urandomb (want, rands, 5L);
188      exp = mpz_get_ui (want);
189
190      refmpz_pow_ui (want, base, exp);
191      check_one (want, base, exp);
192    }
193
194  mpz_clear (base);
195  mpz_clear (want);
196}
197
198int
199main (int argc, char **argv)
200{
201  int reps = 5000;
202
203  /* dummy call to drag in refmpn.o for testing mpz/n_pow_ui.c with
204     refmpn_mul_2 */
205  refmpn_zero_p (NULL, (mp_size_t) 0);
206
207  tests_start ();
208  mp_trace_base = -16;
209
210  if (argc == 2)
211     reps = atoi (argv[1]);
212
213  check_various ();
214  check_random (reps);
215
216  tests_end ();
217  exit (0);
218}
219