1/* random.c -- Handle seed for random numbers.
2
3// Copyright (C) 2008, 2009, 2010, 2011, 2012 INRIA
4
5This file is part of GNU MPC.
6
7GNU MPC is free software; you can redistribute it and/or modify it under
8the terms of the GNU Lesser General Public License as published by the
9Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with this program. If not, see http://www.gnu.org/licenses/ .
19*/
20
21/* Put test_start at the beginning of your test function and
22   test_end at the end.
23   These are an adaptation of those of MPFR. */
24
25#include "config.h"
26#include <stdlib.h>
27#include "mpc-tests.h"
28
29
30#ifdef TIME_WITH_SYS_TIME
31# include <sys/time.h>
32# include <time.h>
33#else
34# ifdef HAVE_SYS_TIME_H
35#  include <sys/time.h>
36# else
37#  include <time.h>
38# endif
39#endif
40
41gmp_randstate_t  rands;
42static char      rands_initialized;
43
44void
45test_start (void)
46{
47  char *environment_seed;
48  unsigned long seed;
49
50  if (rands_initialized)
51    {
52      fprintf (stderr,
53               "Put test_start at the beginning of your test function.\n");
54      exit (1);
55    }
56
57  gmp_randinit_default (rands);
58  rands_initialized = 1;
59
60  environment_seed = getenv ("GMP_CHECK_RANDOMIZE");
61  if (environment_seed == NULL)
62      gmp_randseed_ui (rands, 0xfac11e);
63  else
64    {
65      seed = (unsigned long int) atoi (environment_seed);
66      if (seed == 0 || seed == 1)
67        {
68#if defined HAVE_GETTIMEOFDAY
69          struct timeval  tv;
70          gettimeofday (&tv, NULL);
71          seed = (unsigned long int) (tv.tv_sec + tv.tv_usec);
72#else
73          time_t  tv;
74          time (&tv);
75          seed = (unsigned long int) tv;
76#endif
77          gmp_randseed_ui (rands, seed);
78          printf ("Seed GMP_CHECK_RANDOMIZE=%lu "
79                  "(include this in bug reports)\n", seed);
80        }
81      else
82        {
83          printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%lu\n", seed);
84          gmp_randseed_ui (rands, seed);
85        }
86    }
87
88  /* some tests assume a given exponent range for MPFR, thus since the
89     default exponent range for MPFR is not specified, we hard-code it */
90  mpfr_set_emax (1073741821);
91  mpfr_set_emin (-1073741821);
92}
93
94void
95test_end (void)
96{
97  if (rands_initialized)
98    {
99      rands_initialized = 0;
100      gmp_randclear (rands);
101    }
102  mpfr_free_cache ();
103}
104
105/* Set z to a non zero value random value with absolute values of Re(z) and
106   Im(z) either zero (but not both in the same time) or otherwise greater than
107   or equal to 2^{emin-1} and less than 2^emax.
108   Each part is negative with probability equal to NEGATIVE_PROBABILITY / 256.
109   The result has one zero part (but never the two of them) with probability
110   equal to ZERO_PROBABILITY / 256.
111*/
112void
113test_default_random (mpc_ptr z, mpfr_exp_t emin, mpfr_exp_t emax,
114                     unsigned int negative_probability,
115                     unsigned int zero_probability)
116{
117  const unsigned long range = (unsigned long int) (emax - emin) + 1;
118  unsigned long r;
119
120  if (!rands_initialized)
121    {
122      fprintf (stderr,
123               "Put test_start at the beginning of your test function.\n");
124      exit (1);
125    }
126
127  do
128    {
129      mpc_urandom (z, rands);
130    } while (mpfr_zero_p (mpc_realref (z)) || mpfr_zero_p (mpc_imagref (z)));
131
132  if (zero_probability > 256)
133    zero_probability = 256;
134  r = gmp_urandomb_ui (rands, 19);
135  if ((r & 0x1FF) < zero_probability
136      || ((r >> 9) & 0x1FF) < zero_probability)
137    {
138      int zero_re_p = (r & 0x1FF) < zero_probability;
139      int zero_im_p = ((r >> 9) & 0x1FF) < zero_probability;
140
141      if (zero_re_p && zero_im_p)
142        {
143          /* we just want one zero part. */
144          zero_re_p = (r >> 18) & 1;
145          zero_im_p = !zero_re_p;
146        }
147      if (zero_re_p)
148        mpfr_set_ui (mpc_realref (z), 0, MPFR_RNDN);
149      if (zero_im_p)
150        mpfr_set_ui (mpc_imagref (z), 0, MPFR_RNDN);
151    }
152  if (!mpfr_zero_p (mpc_realref (z)))
153    mpfr_set_exp (mpc_realref (z), (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin);
154
155  if (!mpfr_zero_p (mpc_imagref (z)))
156    mpfr_set_exp (mpc_imagref (z), (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin);
157
158  if (negative_probability > 256)
159    negative_probability = 256;
160  r = gmp_urandomb_ui (rands, 16);
161  if ((r & 0xFF) < negative_probability)
162    mpfr_neg (mpc_realref (z), mpc_realref (z), MPFR_RNDN);
163  if (((r>>8) & 0xFF) < negative_probability)
164    mpfr_neg (mpc_imagref (z), mpc_imagref (z), MPFR_RNDN);
165}
166
167/* Set n to a non zero value random value with absolute values less than
168   2^emax.
169
170   n is negative with probability equal to NEGATIVE_PROBABILITY / 256.
171*/
172void test_random_si (long int *n, unsigned long emax,
173                     unsigned int negative_probability)
174{
175  unsigned long r;
176
177  if (!rands_initialized)
178    {
179      fprintf (stderr,
180               "Put test_start at the beginning of your test function.\n");
181      exit (1);
182    }
183
184  do
185    {
186      *n = gmp_urandomb_ui (rands, emax);
187    } while (*n == 0);
188
189  if (negative_probability > 256)
190    negative_probability = 256;
191  r = gmp_urandomb_ui (rands, 8);
192  if ((r & 0xFF) < negative_probability)
193    *n = -(*n);
194}
195
196/* Set x to a non zero value random value with absolute values greater than
197   or equal to 2^{emin-1} and less than 2^emax.
198
199   x is negative with probability equal to NEGATIVE_PROBABILITY / 256.
200*/
201void
202test_random_mpfr (mpfr_ptr x, mpfr_exp_t emin, mpfr_exp_t emax,
203                  unsigned int negative_probability)
204{
205  const unsigned long range = (unsigned long int) (emax - emin) + 1;
206  unsigned long r;
207
208  if (!rands_initialized)
209    {
210      fprintf (stderr,
211               "Put test_start at the beginning of your test function.\n");
212      exit (1);
213    }
214
215  do
216    {
217      mpfr_urandom (x, rands, MPFR_RNDN);
218    } while (mpfr_zero_p (x));
219
220  mpfr_set_exp (x, (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin);
221  if (negative_probability > 256)
222    negative_probability = 256;
223  r = gmp_urandomb_ui (rands, 8);
224  if ((r & 0xFF) < negative_probability)
225    mpfr_neg (x, x, MPFR_RNDN);
226}
227
228/* Set x to a non zero value random value.
229   x is negative with probability equal to NEGATIVE_PROBABILITY / 256.
230*/
231void
232test_random_d (double *x, unsigned int negative_probability)
233{
234  MPFR_DECL_INIT (mpfr_x, 53);
235  test_random_mpfr (mpfr_x, -1022, 1022, negative_probability);
236  *x = mpfr_get_d (mpfr_x, MPFR_RNDN);
237}
238
239/* Set z to a non zero value random value with absolute values of Re(z) and
240   Im(z) greater than or equal to 2^{emin-1} and less than 2^emax.
241
242   Each part is negative with probability equal to NEGATIVE_PROBABILITY / 256.
243*/
244void
245test_random_mpc (mpc_ptr z, mpfr_exp_t emin, mpfr_exp_t emax,
246                 unsigned int negative_probability)
247{
248  const unsigned long range = (unsigned long int) (emax - emin) + 1;
249  unsigned long r;
250
251  if (!rands_initialized)
252    {
253      fprintf (stderr,
254               "Put test_start at the beginning of your test function.\n");
255      exit (1);
256    }
257
258  do
259    {
260      mpc_urandom (z, rands);
261    } while (mpfr_zero_p (mpc_realref (z)) || mpfr_zero_p (mpc_imagref (z)));
262
263    mpfr_set_exp (mpc_realref (z),
264                  (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin);
265
266    mpfr_set_exp (mpc_imagref (z),
267                  (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin);
268
269  if (negative_probability > 256)
270    negative_probability = 256;
271  r = gmp_urandomb_ui (rands, 16);
272  if ((r & 0xFF) < negative_probability)
273    mpfr_neg (mpc_realref (z), mpc_realref (z), MPFR_RNDN);
274  if (((r>>8) & 0xFF) < negative_probability)
275    mpfr_neg (mpc_imagref (z), mpc_imagref (z), MPFR_RNDN);
276}
277