use num::Float;
pub trait PercentageVariance {
fn jitter_percentage(&self, percentage: f64) -> Self;
}
pub trait FixedNumberVariance<T: Float> {
fn jitter_within(&self, upto: T) -> T;
}
macro_rules! implement_float_variance {
([$($t:ty),*]) => { $( implement_float_variance!($t); )+ };
($t:ty) => { implement_float_variance!(reactor U64, u64, 63, $t); };
(reactor $r:ident, $type:ty, $mantissa_bits:literal, $t:ty) => {paste::paste!{
impl FixedNumberVariance<$t> for $t {
fn jitter_within(&self, upto: Self) -> Self {
use super::DiceExt;
if upto <= 0.0 { return *self; }
let raw_bits = 1_u64.d($type::MAX as usize);
let mantissa_bits = ([<$t>]::MANTISSA_DIGITS as u32).min($mantissa_bits);
let max_mask = ((1 as $type) << mantissa_bits) - 1;
let scale = (raw_bits & max_mask) as $t / max_mask as $t;
self + ((scale * 2.0 * upto ) - upto)
}
}
impl PercentageVariance for $t {
fn jitter_percentage(&self, percentage: f64) -> Self {
let p = 0.01 * percentage as $t;
self.jitter_within( self.abs() * p )
}
}
}};
}
implement_float_variance!([f32,f64]);
#[cfg(feature = "f128-stable")]
implement_float_variance!(f128);