dashu_int/third_party/
rand.rs1use crate::{
15 arch::word::{DoubleWord, Word},
16 buffer::Buffer,
17 ibig::IBig,
18 math::ceil_div,
19 primitive::{DWORD_BITS_USIZE, WORD_BITS_USIZE},
20 repr::{Repr, TypedReprRef::*},
21 ubig::UBig,
22};
23use dashu_base::Sign;
24
25pub trait BitRng {
32 fn next_word(&mut self) -> Word;
34 fn next_double_word(&mut self) -> DoubleWord;
36 fn next_bool(&mut self) -> bool;
38 fn fill_words(&mut self, words: &mut [Word]);
40 fn gen_word_inclusive(&mut self, high: Word) -> Word;
42 fn gen_dword_exclusive(&mut self, high: DoubleWord) -> DoubleWord;
44}
45
46pub struct UniformBits {
51 bits: usize,
52}
53
54impl UniformBits {
55 #[inline]
57 pub const fn new(bits: usize) -> Self {
58 UniformBits { bits }
59 }
60
61 pub fn sample_ubig<R: BitRng + ?Sized>(&self, rng: &mut R) -> UBig {
63 if self.bits == 0 {
64 UBig::ZERO
65 } else if self.bits <= DWORD_BITS_USIZE {
66 let dword: DoubleWord = rng.next_double_word();
67 UBig::from_dword(dword >> (DWORD_BITS_USIZE - self.bits))
68 } else {
69 let num_words = ceil_div(self.bits, WORD_BITS_USIZE);
70 let mut buffer = Buffer::allocate(num_words);
71 buffer.push_zeros(num_words);
72
73 rng.fill_words(buffer.as_mut());
74
75 let rem = self.bits % WORD_BITS_USIZE;
76 if rem != 0 {
77 *buffer.last_mut().unwrap() >>= WORD_BITS_USIZE - rem;
78 }
79
80 UBig(Repr::from_buffer(buffer))
81 }
82 }
83
84 pub fn sample_ibig<R: BitRng + ?Sized>(&self, rng: &mut R) -> IBig {
86 loop {
87 let mag: UBig = self.sample_ubig(rng);
88 let neg = rng.next_bool();
89 if mag.is_zero() && neg {
90 continue;
93 }
94 break IBig::from_parts(Sign::from(neg), mag);
95 }
96 }
97}
98
99pub struct UniformBelow<'a> {
104 limit: &'a UBig,
105}
106
107impl<'a> UniformBelow<'a> {
108 #[inline]
110 pub const fn new(limit: &'a UBig) -> Self {
111 Self { limit }
112 }
113
114 #[inline]
116 pub fn sample_ubig<R: BitRng + ?Sized>(&self, rng: &mut R) -> UBig {
117 uniform(self.limit, rng)
118 }
119
120 pub fn sample_ibig<R: BitRng + ?Sized>(&self, rng: &mut R) -> IBig {
122 loop {
123 let mag: UBig = uniform(self.limit, rng);
124 let neg = rng.next_bool();
125 if mag.is_zero() && neg {
126 continue;
129 }
130 break IBig::from_parts(Sign::from(neg), mag);
131 }
132 }
133}
134
135fn uniform<R: BitRng + ?Sized>(range: &UBig, rng: &mut R) -> UBig {
137 debug_assert!(!range.is_zero());
138
139 match range.repr() {
140 RefSmall(dword) => UBig::from(rng.gen_dword_exclusive(dword)),
141 RefLarge(words) => uniform_large(words, rng),
142 }
143}
144
145fn uniform_large<R: BitRng + ?Sized>(words: &[Word], rng: &mut R) -> UBig {
147 let mut buffer = Buffer::allocate(words.len());
148 buffer.push_zeros(words.len());
149 while !try_fill_uniform(words, rng, &mut buffer) {
150 }
152 UBig(Repr::from_buffer(buffer))
153}
154
155fn try_fill_uniform<R: BitRng + ?Sized>(words: &[Word], rng: &mut R, result: &mut [Word]) -> bool {
159 let n = words.len();
160 debug_assert!(n > 0 && result.len() == n);
161 let mut i = n - 1;
162 result[i] = rng.gen_word_inclusive(words[i]);
163 while result[i] == words[i] {
165 if i == 0 {
166 return false;
168 }
169 i -= 1;
170 result[i] = rng.next_word();
171 if result[i] > words[i] {
172 return false;
173 }
174 }
175 rng.fill_words(&mut result[..i]);
176 true
177}
178
179pub struct UniformUBig {
181 pub(crate) range: UBig,
182 pub(crate) offset: UBig,
183}
184
185impl UniformUBig {
186 #[inline]
187 pub(crate) const fn from_parts(range: UBig, offset: UBig) -> Self {
188 UniformUBig { range, offset }
189 }
190
191 #[inline]
193 pub fn sample<R: BitRng + ?Sized>(&self, rng: &mut R) -> UBig {
194 uniform(&self.range, rng) + &self.offset
195 }
196}
197
198pub struct UniformIBig {
200 pub(crate) range: UBig,
201 pub(crate) offset: IBig,
202}
203
204impl UniformIBig {
205 #[inline]
206 pub(crate) const fn from_parts(range: UBig, offset: IBig) -> Self {
207 UniformIBig { range, offset }
208 }
209
210 #[inline]
212 pub fn sample<R: BitRng + ?Sized>(&self, rng: &mut R) -> IBig {
213 IBig::from(uniform(&self.range, rng)) + &self.offset
214 }
215}
216
217#[cfg(feature = "rand_v08")]
219pub fn bridge_v08<'a, R: rand_v08::Rng + ?Sized>(rng: &'a mut R) -> impl BitRng + 'a {
220 super::rand_v08::RngBridge(rng)
221}
222
223#[cfg(feature = "rand_v09")]
225pub fn bridge_v09<'a, R: rand_v09::Rng + ?Sized>(rng: &'a mut R) -> impl BitRng + 'a {
226 super::rand_v09::RngBridge(rng)
227}
228
229#[cfg(feature = "rand_v010")]
231pub fn bridge_v010<'a, R: rand_v010::Rng + ?Sized>(rng: &'a mut R) -> impl BitRng + 'a {
232 super::rand_v010::RngBridge(rng)
233}