beta-0.89.2
[luatex.git] / source / libs / mpfr / mpfr-3.1.3 / src / urandom.c
blob0610eb1dbd4ce20d744e65ed14b3b7d12c42bdf4
1 /* mpfr_urandom (rop, state, rnd_mode) -- Generate a uniform pseudorandom
2 real number between 0 and 1 (exclusive) and round it to the precision of rop
3 according to the given rounding mode.
5 Copyright 2000-2004, 2006-2015 Free Software Foundation, Inc.
6 Contributed by the AriC and Caramel projects, INRIA.
8 This file is part of the GNU MPFR Library.
10 The GNU MPFR Library is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or (at your
13 option) any later version.
15 The GNU MPFR Library is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18 License for more details.
20 You should have received a copy of the GNU Lesser General Public License
21 along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
22 http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
26 #define MPFR_NEED_LONGLONG_H
27 #include "mpfr-impl.h"
30 /* generate one random bit */
31 static int
32 random_rounding_bit (gmp_randstate_t rstate)
34 mp_limb_t r;
36 mpfr_rand_raw (&r, rstate, 1);
37 return r & MPFR_LIMB_ONE;
41 int
42 mpfr_urandom (mpfr_ptr rop, gmp_randstate_t rstate, mpfr_rnd_t rnd_mode)
44 mpfr_limb_ptr rp;
45 mpfr_prec_t nbits;
46 mp_size_t nlimbs;
47 mp_size_t n;
48 mpfr_exp_t exp;
49 mpfr_exp_t emin;
50 int cnt;
51 int inex;
53 rp = MPFR_MANT (rop);
54 nbits = MPFR_PREC (rop);
55 nlimbs = MPFR_LIMB_SIZE (rop);
56 MPFR_SET_POS (rop);
57 exp = 0;
58 emin = mpfr_get_emin ();
59 if (MPFR_UNLIKELY (emin > 0))
61 if (rnd_mode == MPFR_RNDU || rnd_mode == MPFR_RNDA
62 || (emin == 1 && rnd_mode == MPFR_RNDN
63 && random_rounding_bit (rstate)))
65 mpfr_set_ui_2exp (rop, 1, emin - 1, rnd_mode);
66 return +1;
68 else
70 MPFR_SET_ZERO (rop);
71 return -1;
75 /* Exponent */
76 #define DRAW_BITS 8 /* we draw DRAW_BITS at a time */
77 cnt = DRAW_BITS;
78 MPFR_ASSERTN(DRAW_BITS <= GMP_NUMB_BITS);
79 while (cnt == DRAW_BITS)
81 /* generate DRAW_BITS in rp[0] */
82 mpfr_rand_raw (rp, rstate, DRAW_BITS);
83 if (MPFR_UNLIKELY (rp[0] == 0))
84 cnt = DRAW_BITS;
85 else
87 count_leading_zeros (cnt, rp[0]);
88 cnt -= GMP_NUMB_BITS - DRAW_BITS;
91 if (MPFR_UNLIKELY (exp < emin + cnt))
93 /* To get here, we have been drawing more than -emin zeros
94 in a row, then return 0 or the smallest representable
95 positive number.
97 The rounding to nearest mode is subtle:
98 If exp - cnt == emin - 1, the rounding bit is set, except
99 if cnt == DRAW_BITS in which case the rounding bit is
100 outside rp[0] and must be generated. */
101 if (rnd_mode == MPFR_RNDU || rnd_mode == MPFR_RNDA
102 || (rnd_mode == MPFR_RNDN && cnt == exp - emin - 1
103 && (cnt != DRAW_BITS || random_rounding_bit (rstate))))
105 mpfr_set_ui_2exp (rop, 1, emin - 1, rnd_mode);
106 return +1;
108 else
110 MPFR_SET_ZERO (rop);
111 return -1;
114 exp -= cnt;
116 MPFR_EXP (rop) = exp; /* Warning: may be outside the current
117 exponent range */
120 /* Significand: we need generate only nbits-1 bits, since the most
121 significant is 1 */
122 mpfr_rand_raw (rp, rstate, nbits - 1);
123 n = nlimbs * GMP_NUMB_BITS - nbits;
124 if (MPFR_LIKELY (n != 0)) /* this will put the low bits to zero */
125 mpn_lshift (rp, rp, nlimbs, n);
127 /* Set the msb to 1 since it was fixed by the exponent choice */
128 rp[nlimbs - 1] |= MPFR_LIMB_HIGHBIT;
130 /* Rounding */
131 if (rnd_mode == MPFR_RNDU || rnd_mode == MPFR_RNDA
132 || (rnd_mode == MPFR_RNDN && random_rounding_bit (rstate)))
134 /* Take care of the exponent range: it may have been reduced */
135 if (exp < emin)
136 mpfr_set_ui_2exp (rop, 1, emin - 1, rnd_mode);
137 else if (exp > mpfr_get_emax ())
138 mpfr_set_inf (rop, +1); /* overflow, flag set by mpfr_check_range */
139 else
140 mpfr_nextabove (rop);
141 inex = +1;
143 else
144 inex = -1;
146 return mpfr_check_range (rop, inex, rnd_mode);