dashu_int/third_party/
rand.rs1use crate::{
41 arch::word::{DoubleWord, Word},
42 buffer::Buffer,
43 ibig::IBig,
44 math::ceil_div,
45 ops::UnsignedAbs,
46 primitive::{DWORD_BITS_USIZE, WORD_BITS_USIZE},
47 repr::{Repr, TypedReprRef::*},
48 ubig::UBig,
49};
50
51use dashu_base::Sign;
52use rand_v08::{
53 distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler},
54 prelude::Distribution,
55 Rng,
56};
57
58pub struct UniformBits {
63 bits: usize,
64}
65
66impl UniformBits {
67 #[inline]
69 pub const fn new(bits: usize) -> Self {
70 UniformBits { bits }
71 }
72}
73
74impl Distribution<UBig> for UniformBits {
75 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UBig {
76 if self.bits == 0 {
77 UBig::ZERO
78 } else if self.bits <= DWORD_BITS_USIZE {
79 let dword: DoubleWord = rng.gen();
80 UBig::from_dword(dword >> (DWORD_BITS_USIZE - self.bits))
81 } else {
82 let num_words = ceil_div(self.bits, WORD_BITS_USIZE);
83 let mut buffer = Buffer::allocate(num_words);
84 buffer.push_zeros(num_words);
85
86 rng.fill(buffer.as_mut());
87
88 let rem = self.bits % WORD_BITS_USIZE;
89 if rem != 0 {
90 *buffer.last_mut().unwrap() >>= WORD_BITS_USIZE - rem;
91 }
92
93 UBig(Repr::from_buffer(buffer))
94 }
95 }
96}
97
98impl Distribution<IBig> for UniformBits {
99 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> IBig {
100 loop {
101 let mag: UBig = self.sample(rng);
102 let neg = rng.gen();
103 if mag.is_zero() && neg {
104 continue;
108 }
109 break IBig::from_parts(Sign::from(neg), mag);
110 }
111 }
112}
113
114pub struct UniformBelow<'a> {
119 limit: &'a UBig,
120}
121
122impl<'a> UniformBelow<'a> {
123 #[inline]
125 pub const fn new(limit: &'a UBig) -> Self {
126 Self { limit }
127 }
128}
129
130impl<'a> Distribution<UBig> for UniformBelow<'a> {
131 #[inline]
132 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UBig {
133 UBig::uniform(self.limit, rng)
134 }
135}
136
137impl<'a> Distribution<IBig> for UniformBelow<'a> {
138 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> IBig {
139 loop {
140 let mag: UBig = UBig::uniform(self.limit, rng);
141 let neg = rng.gen();
142 if mag.is_zero() && neg {
143 continue;
147 }
148 break IBig::from_parts(Sign::from(neg), mag);
149 }
150 }
151}
152
153impl UBig {
154 #[inline]
156 fn uniform<R>(range: &UBig, rng: &mut R) -> UBig
157 where
158 R: Rng + ?Sized,
159 {
160 debug_assert!(!range.is_zero());
161
162 match range.repr() {
163 RefSmall(dword) => UBig::from(rng.gen_range(0..dword)),
164 RefLarge(words) => UBig::uniform_large(words, rng),
165 }
166 }
167
168 fn uniform_large<R>(words: &[Word], rng: &mut R) -> UBig
170 where
171 R: Rng + ?Sized,
172 {
173 let mut buffer = Buffer::allocate(words.len());
174 buffer.push_zeros(words.len());
175 while !try_fill_uniform(words, rng, &mut buffer) {
176 }
178 UBig(Repr::from_buffer(buffer))
179 }
180}
181
182fn try_fill_uniform<R>(words: &[Word], rng: &mut R, result: &mut [Word]) -> bool
187where
188 R: Rng + ?Sized,
189{
190 let n = words.len();
191 debug_assert!(n > 0 && result.len() == n);
192 let mut i = n - 1;
193 result[i] = rng.gen_range(0..=words[i]);
194 while result[i] == words[i] {
196 if i == 0 {
197 return false;
199 }
200 i -= 1;
201 result[i] = rng.gen();
202 if result[i] > words[i] {
203 return false;
204 }
205 }
206 rng.fill(&mut result[..i]);
207 true
208}
209
210pub struct UniformUBig {
214 range: UBig,
215 offset: UBig,
216}
217
218const fn panic_empty_range() -> ! {
220 panic!("empty range for random generation")
221}
222
223impl UniformSampler for UniformUBig {
224 type X = UBig;
225
226 #[inline]
227 fn new<B1, B2>(low: B1, high: B2) -> UniformUBig
228 where
229 B1: SampleBorrow<UBig>,
230 B2: SampleBorrow<UBig>,
231 {
232 if high.borrow() <= low.borrow() {
233 panic_empty_range()
234 }
235
236 let range = high.borrow() - low.borrow();
237 UniformUBig {
238 range,
239 offset: low.borrow().clone(),
240 }
241 }
242
243 #[inline]
244 fn new_inclusive<B1, B2>(low: B1, high: B2) -> UniformUBig
245 where
246 B1: SampleBorrow<UBig>,
247 B2: SampleBorrow<UBig>,
248 {
249 if high.borrow() < low.borrow() {
250 panic_empty_range()
251 }
252
253 let range = high.borrow() - low.borrow() + UBig::ONE;
254 UniformUBig {
255 range,
256 offset: low.borrow().clone(),
257 }
258 }
259
260 #[inline]
261 fn sample<R>(&self, rng: &mut R) -> UBig
262 where
263 R: Rng + ?Sized,
264 {
265 UBig::uniform(&self.range, rng) + &self.offset
266 }
267}
268
269pub struct UniformIBig {
273 range: UBig,
274 offset: IBig,
275}
276
277impl UniformSampler for UniformIBig {
278 type X = IBig;
279
280 #[inline]
281 fn new<B1, B2>(low: B1, high: B2) -> UniformIBig
282 where
283 B1: SampleBorrow<IBig>,
284 B2: SampleBorrow<IBig>,
285 {
286 if high.borrow() <= low.borrow() {
287 panic_empty_range()
288 }
289
290 let range = high.borrow() - low.borrow();
291 UniformIBig {
292 range: range.unsigned_abs(),
293 offset: low.borrow().clone(),
294 }
295 }
296
297 #[inline]
298 fn new_inclusive<B1, B2>(low: B1, high: B2) -> UniformIBig
299 where
300 B1: SampleBorrow<IBig>,
301 B2: SampleBorrow<IBig>,
302 {
303 if high.borrow() < low.borrow() {
304 panic_empty_range()
305 }
306
307 let range = high.borrow() - low.borrow() + IBig::ONE;
308 UniformIBig {
309 range: range.unsigned_abs(),
310 offset: low.borrow().clone(),
311 }
312 }
313
314 #[inline]
315 fn sample<R>(&self, rng: &mut R) -> IBig
316 where
317 R: Rng + ?Sized,
318 {
319 IBig::from(UBig::uniform(&self.range, rng)) + &self.offset
320 }
321}
322
323impl SampleUniform for UBig {
324 type Sampler = UniformUBig;
325}
326
327impl SampleUniform for IBig {
328 type Sampler = UniformIBig;
329}