llm_tool/types/truncation/
ratio.rs1use alloc::format;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct HeadRatio {
8 numerator: u32,
9 denominator: u32,
10}
11
12impl HeadRatio {
13 pub const BALANCED: Self = Self {
15 numerator: 1,
16 denominator: 2,
17 };
18 pub const HEAD_ONLY: Self = Self {
20 numerator: 1,
21 denominator: 1,
22 };
23 pub const TAIL_ONLY: Self = Self {
25 numerator: 0,
26 denominator: 1,
27 };
28
29 #[must_use]
31 pub const fn new(numerator: u32, denominator: u32) -> Self {
32 if denominator == 0 {
33 Self::BALANCED
34 } else {
35 Self {
36 numerator: if numerator > denominator {
37 denominator
38 } else {
39 numerator
40 },
41 denominator,
42 }
43 }
44 }
45
46 #[must_use]
48 pub const fn from_percent(percent: u32) -> Self {
49 Self::new(percent, 100)
50 }
51
52 #[must_use]
54 pub const fn from_permille(permille: u32) -> Self {
55 Self::new(permille, 1000)
56 }
57
58 #[must_use]
60 pub fn from_f64(ratio: f64) -> Self {
61 if ratio.is_nan() || ratio <= 0.0 {
62 Self::TAIL_ONLY
63 } else if ratio >= 1.0 {
64 Self::HEAD_ONLY
65 } else {
66 let clamped = ratio.clamp(0.0, 1.0);
67 let s = format!("{clamped:.4}");
68 match s.strip_prefix("0.") {
69 Some(dec) => match dec.parse::<u32>() {
70 Ok(val) => Self::new(val, 10_000),
71 Err(e) => {
72 tracing::debug!(error = %e, "failed to parse head ratio digits");
73 Self::BALANCED
74 }
75 },
76 None => Self::BALANCED,
77 }
78 }
79 }
80
81 #[must_use]
83 pub fn compute_head_budget(&self, total_budget: usize) -> usize {
84 if self.denominator == 0 {
85 return total_budget / 2;
86 }
87 let total = u128::try_from(total_budget).unwrap_or(u128::MAX);
88 let num = u128::from(self.numerator);
89 let den = u128::from(self.denominator);
90 let head = (total.saturating_mul(num)) / den;
91 usize::try_from(head)
92 .unwrap_or(total_budget)
93 .min(total_budget)
94 }
95}
96
97impl Default for HeadRatio {
98 fn default() -> Self {
99 Self::BALANCED
100 }
101}
102
103impl From<f64> for HeadRatio {
104 fn from(r: f64) -> Self {
105 Self::from_f64(r)
106 }
107}