blob: d3292db1bd1b6d21f960e4206cc081b525d7ef37 [file] [log] [blame]
Austin Schuhbb1338c2024-06-15 19:31:16 -07001/* gmp_urandomm_ui -- uniform random number 0 to N-1 for ulong N.
2
3Copyright 2003, 2004 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of either:
9
10 * the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13
14or
15
16 * the GNU General Public License as published by the Free Software
17 Foundation; either version 2 of the License, or (at your option) any
18 later version.
19
20or both in parallel, as here.
21
22The GNU MP Library is distributed in the hope that it will be useful, but
23WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25for more details.
26
27You should have received copies of the GNU General Public License and the
28GNU Lesser General Public License along with the GNU MP Library. If not,
29see https://www.gnu.org/licenses/. */
30
31#include "gmp-impl.h"
32#include "longlong.h"
33
34
35/* If n is a power of 2 then the test ret<n is always true and the loop is
36 unnecessary, but there's no need to add special code for this. Just get
37 the "bits" calculation correct and let it go through normally.
38
39 If n is 1 then will have bits==0 and _gmp_rand will produce no output and
40 we always return 0. Again there seems no need for a special case, just
41 initialize a[0]=0 and let it go through normally. */
42
43#define MAX_URANDOMM_ITER 80
44
45unsigned long
46gmp_urandomm_ui (gmp_randstate_ptr rstate, unsigned long n)
47{
48 mp_limb_t a[LIMBS_PER_ULONG];
49 unsigned long ret, bits, leading;
50 int i;
51
52 if (UNLIKELY (n == 0))
53 DIVIDE_BY_ZERO;
54
55 /* start with zeros, since if bits==0 then _gmp_rand will store nothing at
56 all (bits==0 arises when n==1), or if bits <= GMP_NUMB_BITS then it
57 will store only a[0]. */
58 a[0] = 0;
59#if LIMBS_PER_ULONG > 1
60 a[1] = 0;
61#endif
62
63 count_leading_zeros (leading, (mp_limb_t) n);
64 bits = GMP_LIMB_BITS - leading - (POW2_P(n) != 0);
65
66 for (i = 0; i < MAX_URANDOMM_ITER; i++)
67 {
68 _gmp_rand (a, rstate, bits);
69#if LIMBS_PER_ULONG == 1
70 ret = a[0];
71#else
72 ret = a[0] | (a[1] << GMP_NUMB_BITS);
73#endif
74 if (LIKELY (ret < n)) /* usually one iteration suffices */
75 goto done;
76 }
77
78 /* Too many iterations, there must be something degenerate about the
79 rstate algorithm. Return r%n. */
80 ret -= n;
81 ASSERT (ret < n);
82
83 done:
84 return ret;
85}