impl UniformSampler for DecimalSampler { type X = Decimal;
/// Creates a new sampler that will yield random decimal objects between `low` and `high`. /// /// The sampler will always provide decimals at the same scale as the inputs; if the inputs /// have different scales, the higher scale is used. /// /// # Example /// /// ``` /// # use rand::Rng; /// # use rust_decimal_macros::dec; /// let mut rng = rand::rngs::OsRng; /// let random = rng.gen_range(dec!(1.00)..dec!(2.00)); /// assert!(random >= dec!(1.00)); /// assert!(random < dec!(2.00)); /// assert_eq!(random.scale(), 2); /// ``` #[inline] fn new<B1, B2>(low: B1, high: B2) -> Self where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{ let (low, high) = sync_scales(*low.borrow(), *high.borrow()); let high = Decimal::from_i128_with_scale(high.mantissa() - 1, high.scale());
UniformSampler::new_inclusive(low, high)
}
/// Creates a new sampler that will yield random decimal objects between `low` and `high`. /// /// The sampler will always provide decimals at the same scale as the inputs; if the inputs /// have different scales, the higher scale is used. /// /// # Example /// /// ``` /// # use rand::Rng; /// # use rust_decimal_macros::dec; /// let mut rng = rand::rngs::OsRng; /// let random = rng.gen_range(dec!(1.00)..=dec!(2.00)); /// assert!(random >= dec!(1.00)); /// assert!(random <= dec!(2.00)); /// assert_eq!(random.scale(), 2); /// ``` #[inline] fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{ let (low, high) = sync_scales(*low.borrow(), *high.borrow());
// Return our sampler, which contains an underlying i128 sampler so we // outsource the actual randomness implementation. Self {
mantissa_sampler: UniformInt::new_inclusive(low.mantissa(), high.mantissa()),
scale: low.scale(),
}
}
/// Return equivalent Decimal objects with the same scale as one another. #[inline] fn sync_scales(mut a: Decimal, mut b: Decimal) -> (Decimal, Decimal) { if a.scale() == b.scale() { return (a, b);
}
// Set scales to match one another, because we are relying on mantissas' // being comparable in order outsource the actual sampling implementation.
a.rescale(a.scale().max(b.scale()));
b.rescale(a.scale().max(b.scale()));
// Edge case: If the values have _wildly_ different scales, the values may not have rescaled far enough to match one another. // // In this case, we accept some precision loss because the randomization approach we are using assumes that the scales will necessarily match. if a.scale() != b.scale() {
a.rescale(a.scale().min(b.scale()));
b.rescale(a.scale().min(b.scale()));
}
(a, b)
}
#[cfg(test)] mod tests { use std::collections::HashSet;
usesuper::*;
macro_rules! dec {
($e:expr) => {
Decimal::from_str_exact(stringify!($e)).unwrap()
};
}
#[test] fn generates_within_range() { letmut rng = rand::rngs::OsRng; for _ in0..128 { let random = rng.gen_range(dec!(1.00)..dec!(1.05));
assert!(random < dec!(1.05));
assert!(random >= dec!(1.00));
}
}
#[test] fn generates_within_inclusive_range() { letmut rng = rand::rngs::OsRng; letmut values: HashSet<Decimal> = HashSet::new(); for _ in0..256 { let random = rng.gen_range(dec!(1.00)..=dec!(1.01)); // The scale is 2, so 1.00 and 1.01 are the only two valid choices.
assert!(random == dec!(1.00) || random == dec!(1.01));
values.insert(random);
} // Somewhat flaky, will fail 1 out of every 2^255 times this is run. // Probably acceptable in the real world.
assert_eq!(values.len(), 2);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.