pub(crate) trait RatioInt: Copy + PartialOrd + Sized {
type Narrow: Copy;
type Float: Copy + Default + From<Self::Narrow>;
const ZERO: Self;
const ONE: Self;
const MAX: Self;
const NARROW_MAX: Self::Narrow;
const RANGE: Self;
#[must_use]
fn max(self, other: Self) -> Self;
fn checked_div(self, rhs: Self) -> Option<Self>;
#[must_use]
fn saturating_add(self, rhs: Self) -> Self;
fn try_into_narrow(self) -> Option<Self::Narrow>;
fn float_div(numerator: Self::Float, denominator: Self::Float) -> Self::Float;
}
impl RatioInt for u64 {
type Narrow = u32;
type Float = f64;
const ZERO: Self = 0;
const ONE: Self = 1;
const MAX: Self = u64::MAX;
const NARROW_MAX: Self::Narrow = u32::MAX;
const RANGE: Self = u32::MAX as u64 + 1;
fn max(self, other: Self) -> Self {
core::cmp::max(self, other)
}
fn checked_div(self, rhs: Self) -> Option<Self> {
u64::checked_div(self, rhs)
}
fn saturating_add(self, rhs: Self) -> Self {
u64::saturating_add(self, rhs)
}
fn try_into_narrow(self) -> Option<Self::Narrow> {
u32::try_from(self).ok()
}
fn float_div(numerator: Self::Float, denominator: Self::Float) -> Self::Float {
numerator / denominator
}
}
impl RatioInt for usize {
type Narrow = u16;
type Float = f32;
const ZERO: Self = 0;
const ONE: Self = 1;
const MAX: Self = usize::MAX;
const NARROW_MAX: Self::Narrow = u16::MAX;
const RANGE: Self = u16::MAX as usize + 1;
fn max(self, other: Self) -> Self {
core::cmp::max(self, other)
}
fn checked_div(self, rhs: Self) -> Option<Self> {
usize::checked_div(self, rhs)
}
fn saturating_add(self, rhs: Self) -> Self {
usize::saturating_add(self, rhs)
}
fn try_into_narrow(self) -> Option<Self::Narrow> {
u16::try_from(self).ok()
}
fn float_div(numerator: Self::Float, denominator: Self::Float) -> Self::Float {
numerator / denominator
}
}
fn scale_operand<T: RatioInt>(value: T, scale: T) -> T {
let scaled = T::checked_div(value, scale).unwrap_or(value);
if value > T::ZERO && scaled == T::ZERO {
T::ONE
} else {
scaled
}
}
#[must_use]
pub(crate) fn unit_ratio<T: RatioInt>(numerator: T, denominator: T) -> T::Float {
if denominator == T::ZERO {
return T::Float::default();
}
let scale = T::saturating_add(
T::checked_div(T::max(denominator, numerator), T::RANGE).unwrap_or(T::MAX),
T::ONE,
);
let numerator_scaled = scale_operand(numerator, scale);
let denominator_scaled = scale_operand(denominator, scale);
let numerator_narrow = numerator_scaled.try_into_narrow().unwrap_or(T::NARROW_MAX);
let denominator_narrow = denominator_scaled
.try_into_narrow()
.unwrap_or(T::NARROW_MAX);
T::float_div(
T::Float::from(numerator_narrow),
T::Float::from(denominator_narrow),
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unit_ratio_f64_normal_range() {
assert!((unit_ratio::<u64>(1, 4) - 0.25).abs() < 0.001);
assert!((unit_ratio::<u64>(3, 3) - 1.0).abs() < f64::EPSILON);
assert!(unit_ratio::<u64>(0, 3).abs() < f64::EPSILON);
}
#[test]
fn unit_ratio_f64_is_zero_for_zero_denominator() {
assert!(unit_ratio::<u64>(5, 0).abs() < f64::EPSILON);
}
#[test]
fn unit_ratio_f64_exceeds_one_for_overflow() {
let ratio = unit_ratio::<u64>(150, 100);
assert!(
(ratio - 1.5).abs() < 0.001,
"overflow must exceed 1.0, got {ratio}"
);
}
#[test]
fn unit_ratio_f64_large_partial_overlap_does_not_collapse_to_one() {
let over = u64::from(u32::MAX) + 1;
let ratio = unit_ratio::<u64>(over * 7 / 10, over);
assert!(
(ratio - 0.7).abs() < 0.01,
"partial overlap above u32::MAX must not collapse to 1.0, got {ratio}"
);
}
#[test]
fn unit_ratio_f64_small_positive_numerator_stays_positive_at_large_scale() {
let over = u64::from(u32::MAX) + 1;
let ratio = unit_ratio::<u64>(1, over);
assert!(
ratio > 0.0,
"positive numerator must yield positive ratio, got {ratio}"
);
}
#[test]
fn unit_ratio_f64_large_overflow_exceeds_one() {
let over = u64::from(u32::MAX) + 1;
let ratio = unit_ratio::<u64>(over + over / 2, over);
assert!(
ratio > 1.0,
"overflow above u32::MAX must stay above 1.0, got {ratio}"
);
}
#[test]
fn unit_ratio_f32_identity_and_disjoint_in_normal_range() {
assert!((unit_ratio::<usize>(3, 3) - 1.0).abs() < f32::EPSILON);
assert!(unit_ratio::<usize>(0, 3).abs() < f32::EPSILON);
}
#[test]
fn unit_ratio_f32_preserves_fraction_in_normal_range() {
assert!((unit_ratio::<usize>(1, 4) - 0.25).abs() < 0.01);
assert!((unit_ratio::<usize>(2, 3) - 0.66).abs() < 0.01);
}
#[test]
fn unit_ratio_f32_is_zero_for_zero_denominator() {
assert!(unit_ratio::<usize>(5, 0).abs() < f32::EPSILON);
}
#[test]
fn unit_ratio_f32_large_partial_overlap_does_not_collapse_to_one() {
let ratio = unit_ratio::<usize>(70_000, 100_000);
assert!((ratio - 0.7_f32).abs() < 0.01, "expected ~0.7, got {ratio}");
assert!(
(ratio - 1.0_f32).abs() > 0.01,
"partial overlap must not collapse to 1.0"
);
}
#[test]
fn unit_ratio_f32_small_positive_numerator_stays_positive_at_large_scale() {
let ratio = unit_ratio::<usize>(1, 70_000);
assert!(
ratio > 0.0,
"positive numerator must yield positive ratio, got {ratio}"
);
}
#[test]
fn unit_ratio_at_narrow_threshold_does_not_overscale() {
let near_max = u16::MAX as usize;
let ratio = unit_ratio::<usize>(near_max.saturating_sub(1), near_max);
assert!(
ratio < 1.0,
"near-identical counts must not collapse to 1.0 at the threshold, got {ratio}"
);
assert!(
(ratio - 0.999_97_f32).abs() < 0.001,
"expected ~0.99997, got {ratio}"
);
}
#[test]
fn unit_ratio_f32_small_positive_denominator_stays_finite_at_large_scale() {
let ratio = unit_ratio::<usize>(70_000, 1);
assert!(
ratio.is_finite(),
"positive denominator must yield a finite ratio, got {ratio}"
);
assert!(ratio > 1.0, "70_000/1 must exceed 1.0, got {ratio}");
}
#[test]
fn unit_ratio_f64_small_positive_denominator_stays_finite_at_large_scale() {
let over = u64::from(u32::MAX) + 1;
let ratio = unit_ratio::<u64>(over, 1);
assert!(
ratio.is_finite(),
"positive denominator must yield a finite ratio, got {ratio}"
);
assert!(ratio > 1.0, "over/1 must exceed 1.0, got {ratio}");
}
}