1/* random.c -- Handle seed for random numbers.
2
3// Copyright (C) 2008, 2009, 2010, 2011 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
89void
90test_end (void)
91{
92  if (rands_initialized)
93    {
94      rands_initialized = 0;
95      gmp_randclear (rands);
96    }
97  mpfr_free_cache ();
98}
99
100/* Set z to a non zero value random value with absolute values of Re(z) and
101   Im(z) either zero (but not both in the same time) or otherwise greater than
102   or equal to 2^{emin-1} and less than 2^emax.
103   Each part is negative with probability equal to NEGATIVE_PROBABILITY / 256.
104   The result has one zero part (but never the two of them) with probability
105   equal to ZERO_PROBABILITY / 256.
106*/
107void
108test_default_random (mpc_ptr z, mpfr_exp_t emin, mpfr_exp_t emax,
109                     unsigned int negative_probability,
110                     unsigned int zero_probability)
111{
112  const unsigned long range = (unsigned long int) (emax - emin) + 1;
113  unsigned long r;
114
115  if (!rands_initialized)
116    {
117      fprintf (stderr,
118               "Put test_start at the beginning of your test function.\n");
119      exit (1);
120    }
121
122  do
123    {
124      mpc_urandom (z, rands);
125    } while (mpfr_zero_p (mpc_realref (z)) || mpfr_zero_p (mpc_imagref (z)));
126
127  if (zero_probability > 256)
128    zero_probability = 256;
129  r = gmp_urandomb_ui (rands, 19);
130  if ((r & 0x1FF) < zero_probability
131      || ((r >> 9) & 0x1FF) < zero_probability)
132    {
133      int zero_re_p = (r & 0x1FF) < zero_probability;
134      int zero_im_p = ((r >> 9) & 0x1FF) < zero_probability;
135
136      if (zero_re_p && zero_im_p)
137        {
138          /* we just want one zero part. */
139          zero_re_p = (r >> 18) & 1;
140          zero_im_p = !zero_re_p;
141        }
142      if (zero_re_p)
143        mpfr_set_ui (mpc_realref (z), 0, GMP_RNDN);
144      if (zero_im_p)
145        mpfr_set_ui (mpc_imagref (z), 0, GMP_RNDN);
146    }
147  if (!mpfr_zero_p (mpc_realref (z)))
148    mpfr_set_exp (mpc_realref (z), (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin);
149
150  if (!mpfr_zero_p (mpc_imagref (z)))
151    mpfr_set_exp (mpc_imagref (z), (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin);
152
153  if (negative_probability > 256)
154    negative_probability = 256;
155  r = gmp_urandomb_ui (rands, 16);
156  if ((r & 0xFF) < negative_probability)
157    mpfr_neg (mpc_realref (z), mpc_realref (z), GMP_RNDN);
158  if (((r>>8) & 0xFF) < negative_probability)
159    mpfr_neg (mpc_imagref (z), mpc_imagref (z), GMP_RNDN);
160}
161