#![allow(dead_code)]
const MAX_DENOMINATOR: u32 = 1 << 16;
#[derive(Clone, Copy)]
pub(crate) struct Fraction {
pub numerator: u32,
pub denominator: u32,
}
#[derive(Clone, Copy)]
struct Candidate {
fraction: Fraction,
error: u32,
}
impl Candidate {
fn closer_of(self, other: Candidate) -> Candidate {
if self.error as u64 * other.fraction.denominator as u64
<= other.error as u64 * self.fraction.denominator as u64
{
self
} else {
other
}
}
}
fn candidates(target: Fraction, max_denominator: u32) -> impl Iterator<Item = Candidate> {
let Fraction {
numerator: n,
denominator: d,
} = target;
let complement = d - n;
let mut acc = 0_u32;
let mut whole = 0_u32;
let mut denominator = 0;
let mut exact = false;
core::iter::from_fn(move || {
if exact || denominator == max_denominator {
return None;
}
denominator += 1;
if acc >= complement {
acc -= complement;
whole += 1;
} else {
acc += n;
}
exact = acc == 0;
let below = d - acc;
let (numerator, error) = if acc <= below {
(whole, acc)
} else {
(whole + 1, below)
};
Some(Candidate {
fraction: Fraction {
numerator,
denominator,
},
error,
})
})
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct FractionalDivider {
pub integer: u32,
pub numerator: u32,
pub denominator: u32,
}
impl FractionalDivider {
pub(crate) fn new(source: u32, target: u32, max_denominator: u32) -> Self {
debug_assert!(target != 0);
debug_assert!((1..=MAX_DENOMINATOR).contains(&max_denominator));
let integer = source / target;
let remainder = Fraction {
numerator: source % target,
denominator: target,
};
if remainder.numerator == 0 {
return Self::integral(integer);
}
let dropped = Candidate {
fraction: Fraction {
numerator: 0,
denominator: 1,
},
error: remainder.numerator,
};
let closest = candidates(remainder, max_denominator)
.fold(dropped, Candidate::closer_of)
.fraction;
if closest.numerator == closest.denominator {
Self::integral(integer + 1)
} else if closest.numerator == 0 {
Self::integral(integer)
} else {
Self {
integer,
numerator: closest.numerator,
denominator: closest.denominator,
}
}
}
const fn integral(integer: u32) -> Self {
Self {
integer,
numerator: 0,
denominator: 0,
}
}
pub(crate) fn output_frequency(&self, source: u32) -> u32 {
if self.numerator == 0 || self.denominator == 0 {
return source / self.integer;
}
let source = source as u64;
let n = self.integer as u64;
let b = self.numerator as u64;
let a = self.denominator as u64;
((source * a) / (n * a + b)) as u32
}
}