1pub(crate) use self::f32::F32U;
21pub(crate) use self::f64::F64U;
22
23macro_rules! float_sampler {
24 ($typ: ident, $int_typ: ident, $wrapper: ident) => {
25 pub mod $typ {
26 use rand::prelude::*;
27 use rand::distributions::uniform::{
28 SampleBorrow, SampleUniform, UniformSampler,
29 };
30 #[cfg(not(feature = "std"))]
31 use num_traits::float::Float;
32
33 #[must_use]
34 fn next_down(a: $typ) -> $typ {
37 debug_assert!(a.is_finite() && a > $typ::MIN, "`next_down` invalid input: {}", a);
38 if a == (0.) {
39 -$typ::from_bits(1)
40 } else if a < 0. {
41 $typ::from_bits(a.to_bits() + 1)
42 } else {
43 $typ::from_bits(a.to_bits() - 1)
44 }
45 }
46
47 #[must_use]
48 fn ulp(a: $typ) -> $typ {
52 debug_assert!(a.is_finite() && a > $typ::MIN, "`ulp` invalid input: {}", a);
53 a.abs() - next_down(a.abs())
54 }
55
56 #[derive(Copy, Clone, Debug)]
57 pub(crate) struct $wrapper($typ);
58
59 impl From<$typ> for $wrapper {
60 fn from(x: $typ) -> Self {
61 $wrapper(x)
62 }
63 }
64 impl From<$wrapper> for $typ {
65 fn from(x: $wrapper) -> Self {
66 x.0
67 }
68 }
69
70 #[derive(Clone, Copy, Debug)]
71 pub(crate) struct FloatUniform {
72 low: $typ,
73 high: $typ,
74 intervals: IntervalCollection,
75 inclusive: bool,
76 }
77
78 impl UniformSampler for FloatUniform {
79
80 type X = $wrapper;
81
82 fn new<B1, B2>(low: B1, high: B2) -> Self
83 where
84 B1: SampleBorrow<Self::X> + Sized,
85 B2: SampleBorrow<Self::X> + Sized,
86 {
87 let low = low.borrow().0;
88 let high = high.borrow().0;
89 FloatUniform {
90 low,
91 high,
92 intervals: split_interval([low, high]),
93 inclusive: false,
94 }
95 }
96
97 fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
98 where
99 B1: SampleBorrow<Self::X> + Sized,
100 B2: SampleBorrow<Self::X> + Sized,
101 {
102 let low = low.borrow().0;
103 let high = high.borrow().0;
104
105 FloatUniform {
106 low,
107 high,
108 intervals: split_interval([low, high]),
109 inclusive: true,
110 }
111 }
112
113 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
114 let mut intervals = self.intervals;
115 while intervals.count > 1 {
116 let new_interval = intervals.get(rng.gen_range(0..intervals.count));
117 intervals = split_interval(new_interval);
118 }
119 let last = intervals.get(0);
120 let result = *last.choose(rng).expect("Slice is not empty");
121
122 let clamped_result = if result < self.low {
126 debug_assert!(self.low - result < self.intervals.step);
127 self.low
128 } else if result > self.high{
129 debug_assert!(result - self.high < self.intervals.step);
130 self.high
131 } else {
132 result
133 };
134
135 if !self.inclusive && clamped_result == self.high {
136 return $wrapper(next_down(self.high));
137 };
138
139 $wrapper(clamped_result)
140 }
141 }
142
143 impl SampleUniform for $wrapper {
144 type Sampler = FloatUniform;
145 }
146
147 #[derive(Clone, Copy, Debug)]
150 struct IntervalCollection {
151 start: $typ,
152 step: $typ,
153 count: $int_typ,
154 }
155
156 fn split_interval([low, high]: [$typ; 2]) -> IntervalCollection {
157 assert!(low.is_finite(), "low finite");
158 assert!(high.is_finite(), "high finite");
159 assert!(high - low > 0., "invalid range");
160
161 let min_abs = $typ::min(low.abs(), high.abs());
162 let max_abs = $typ::max(low.abs(), high.abs());
163
164 let gap = ulp(max_abs);
165
166 let (start, step) = if low.abs() < high.abs() {
167 (high, -gap)
168 } else {
169 (low, gap)
170 };
171
172 let min_gaps = min_abs / gap;
173 let max_gaps = max_abs / gap;
174 debug_assert!(
175 max_gaps.floor() == max_gaps,
176 "max_gaps is an integer"
177 );
178
179 let count = if low.signum() == high.signum() {
180 max_gaps as $int_typ - min_gaps.floor() as $int_typ
181 } else {
182 if min_gaps == 0. && min_abs > 0. {
185 max_gaps as $int_typ + 1
186 } else {
187 max_gaps as $int_typ + min_gaps.ceil() as $int_typ
188 }
189 };
190
191 debug_assert!(count - 1 <= 2 * MAX_PRECISE_INT);
192
193 IntervalCollection {
194 start,
195 step,
196 count,
197 }
198 }
199
200
201 impl IntervalCollection {
202 fn get(&self, index: $int_typ) -> [$typ; 2] {
203 assert!(index < self.count, "index out of bounds");
204
205 let x = ((index / 2) as $typ).mul_add(
211 2. * self.step,
212 (index % 2) as $typ * self.step + self.start,
213 );
214
215 let y = x + self.step;
216
217 if self.step > 0. {
218 [x, y]
219 } else {
220 [y, x]
221 }
222 }
223 }
224
225
226 const MAX_PRECISE_INT: $int_typ =
228 (2 as $int_typ).pow($typ::MANTISSA_DIGITS);
229
230 #[cfg(test)]
231 mod test {
232
233 use super::*;
234 use crate::prelude::*;
235
236 fn sort((left, right): ($typ, $typ)) -> ($typ, $typ) {
237 if left < right {
238 (left, right)
239 } else {
240 (right, left)
241 }
242 }
243
244 fn finite() -> impl Strategy<Value = $typ> {
245 prop::num::$typ::NEGATIVE
246 | prop::num::$typ::POSITIVE
247 | prop::num::$typ::NORMAL
248 | prop::num::$typ::SUBNORMAL
249 | prop::num::$typ::ZERO
250 }
251
252 fn bounds() -> impl Strategy<Value = ($typ, $typ)> {
253 (finite(), finite())
254 .prop_filter("Bounds can't be equal", |(a, b)| a != b)
255 .prop_map(sort)
256 }
257
258 #[test]
259 fn range_test() {
260 use crate::test_runner::{RngAlgorithm, TestRng};
261
262 let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default());
263 let (low, high) = (-1., 10.);
264 let uniform = FloatUniform::new($wrapper(low), $wrapper(high));
265
266 let samples = (0..100)
267 .map(|_| $typ::from(uniform.sample(&mut test_rng)));
268 for s in samples {
269 assert!(low <= s && s < high);
270 }
271 }
272
273 #[test]
274 fn range_end_bound_test() {
275 use crate::test_runner::{RngAlgorithm, TestRng};
276
277 let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default());
278 let (low, high) = (1., 1. + $typ::EPSILON);
279 let uniform = FloatUniform::new($wrapper(low), $wrapper(high));
280
281 let mut samples = (0..100)
282 .map(|_| $typ::from(uniform.sample(&mut test_rng)));
283 assert!(samples.all(|x| x == 1.));
284 }
285
286 #[test]
287 fn inclusive_range_test() {
288 use crate::test_runner::{RngAlgorithm, TestRng};
289
290 let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default());
291 let (low, high) = (-1., 10.);
292 let uniform = FloatUniform::new_inclusive($wrapper(low), $wrapper(high));
293
294 let samples = (0..100)
295 .map(|_| $typ::from(uniform.sample(&mut test_rng)));
296 for s in samples {
297 assert!(low <= s && s <= high);
298 }
299 }
300
301 #[test]
302 fn inclusive_range_end_bound_test() {
303 use crate::test_runner::{RngAlgorithm, TestRng};
304
305 let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default());
306 let (low, high) = (1., 1. + $typ::EPSILON);
307 let uniform = FloatUniform::new_inclusive($wrapper(low), $wrapper(high));
308
309 let mut samples = (0..100)
310 .map(|_| $typ::from(uniform.sample(&mut test_rng)));
311 assert!(samples.any(|x| x == 1. + $typ::EPSILON));
312 }
313
314 #[test]
315 fn all_floats_in_range_are_possible_1() {
316 use crate::test_runner::{RngAlgorithm, TestRng};
317
318 let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default());
319 let (low, high) = (1. - $typ::EPSILON, 1. + $typ::EPSILON);
320 let uniform = FloatUniform::new_inclusive($wrapper(low), $wrapper(high));
321
322 let mut samples = (0..100)
323 .map(|_| $typ::from(uniform.sample(&mut test_rng)));
324 assert!(samples.any(|x| x == 1. - $typ::EPSILON / 2.));
325 }
326
327 #[test]
328 fn all_floats_in_range_are_possible_2() {
329 use crate::test_runner::{RngAlgorithm, TestRng};
330
331 let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default());
332 let (low, high) = (0., MAX_PRECISE_INT as $typ);
333 let uniform = FloatUniform::new_inclusive($wrapper(low), $wrapper(high));
334
335 let mut samples = (0..100)
336 .map(|_| $typ::from(uniform.sample(&mut test_rng)))
337 .map(|x| x.fract());
338
339 assert!(samples.any(|x| x != 0.));
340 }
341
342 #[test]
343 fn max_precise_int_plus_one_is_rounded_down() {
344 assert_eq!(((MAX_PRECISE_INT + 1) as $typ) as $int_typ, MAX_PRECISE_INT);
345 }
346
347 proptest! {
348 #[test]
349 fn next_down_less_than_float(val in finite()) {
350 prop_assume!(val > $typ::MIN);
351 prop_assert!(next_down(val) < val);
352 }
353
354 #[test]
355 fn no_value_between_float_and_next_down(val in finite()) {
356 prop_assume!(val > $typ::MIN);
357 let prev = next_down(val);
358 let avg = prev / 2. + val / 2.;
359 prop_assert!(avg == prev || avg == val);
360 }
361
362 #[test]
363 fn values_less_than_or_equal_to_max_precise_int_are_not_rounded(i in 0..=MAX_PRECISE_INT) {
364 prop_assert_eq!((i as $typ) as $int_typ, i);
365 }
366
367 #[test]
368 fn indivisible_intervals_are_split_to_self(val in finite()) {
369 prop_assume!(val > $typ::MIN);
370 let prev = next_down(val);
371 let intervals = split_interval([prev, val]);
372 prop_assert_eq!(intervals.count, 1);
373 }
374
375 #[test]
376 fn split_intervals_are_the_same_size(
377 (low, high) in bounds(),
378 indices: [prop::sample::Index; 32]) {
379
380 let intervals = split_interval([low, high]);
381
382 let size = (intervals.count - 1) as usize;
383 prop_assume!(size > 0);
384
385 let mut it = indices.iter()
386 .map(|i| i.index(size) as $int_typ)
387 .map(|i| intervals.get(i))
388 .map(|[low, high]| high - low);
389
390 let interval_size = it.next().unwrap();
391 let all_equal = it.all(|g| g == interval_size);
392 prop_assert!(all_equal);
393 }
394
395 #[test]
396 fn split_intervals_are_consecutive(
397 (low, high) in bounds(),
398 indices: [prop::sample::Index; 32]) {
399
400 let intervals = split_interval([low, high]);
401
402 let size = (intervals.count - 1) as usize;
403 prop_assume!(size > 1);
404
405 let mut it = indices.iter()
406 .map(|i| i.index(size - 1) as $int_typ)
407 .map(|i| (intervals.get(i), intervals.get(i + 1)));
408
409 let ascending = it.all(|([_, h1], [l2, _])| h1 == l2);
410 let descending = it.all(|([l1, _], [_, h2])| l1 == h2);
411
412 prop_assert!(ascending || descending);
413 }
414
415 #[test]
416 fn first_split_might_slightly_overshoot_one_bound((low, high) in bounds()) {
417 let intervals = split_interval([low, high]);
418 let start = intervals.get(0);
419 let end = intervals.get(intervals.count - 1);
420 let (low_interval, high_interval) = if start[0] < end[0] {
421 (start, end)
422 } else {
423 (end, start)
424 };
425
426 prop_assert!(
427 low == low_interval[0] && high_interval[0] < high && high <= high_interval[1] ||
428 low_interval[0] <= low && low < low_interval[1] && high == high_interval[1]);
429 }
430
431 #[test]
432 fn subsequent_splits_always_match_bounds(
433 (low, high) in bounds(),
434 index: prop::sample::Index) {
435 let intervals = split_interval([low, high]);
439 let size = (intervals.count - 1) as usize;
440
441 let interval = intervals.get(index.index(size) as $int_typ);
442 let small_intervals = split_interval(interval);
443
444 let start = small_intervals.get(0);
445 let end = small_intervals.get(small_intervals.count - 1);
446 let (low_interval, high_interval) = if start[0] < end[0] {
447 (start, end)
448 } else {
449 (end, start)
450 };
451
452 prop_assert!(
453 interval[0] == low_interval[0] &&
454 interval[1] == high_interval[1]);
455 }
456 }
457 }
458 }
459 };
460}
461
462float_sampler!(f32, u32, F32U);
463float_sampler!(f64, u64, F64U);