use crate::bools::random::{random_bools, RandomBools};
use crate::iterators::{
nonzero_values, with_special_value, with_special_values, NonzeroValues, WithSpecialValue,
WithSpecialValues,
};
use crate::num::arithmetic::traits::{Parity, PowerOf2, ShrRound};
use crate::num::basic::floats::PrimitiveFloat;
use crate::num::basic::integers::PrimitiveInt;
use crate::num::basic::signeds::PrimitiveSigned;
use crate::num::basic::unsigneds::PrimitiveUnsigned;
use crate::num::conversion::traits::WrappingFrom;
use crate::num::float::NiceFloat;
use crate::num::iterators::{iterator_to_bit_chunks, IteratorToBitChunks};
use crate::num::logic::traits::{BitAccess, SignificantBits};
use crate::num::random::geometric::{
geometric_random_signed_inclusive_range, geometric_random_unsigned_inclusive_range,
geometric_random_unsigneds, GeometricRandomNaturalValues, GeometricRandomSignedRange,
};
use crate::random::{Seed, EXAMPLE_SEED};
use crate::rounding_modes::RoundingMode;
use crate::vecs::{random_values_from_vec, RandomValuesFromVec};
use itertools::Itertools;
use rand::Rng;
use rand_chacha::ChaCha20Rng;
use std::collections::HashMap;
use std::convert::identity;
use std::fmt::Debug;
use std::marker::PhantomData;
#[doc(hidden)]
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct ThriftyRandomState {
x: u32,
bits_left: u64,
}
#[doc(hidden)]
pub trait HasRandomPrimitiveInts {
type State: Clone + Debug;
fn new_state() -> Self::State;
fn get_random(rng: &mut ChaCha20Rng, state: &mut Self::State) -> Self;
}
macro_rules! impl_trivial_random_primitive_ints {
($t: ident) => {
impl HasRandomPrimitiveInts for $t {
type State = ();
#[inline]
fn new_state() -> () {}
#[inline]
fn get_random(rng: &mut ChaCha20Rng, _state: &mut ()) -> $t {
rng.gen()
}
}
};
}
impl_trivial_random_primitive_ints!(u32);
impl_trivial_random_primitive_ints!(u64);
impl_trivial_random_primitive_ints!(u128);
impl_trivial_random_primitive_ints!(usize);
impl_trivial_random_primitive_ints!(i32);
impl_trivial_random_primitive_ints!(i64);
impl_trivial_random_primitive_ints!(i128);
impl_trivial_random_primitive_ints!(isize);
fn get_random<T: PrimitiveInt>(rng: &mut ChaCha20Rng, state: &mut ThriftyRandomState) -> T {
if state.bits_left == 0 {
state.x = rng.gen();
state.bits_left = u32::WIDTH - T::WIDTH;
} else {
state.x >>= T::WIDTH;
state.bits_left -= T::WIDTH;
}
T::wrapping_from(state.x)
}
macro_rules! impl_thrifty_random_primitive_ints {
($t: ident) => {
impl HasRandomPrimitiveInts for $t {
type State = ThriftyRandomState;
#[inline]
fn new_state() -> ThriftyRandomState {
ThriftyRandomState { x: 0, bits_left: 0 }
}
#[inline]
fn get_random(rng: &mut ChaCha20Rng, state: &mut ThriftyRandomState) -> $t {
get_random(rng, state)
}
}
};
}
impl_thrifty_random_primitive_ints!(u8);
impl_thrifty_random_primitive_ints!(u16);
impl_thrifty_random_primitive_ints!(i8);
impl_thrifty_random_primitive_ints!(i16);
#[derive(Clone, Debug)]
pub struct RandomPrimitiveInts<T: HasRandomPrimitiveInts> {
pub(crate) rng: ChaCha20Rng,
pub(crate) state: T::State,
}
impl<T: HasRandomPrimitiveInts> Iterator for RandomPrimitiveInts<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
Some(T::get_random(&mut self.rng, &mut self.state))
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug)]
pub enum RandomUnsignedsLessThan<T: PrimitiveUnsigned> {
One,
AtLeastTwo(RandomUnsignedBitChunks<T>, T),
}
impl<T: PrimitiveUnsigned> Iterator for RandomUnsignedsLessThan<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
match *self {
RandomUnsignedsLessThan::One => Some(T::ZERO),
RandomUnsignedsLessThan::AtLeastTwo(ref mut xs, limit) => loop {
let x = xs.next();
if x.unwrap() < limit {
return x;
}
},
}
}
}
#[derive(Clone, Debug)]
pub struct RandomUnsignedRange<T: PrimitiveUnsigned> {
pub(crate) xs: RandomUnsignedsLessThan<T>,
pub(crate) a: T,
}
impl<T: PrimitiveUnsigned> Iterator for RandomUnsignedRange<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
self.xs.next().map(|x| x + self.a)
}
}
#[derive(Clone, Debug)]
pub enum RandomUnsignedInclusiveRange<T: PrimitiveUnsigned> {
NotAll(RandomUnsignedsLessThan<T>, T),
All(RandomPrimitiveInts<T>),
}
impl<T: PrimitiveUnsigned> Iterator for RandomUnsignedInclusiveRange<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
match self {
RandomUnsignedInclusiveRange::NotAll(xs, a) => xs.next().map(|x| x + *a),
RandomUnsignedInclusiveRange::All(xs) => xs.next(),
}
}
}
#[doc(hidden)]
pub trait HasRandomSignedRange: Sized {
type UnsignedValue: PrimitiveUnsigned;
fn new_unsigned_range(seed: Seed, a: Self, b: Self)
-> RandomUnsignedRange<Self::UnsignedValue>;
fn new_unsigned_inclusive_range(
seed: Seed,
a: Self,
b: Self,
) -> RandomUnsignedInclusiveRange<Self::UnsignedValue>;
fn from_unsigned_value(x: Self::UnsignedValue) -> Self;
}
macro_rules! impl_has_random_signed_range {
($u: ident, $s: ident) => {
impl HasRandomSignedRange for $s {
type UnsignedValue = $u;
fn new_unsigned_range(seed: Seed, mut a: $s, mut b: $s) -> RandomUnsignedRange<$u> {
a.flip_bit($u::WIDTH - 1);
b.flip_bit($u::WIDTH - 1);
random_unsigned_range(seed, $u::wrapping_from(a), $u::wrapping_from(b))
}
fn new_unsigned_inclusive_range(
seed: Seed,
mut a: $s,
mut b: $s,
) -> RandomUnsignedInclusiveRange<$u> {
a.flip_bit($u::WIDTH - 1);
b.flip_bit($u::WIDTH - 1);
random_unsigned_inclusive_range(seed, $u::wrapping_from(a), $u::wrapping_from(b))
}
fn from_unsigned_value(mut u: $u) -> $s {
u.flip_bit($u::WIDTH - 1);
$s::wrapping_from(u)
}
}
};
}
apply_to_unsigned_signed_pairs!(impl_has_random_signed_range);
#[derive(Clone, Debug)]
pub struct RandomSignedRange<T: HasRandomSignedRange> {
pub(crate) xs: RandomUnsignedRange<T::UnsignedValue>,
}
impl<T: HasRandomSignedRange> Iterator for RandomSignedRange<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.xs.next().map(T::from_unsigned_value)
}
}
#[derive(Clone, Debug)]
pub struct RandomSignedInclusiveRange<T: HasRandomSignedRange> {
pub(crate) xs: RandomUnsignedInclusiveRange<T::UnsignedValue>,
}
impl<T: HasRandomSignedRange> Iterator for RandomSignedInclusiveRange<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.xs.next().map(T::from_unsigned_value)
}
}
#[derive(Clone, Debug)]
pub struct RandomUnsignedBitChunks<T: PrimitiveUnsigned> {
xs: IteratorToBitChunks<RandomPrimitiveInts<T>, T, T>,
}
impl<T: PrimitiveUnsigned> Iterator for RandomUnsignedBitChunks<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.xs.next_with_wrapping(identity).map(Option::unwrap)
}
}
#[doc(hidden)]
pub trait RandomSignedChunkable: Sized {
type AbsoluteChunks: Clone + Debug;
fn new_absolute_chunks(seed: Seed, chunk_size: u64) -> Self::AbsoluteChunks;
fn next_chunk(xs: &mut Self::AbsoluteChunks) -> Option<Self>;
}
macro_rules! impl_random_signed_chunkable {
($u: ident, $s: ident) => {
impl RandomSignedChunkable for $s {
type AbsoluteChunks = RandomUnsignedBitChunks<$u>;
fn new_absolute_chunks(seed: Seed, chunk_size: u64) -> RandomUnsignedBitChunks<$u> {
random_unsigned_bit_chunks(seed, chunk_size)
}
fn next_chunk(xs: &mut Self::AbsoluteChunks) -> Option<$s> {
xs.next().map(WrappingFrom::wrapping_from)
}
}
};
}
apply_to_unsigned_signed_pairs!(impl_random_signed_chunkable);
#[derive(Clone, Debug)]
pub struct RandomSignedBitChunks<T: RandomSignedChunkable> {
pub(crate) xs: T::AbsoluteChunks,
}
impl<T: RandomSignedChunkable> Iterator for RandomSignedBitChunks<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
T::next_chunk(&mut self.xs)
}
}
#[derive(Clone, Debug)]
pub struct RandomHighestBitSetValues<I: Iterator>
where
I::Item: PrimitiveInt,
{
pub(crate) xs: I,
pub(crate) mask: I::Item,
}
impl<I: Iterator> Iterator for RandomHighestBitSetValues<I>
where
I::Item: PrimitiveInt,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
self.xs.next().map(|x| x | self.mask)
}
}
#[inline]
pub fn random_primitive_ints<T: PrimitiveInt>(seed: Seed) -> RandomPrimitiveInts<T> {
RandomPrimitiveInts {
rng: seed.get_rng(),
state: T::new_state(),
}
}
#[inline]
pub fn random_positive_unsigneds<T: PrimitiveUnsigned>(
seed: Seed,
) -> NonzeroValues<RandomPrimitiveInts<T>> {
nonzero_values(random_primitive_ints(seed))
}
#[inline]
pub fn random_positive_signeds<T: PrimitiveSigned>(
seed: Seed,
) -> NonzeroValues<RandomSignedBitChunks<T>> {
nonzero_values(random_natural_signeds(seed))
}
#[inline]
pub fn random_negative_signeds<T: PrimitiveSigned>(
seed: Seed,
) -> RandomHighestBitSetValues<RandomSignedBitChunks<T>> {
RandomHighestBitSetValues {
xs: random_signed_bit_chunks(seed, T::WIDTH - 1),
mask: T::MIN,
}
}
#[inline]
pub fn random_natural_signeds<T: PrimitiveSigned>(seed: Seed) -> RandomSignedBitChunks<T> {
random_signed_bit_chunks(seed, T::WIDTH - 1)
}
#[inline]
pub fn random_nonzero_signeds<T: PrimitiveSigned>(
seed: Seed,
) -> NonzeroValues<RandomPrimitiveInts<T>> {
nonzero_values(random_primitive_ints(seed))
}
pub fn random_unsigneds_less_than<T: PrimitiveUnsigned>(
seed: Seed,
limit: T,
) -> RandomUnsignedsLessThan<T> {
if limit == T::ZERO {
panic!("limit cannot be 0.");
} else if limit == T::ONE {
RandomUnsignedsLessThan::One
} else {
RandomUnsignedsLessThan::AtLeastTwo(
random_unsigned_bit_chunks(seed, limit.ceiling_log_base_2()),
limit,
)
}
}
pub fn random_unsigned_range<T: PrimitiveUnsigned>(
seed: Seed,
a: T,
b: T,
) -> RandomUnsignedRange<T> {
if a >= b {
panic!("a must be less than b. a: {}, b: {}", a, b);
}
RandomUnsignedRange {
xs: random_unsigneds_less_than(seed, b - a),
a,
}
}
pub fn random_unsigned_inclusive_range<T: PrimitiveUnsigned>(
seed: Seed,
a: T,
b: T,
) -> RandomUnsignedInclusiveRange<T> {
if a > b {
panic!("a must be less than or equal to b. a: {}, b: {}", a, b);
}
if a == T::ZERO && b == T::MAX {
RandomUnsignedInclusiveRange::All(random_primitive_ints(seed))
} else {
RandomUnsignedInclusiveRange::NotAll(random_unsigneds_less_than(seed, b - a + T::ONE), a)
}
}
#[inline]
pub fn random_signed_range<T: PrimitiveSigned>(seed: Seed, a: T, b: T) -> RandomSignedRange<T> {
if a >= b {
panic!("a must be less than b. a: {}, b: {}", a, b);
}
RandomSignedRange {
xs: T::new_unsigned_range(seed, a, b),
}
}
#[inline]
pub fn random_signed_inclusive_range<T: PrimitiveSigned>(
seed: Seed,
a: T,
b: T,
) -> RandomSignedInclusiveRange<T> {
if a > b {
panic!("a must be less than or equal to b. a: {}, b: {}", a, b);
}
RandomSignedInclusiveRange {
xs: T::new_unsigned_inclusive_range(seed, a, b),
}
}
pub fn random_unsigned_bit_chunks<T: PrimitiveUnsigned>(
seed: Seed,
chunk_size: u64,
) -> RandomUnsignedBitChunks<T> {
RandomUnsignedBitChunks {
xs: iterator_to_bit_chunks(random_primitive_ints(seed), T::WIDTH, chunk_size),
}
}
pub fn random_signed_bit_chunks<T: PrimitiveSigned>(
seed: Seed,
chunk_size: u64,
) -> RandomSignedBitChunks<T> {
assert!(chunk_size <= T::WIDTH);
RandomSignedBitChunks {
xs: T::new_absolute_chunks(seed, chunk_size),
}
}
#[inline]
pub fn random_highest_bit_set_unsigneds<T: PrimitiveUnsigned>(
seed: Seed,
) -> RandomHighestBitSetValues<RandomUnsignedBitChunks<T>> {
RandomHighestBitSetValues {
xs: random_unsigned_bit_chunks(seed, T::WIDTH - 1),
mask: T::power_of_2(T::WIDTH - 1),
}
}
#[derive(Clone, Debug)]
pub struct RandomPrimitiveFloatRange<T: PrimitiveFloat> {
phantom: PhantomData<*const T>,
xs: RandomUnsignedRange<u64>,
}
impl<T: PrimitiveFloat> Iterator for RandomPrimitiveFloatRange<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.xs.next().map(T::from_ordered_representation)
}
}
#[derive(Clone, Debug)]
pub struct RandomPrimitiveFloatInclusiveRange<T: PrimitiveFloat> {
phantom: PhantomData<*const T>,
xs: RandomUnsignedInclusiveRange<u64>,
}
impl<T: PrimitiveFloat> Iterator for RandomPrimitiveFloatInclusiveRange<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.xs.next().map(T::from_ordered_representation)
}
}
#[inline]
pub fn random_primitive_float_range<T: PrimitiveFloat>(
seed: Seed,
a: T,
b: T,
) -> RandomPrimitiveFloatRange<T> {
assert!(!a.is_nan());
assert!(!b.is_nan());
if NiceFloat(a) >= NiceFloat(b) {
panic!(
"a must be less than b. a: {}, b: {}",
NiceFloat(a),
NiceFloat(b)
);
}
RandomPrimitiveFloatRange {
phantom: PhantomData,
xs: random_unsigned_range(
seed,
a.to_ordered_representation(),
b.to_ordered_representation(),
),
}
}
#[inline]
pub fn random_primitive_float_inclusive_range<T: PrimitiveFloat>(
seed: Seed,
a: T,
b: T,
) -> RandomPrimitiveFloatInclusiveRange<T> {
assert!(!a.is_nan());
assert!(!b.is_nan());
if NiceFloat(a) > NiceFloat(b) {
panic!(
"a must be less than or equal to b. a: {}, b: {}",
NiceFloat(a),
NiceFloat(b)
);
}
RandomPrimitiveFloatInclusiveRange {
phantom: PhantomData,
xs: random_unsigned_inclusive_range(
seed,
a.to_ordered_representation(),
b.to_ordered_representation(),
),
}
}
#[inline]
pub fn random_positive_finite_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
) -> RandomPrimitiveFloatInclusiveRange<T> {
random_primitive_float_inclusive_range(seed, T::MIN_POSITIVE_SUBNORMAL, T::MAX_FINITE)
}
#[inline]
pub fn random_negative_finite_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
) -> RandomPrimitiveFloatInclusiveRange<T> {
random_primitive_float_inclusive_range(seed, -T::MAX_FINITE, -T::MIN_POSITIVE_SUBNORMAL)
}
#[inline]
pub fn random_nonzero_finite_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
) -> NonzeroValues<RandomPrimitiveFloatInclusiveRange<T>> {
nonzero_values(random_finite_primitive_floats(seed))
}
#[inline]
pub fn random_finite_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
) -> RandomPrimitiveFloatInclusiveRange<T> {
random_primitive_float_inclusive_range(seed, -T::MAX_FINITE, T::MAX_FINITE)
}
#[inline]
pub fn random_positive_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
) -> RandomPrimitiveFloatInclusiveRange<T> {
random_primitive_float_inclusive_range(seed, T::MIN_POSITIVE_SUBNORMAL, T::POSITIVE_INFINITY)
}
#[inline]
pub fn random_negative_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
) -> RandomPrimitiveFloatInclusiveRange<T> {
random_primitive_float_inclusive_range(seed, T::NEGATIVE_INFINITY, -T::MIN_POSITIVE_SUBNORMAL)
}
#[inline]
pub fn random_nonzero_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
) -> NonzeroValues<RandomPrimitiveFloats<T>> {
nonzero_values(random_primitive_floats(seed))
}
#[derive(Clone, Debug)]
pub struct RandomPrimitiveFloats<T: PrimitiveFloat> {
phantom: PhantomData<*const T>,
pub(crate) xs: RandomUnsignedInclusiveRange<u64>,
nan: u64,
}
impl<T: PrimitiveFloat> Iterator for RandomPrimitiveFloats<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.xs.next().map(|x| {
if x == self.nan {
T::NAN
} else {
T::from_ordered_representation(x)
}
})
}
}
#[inline]
pub fn random_primitive_floats<T: PrimitiveFloat>(seed: Seed) -> RandomPrimitiveFloats<T> {
let nan = T::POSITIVE_INFINITY.to_ordered_representation() + 1;
RandomPrimitiveFloats {
phantom: PhantomData,
xs: random_unsigned_inclusive_range(seed, 0, nan),
nan,
}
}
#[derive(Clone, Debug)]
pub struct SpecialRandomPositiveFiniteFloats<T: PrimitiveFloat> {
seed: Seed,
sci_exponents: GeometricRandomSignedRange<i64>,
range_map: HashMap<i64, GeometricRandomNaturalValues<u64>>,
ranges: VariableRangeGenerator,
mean_precision_n: u64,
mean_precision_d: u64,
phantom: PhantomData<*const T>,
}
impl<T: PrimitiveFloat> Iterator for SpecialRandomPositiveFiniteFloats<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
let sci_exponent = self.sci_exponents.next().unwrap();
let mean_precision_n = self.mean_precision_n;
let mean_precision_d = self.mean_precision_d;
let seed = self.seed;
let precisions = self.range_map.entry(sci_exponent).or_insert_with(move || {
geometric_random_unsigned_inclusive_range(
seed.fork(&sci_exponent.to_string()),
1,
T::max_precision_for_sci_exponent(sci_exponent),
mean_precision_n,
mean_precision_d,
)
});
let precision = precisions.next().unwrap();
let mantissa = if precision == 1 {
1
} else {
let x = self.ranges.next_in_range(
u64::power_of_2(precision - 2),
u64::power_of_2(precision - 1),
);
(x << 1) | 1
};
T::from_integer_mantissa_and_exponent(
mantissa,
sci_exponent - i64::wrapping_from(precision) + 1,
)
}
}
pub fn special_random_positive_finite_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
) -> SpecialRandomPositiveFiniteFloats<T> {
assert_ne!(mean_precision_denominator, 0);
assert!(mean_precision_numerator > mean_precision_denominator);
SpecialRandomPositiveFiniteFloats {
seed: seed.fork("precisions"),
sci_exponents: geometric_random_signed_inclusive_range(
EXAMPLE_SEED.fork("exponents"),
T::MIN_EXPONENT,
T::MAX_EXPONENT,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
),
range_map: HashMap::new(),
ranges: variable_range_generator(seed.fork("ranges")),
mean_precision_n: mean_precision_numerator,
mean_precision_d: mean_precision_denominator,
phantom: PhantomData,
}
}
#[derive(Clone, Debug)]
pub struct SpecialRandomNegativeFiniteFloats<T: PrimitiveFloat>(
SpecialRandomPositiveFiniteFloats<T>,
);
impl<T: PrimitiveFloat> Iterator for SpecialRandomNegativeFiniteFloats<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
self.0.next().map(|f| -f)
}
}
#[inline]
pub fn special_random_negative_finite_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
) -> SpecialRandomNegativeFiniteFloats<T> {
SpecialRandomNegativeFiniteFloats(special_random_positive_finite_primitive_floats(
seed,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
))
}
#[derive(Clone, Debug)]
pub struct SpecialRandomNonzeroFiniteFloats<T: PrimitiveFloat> {
bs: RandomBools,
xs: SpecialRandomPositiveFiniteFloats<T>,
}
impl<T: PrimitiveFloat> Iterator for SpecialRandomNonzeroFiniteFloats<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
let x = self.xs.next().unwrap();
Some(if self.bs.next().unwrap() { x } else { -x })
}
}
#[inline]
pub fn special_random_nonzero_finite_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
) -> SpecialRandomNonzeroFiniteFloats<T> {
SpecialRandomNonzeroFiniteFloats {
bs: random_bools(seed.fork("bs")),
xs: special_random_positive_finite_primitive_floats(
seed.fork("xs"),
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
),
}
}
#[inline]
pub fn special_random_finite_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
mean_zero_p_numerator: u64,
mean_zero_p_denominator: u64,
) -> WithSpecialValues<SpecialRandomNonzeroFiniteFloats<T>> {
with_special_values(
seed,
vec![T::ZERO, T::NEGATIVE_ZERO],
mean_zero_p_numerator,
mean_zero_p_denominator,
&|seed_2| {
special_random_nonzero_finite_primitive_floats(
seed_2,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
)
},
)
}
#[inline]
pub fn special_random_positive_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
mean_special_p_numerator: u64,
mean_special_p_denominator: u64,
) -> WithSpecialValue<SpecialRandomPositiveFiniteFloats<T>> {
with_special_value(
seed,
T::POSITIVE_INFINITY,
mean_special_p_numerator,
mean_special_p_denominator,
&|seed_2| {
special_random_positive_finite_primitive_floats(
seed_2,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
)
},
)
}
#[inline]
pub fn special_random_negative_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
mean_special_p_numerator: u64,
mean_special_p_denominator: u64,
) -> WithSpecialValue<SpecialRandomNegativeFiniteFloats<T>> {
with_special_value(
seed,
T::NEGATIVE_INFINITY,
mean_special_p_numerator,
mean_special_p_denominator,
&|seed_2| {
special_random_negative_finite_primitive_floats(
seed_2,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
)
},
)
}
#[inline]
pub fn special_random_nonzero_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
mean_special_p_numerator: u64,
mean_special_p_denominator: u64,
) -> WithSpecialValues<SpecialRandomNonzeroFiniteFloats<T>> {
with_special_values(
seed,
vec![T::POSITIVE_INFINITY, T::NEGATIVE_INFINITY],
mean_special_p_numerator,
mean_special_p_denominator,
&|seed_2| {
special_random_nonzero_finite_primitive_floats(
seed_2,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
)
},
)
}
#[inline]
pub fn special_random_primitive_floats<T: PrimitiveFloat>(
seed: Seed,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
mean_special_p_numerator: u64,
mean_special_p_denominator: u64,
) -> WithSpecialValues<SpecialRandomNonzeroFiniteFloats<T>> {
with_special_values(
seed,
vec![T::ZERO, T::NEGATIVE_ZERO, T::POSITIVE_INFINITY, T::NEGATIVE_INFINITY, T::NAN],
mean_special_p_numerator,
mean_special_p_denominator,
&|seed_2| {
special_random_nonzero_finite_primitive_floats(
seed_2,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
)
},
)
}
fn mantissas_inclusive<T: PrimitiveFloat>(
mut sci_exponent: i64,
mut am: u64,
mut bm: u64,
precision: u64,
) -> Option<(i64, u64, u64)> {
assert_ne!(precision, 0);
let p: u64 = if sci_exponent < T::MIN_NORMAL_EXPONENT {
let ab = am.significant_bits();
let bb = bm.significant_bits();
assert_eq!(ab, bb);
ab - precision
} else {
am.set_bit(T::MANTISSA_WIDTH);
bm.set_bit(T::MANTISSA_WIDTH);
T::MANTISSA_WIDTH + 1 - precision
};
let mut lo = am.shr_round(p, RoundingMode::Up);
if lo.even() {
lo += 1;
}
let mut hi = bm.shr_round(p, RoundingMode::Down);
if hi == 0 {
return None;
} else if hi.even() {
hi -= 1;
}
if sci_exponent >= T::MIN_NORMAL_EXPONENT {
sci_exponent -= i64::wrapping_from(T::MANTISSA_WIDTH);
}
sci_exponent += i64::wrapping_from(p);
if lo > hi {
None
} else {
Some((sci_exponent, lo >> 1, hi >> 1))
}
}
#[doc(hidden)]
#[derive(Clone, Debug)]
pub struct SpecialRandomPositiveFiniteFloatInclusiveRange<T: PrimitiveFloat> {
phantom: PhantomData<*const T>,
am: u64, bm: u64,
ae: i64, be: i64,
sci_exponents: GeometricRandomSignedRange<i64>,
precision_range_map: HashMap<i64, Vec<(i64, u64, u64)>>,
precision_indices: GeometricRandomNaturalValues<usize>,
ranges: VariableRangeGenerator,
}
impl<T: PrimitiveFloat> Iterator for SpecialRandomPositiveFiniteFloatInclusiveRange<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
let sci_exponent = self.sci_exponents.next().unwrap();
let ae = self.ae;
let be = self.be;
let am = self.am;
let bm = self.bm;
let precision_ranges = self
.precision_range_map
.entry(sci_exponent)
.or_insert_with(|| {
let am = if sci_exponent == ae {
am
} else {
T::from_integer_mantissa_and_exponent(1, sci_exponent)
.unwrap()
.raw_mantissa()
};
let bm = if sci_exponent == be {
bm
} else {
T::from_integer_mantissa_and_exponent(1, sci_exponent + 1)
.unwrap()
.next_lower()
.raw_mantissa()
};
(1..=T::max_precision_for_sci_exponent(sci_exponent))
.filter_map(|p| mantissas_inclusive::<T>(sci_exponent, am, bm, p))
.collect_vec()
});
assert!(!precision_ranges.is_empty());
let i = self.precision_indices.next().unwrap() % precision_ranges.len();
let t = precision_ranges[i];
let mantissa = (self.ranges.next_in_inclusive_range(t.1, t.2) << 1) | 1;
Some(T::from_integer_mantissa_and_exponent(mantissa, t.0).unwrap())
}
}
fn special_random_positive_finite_float_inclusive_range<T: PrimitiveFloat>(
seed: Seed,
a: T,
b: T,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
) -> SpecialRandomPositiveFiniteFloatInclusiveRange<T> {
assert!(a.is_finite());
assert!(b.is_finite());
assert!(a > T::ZERO);
assert!(a <= b);
let (am, ae) = a.raw_mantissa_and_exponent();
let (bm, be) = b.raw_mantissa_and_exponent();
let ae = if ae == 0 {
i64::wrapping_from(am.significant_bits()) + T::MIN_EXPONENT - 1
} else {
i64::wrapping_from(ae) - T::MAX_EXPONENT
};
let be = if be == 0 {
i64::wrapping_from(bm.significant_bits()) + T::MIN_EXPONENT - 1
} else {
i64::wrapping_from(be) - T::MAX_EXPONENT
};
SpecialRandomPositiveFiniteFloatInclusiveRange {
phantom: PhantomData,
am,
bm,
ae,
be,
sci_exponents: geometric_random_signed_inclusive_range(
seed.fork("exponents"),
ae,
be,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
),
precision_range_map: HashMap::new(),
precision_indices: geometric_random_unsigneds(
seed.fork("precisions"),
mean_precision_numerator,
mean_precision_denominator,
),
ranges: variable_range_generator(seed.fork("ranges")),
}
}
#[allow(clippy::large_enum_variant)]
#[doc(hidden)]
#[derive(Clone, Debug)]
pub enum SpecialRandomFiniteFloatInclusiveRange<T: PrimitiveFloat> {
AllPositive(SpecialRandomPositiveFiniteFloatInclusiveRange<T>),
AllNegative(SpecialRandomPositiveFiniteFloatInclusiveRange<T>),
PositiveAndNegative(
RandomBools,
SpecialRandomPositiveFiniteFloatInclusiveRange<T>,
SpecialRandomPositiveFiniteFloatInclusiveRange<T>,
),
}
impl<T: PrimitiveFloat> Iterator for SpecialRandomFiniteFloatInclusiveRange<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
match self {
SpecialRandomFiniteFloatInclusiveRange::AllPositive(ref mut xs) => xs.next(),
SpecialRandomFiniteFloatInclusiveRange::AllNegative(ref mut xs) => {
xs.next().map(|x| -x)
}
SpecialRandomFiniteFloatInclusiveRange::PositiveAndNegative(
ref mut bs,
ref mut xs,
ref mut ys,
) => {
if bs.next().unwrap() {
xs.next()
} else {
ys.next().map(|x| -x)
}
}
}
}
}
fn special_random_finite_float_inclusive_range<T: PrimitiveFloat>(
seed: Seed,
a: T,
b: T,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
) -> SpecialRandomFiniteFloatInclusiveRange<T> {
assert!(a.is_finite());
assert!(b.is_finite());
assert_ne!(a, T::ZERO);
assert_ne!(b, T::ZERO);
assert!(a <= b);
if a > T::ZERO {
SpecialRandomFiniteFloatInclusiveRange::AllPositive(
special_random_positive_finite_float_inclusive_range(
seed,
a,
b,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
),
)
} else if b < T::ZERO {
SpecialRandomFiniteFloatInclusiveRange::AllNegative(
special_random_positive_finite_float_inclusive_range(
seed,
-b,
-a,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
),
)
} else {
SpecialRandomFiniteFloatInclusiveRange::PositiveAndNegative(
random_bools(seed.fork("bs")),
special_random_positive_finite_float_inclusive_range(
seed,
T::MIN_POSITIVE_SUBNORMAL,
b,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
),
special_random_positive_finite_float_inclusive_range(
seed,
T::MIN_POSITIVE_SUBNORMAL,
-a,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
),
)
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug)]
pub enum SpecialRandomFloatInclusiveRange<T: PrimitiveFloat> {
OnlySpecial(RandomValuesFromVec<T>),
NoSpecial(Box<SpecialRandomFiniteFloatInclusiveRange<T>>),
Special(Box<WithSpecialValues<SpecialRandomFiniteFloatInclusiveRange<T>>>),
}
impl<T: PrimitiveFloat> Iterator for SpecialRandomFloatInclusiveRange<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
match self {
SpecialRandomFloatInclusiveRange::OnlySpecial(ref mut xs) => xs.next(),
SpecialRandomFloatInclusiveRange::NoSpecial(ref mut xs) => xs.next(),
SpecialRandomFloatInclusiveRange::Special(ref mut xs) => xs.next(),
}
}
}
pub fn special_random_primitive_float_range<T: PrimitiveFloat>(
seed: Seed,
a: T,
b: T,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
mean_special_p_numerator: u64,
mean_special_p_denominator: u64,
) -> SpecialRandomFloatInclusiveRange<T> {
assert!(!a.is_nan());
assert!(!b.is_nan());
assert!(NiceFloat(a) < NiceFloat(b));
special_random_primitive_float_inclusive_range(
seed,
a,
b.next_lower(),
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
mean_special_p_numerator,
mean_special_p_denominator,
)
}
pub fn special_random_primitive_float_inclusive_range<T: PrimitiveFloat>(
seed: Seed,
mut a: T,
mut b: T,
mean_sci_exponent_numerator: u64,
mean_sci_exponent_denominator: u64,
mean_precision_numerator: u64,
mean_precision_denominator: u64,
mean_special_p_numerator: u64,
mean_special_p_denominator: u64,
) -> SpecialRandomFloatInclusiveRange<T> {
assert!(!a.is_nan());
assert!(!b.is_nan());
assert!(NiceFloat(a) <= NiceFloat(b));
assert_ne!(mean_special_p_denominator, 0);
assert!(mean_special_p_numerator <= mean_special_p_denominator);
assert_ne!(mean_precision_denominator, 0);
assert!(mean_precision_numerator > mean_precision_denominator);
let only_special =
a == T::POSITIVE_INFINITY || b == T::NEGATIVE_INFINITY || a == T::ZERO && b == T::ZERO;
let mut special_values = Vec::new();
if a == T::NEGATIVE_INFINITY {
special_values.push(a);
a = -T::MAX_FINITE;
}
if b == T::POSITIVE_INFINITY {
special_values.push(b);
b = T::MAX_FINITE;
}
if NiceFloat(a) <= NiceFloat(T::NEGATIVE_ZERO) && NiceFloat(b) >= NiceFloat(T::NEGATIVE_ZERO) {
special_values.push(T::NEGATIVE_ZERO);
}
if NiceFloat(a) <= NiceFloat(T::ZERO) && NiceFloat(b) >= NiceFloat(T::ZERO) {
special_values.push(T::ZERO);
}
if a == T::ZERO {
a = T::MIN_POSITIVE_SUBNORMAL;
}
if b == T::ZERO {
b = -T::MIN_POSITIVE_SUBNORMAL;
}
if only_special {
SpecialRandomFloatInclusiveRange::OnlySpecial(random_values_from_vec(seed, special_values))
} else if special_values.is_empty() {
SpecialRandomFloatInclusiveRange::NoSpecial(Box::new(
special_random_finite_float_inclusive_range(
seed,
a,
b,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
),
))
} else {
SpecialRandomFloatInclusiveRange::Special(Box::new(with_special_values(
seed,
special_values,
mean_special_p_numerator,
mean_special_p_denominator,
&|seed| {
special_random_finite_float_inclusive_range(
seed,
a,
b,
mean_sci_exponent_numerator,
mean_sci_exponent_denominator,
mean_precision_numerator,
mean_precision_denominator,
)
},
)))
}
}
#[derive(Clone, Debug)]
pub struct VariableRangeGenerator {
xs: RandomPrimitiveInts<u32>,
x: u32,
in_inner_loop: bool,
remaining_x_bits: u64,
}
impl VariableRangeGenerator {
pub fn next_bit_chunk<T: PrimitiveUnsigned>(&mut self, chunk_size: u64) -> T {
assert_ne!(chunk_size, 0);
assert!(chunk_size <= T::WIDTH);
let mut y = T::ZERO;
let mut remaining_y_bits = chunk_size;
loop {
if !self.in_inner_loop {
self.x = self.xs.next().unwrap();
self.remaining_x_bits = u32::WIDTH;
self.in_inner_loop = true;
}
while self.remaining_x_bits != 0 {
let y_index = chunk_size - remaining_y_bits;
if self.remaining_x_bits <= remaining_y_bits {
y |= T::wrapping_from(self.x) << y_index;
remaining_y_bits -= self.remaining_x_bits;
self.remaining_x_bits = 0;
} else {
y |= T::wrapping_from(self.x).mod_power_of_2(remaining_y_bits) << y_index;
self.x >>= remaining_y_bits;
self.remaining_x_bits -= remaining_y_bits;
remaining_y_bits = 0;
}
if remaining_y_bits == 0 {
return y;
}
}
self.in_inner_loop = false;
}
}
pub fn next_less_than<T: PrimitiveUnsigned>(&mut self, limit: T) -> T {
assert_ne!(limit, T::ZERO);
if limit == T::ONE {
T::ZERO
} else {
let chunk_size = limit.ceiling_log_base_2();
loop {
let x = self.next_bit_chunk(chunk_size);
if x < limit {
return x;
}
}
}
}
pub fn next_in_range<T: PrimitiveUnsigned>(&mut self, a: T, b: T) -> T {
self.next_less_than(b - a) + a
}
pub fn next_in_inclusive_range<T: PrimitiveUnsigned>(&mut self, a: T, b: T) -> T {
if a == T::ZERO && b == T::MAX {
self.next_bit_chunk(T::WIDTH)
} else {
self.next_less_than(b - a + T::ONE) + a
}
}
}
pub fn variable_range_generator(seed: Seed) -> VariableRangeGenerator {
VariableRangeGenerator {
xs: random_primitive_ints(seed),
x: 0,
in_inner_loop: false,
remaining_x_bits: 0,
}
}
pub mod geometric;
pub mod striped;