df_hyperliquid_core/utils/dec/
arith.rs1use crate::utils::dec::round::{Round, divide};
5use crate::utils::dec::{Dec, MAX_SCALE, ten};
6
7impl Dec {
8 #[must_use]
9 pub fn checked_add(self, other: Dec) -> Option<Dec> {
10 let (a, b, scale) = self.aligned(other)?;
11 Some(Dec { units: a.checked_add(b)?, scale }.normal())
12 }
13
14 #[must_use]
15 pub fn checked_sub(self, other: Dec) -> Option<Dec> {
16 self.checked_add(other.negate())
17 }
18
19 #[must_use]
22 pub fn checked_sum(figures: impl IntoIterator<Item = Dec>) -> Option<Dec> {
23 figures.into_iter().try_fold(Dec::ZERO, Dec::checked_add)
24 }
25
26 #[must_use]
28 pub fn checked_mul(self, other: Dec) -> Option<Dec> {
29 let (a, b) = (self.normal(), other.normal());
30 let units = a.units.checked_mul(b.units)?;
31 let scale = a.scale + b.scale;
32 if scale <= MAX_SCALE {
33 return Some(Dec { units, scale }.normal());
34 }
35 let units = divide(units, ten(scale - MAX_SCALE)?, Round::Nearest);
36 Some(Dec { units, scale: MAX_SCALE }.normal())
37 }
38
39 #[must_use]
41 pub fn checked_div(self, other: Dec, places: u32, round: Round) -> Option<Dec> {
42 if other.units == 0 || places > MAX_SCALE {
43 return None;
44 }
45 let (a, b) = (self.normal(), other.normal());
46 let scale = a.scale.max(b.scale);
52 let top = a.units.checked_mul(ten(scale - a.scale)?)?;
53 let bottom = b.units.checked_mul(ten(scale - b.scale)?)?;
54 let negative = (top < 0) != (bottom < 0);
55 let (top, bottom) = (top.unsigned_abs(), bottom.unsigned_abs());
56 let mut units = top / bottom;
57 let mut rest = top % bottom;
58 for _ in 0..places {
59 rest = rest.checked_mul(10)?;
60 units = units.checked_mul(10)?.checked_add(rest / bottom)?;
61 rest %= bottom;
62 }
63 let away = match round {
64 Round::Down => false,
65 Round::Up => rest != 0,
66 Round::Nearest => rest != 0 && rest >= bottom - rest,
67 };
68 let units = i128::try_from(units.checked_add(u128::from(away))?).ok()?;
69 let units = if negative { -units } else { units };
70 Some(Dec { units, scale: places }.normal())
71 }
72}
73
74#[cfg(test)]
75#[path = "tests/arith.rs"]
76mod tests;