ancdec/ancdec128/
rounding.rs1use super::AncDec128;
2use crate::util::pow10_128;
3use crate::wide::{divmod_u256, mul_wide};
4use crate::RoundMode;
5
6impl AncDec128 {
7 pub fn round(&self, decimal_places: u8, mode: RoundMode) -> Self {
9 if mode == RoundMode::Fract {
10 return Self {
11 int: 0,
12 frac: self.frac,
13 scale: self.scale,
14 neg: self.neg,
15 };
16 }
17 if self.scale <= decimal_places {
18 return *self;
19 }
20
21 let (hi, lo) = mul_wide(self.int, pow10_128(self.scale));
23 let (lo, carry) = lo.overflowing_add(self.frac);
24 let combined = (hi + carry as u128, lo);
25
26 let cut = self.scale - decimal_places;
27 let divisor = pow10_128(cut);
28
29 let (truncated_256, remainder) = divmod_u256(combined.0, combined.1, divisor);
31 let truncated = truncated_256.1;
33
34 if self.should_round_up(truncated, remainder, divisor, mode) {
35 let (lo, carry) = truncated.overflowing_add(1);
37 Self::from_combined((carry as u128, lo), decimal_places, self.neg)
38 } else {
39 Self::from_combined((0, truncated), decimal_places, self.neg)
40 }
41 }
42
43 fn should_round_up(
44 &self,
45 truncated: u128,
46 remainder: u128,
47 divisor: u128,
48 mode: RoundMode,
49 ) -> bool {
50 if remainder == 0 {
51 return false;
52 }
53 let half = divisor / 2;
54
55 match mode {
56 RoundMode::Floor => self.neg,
57 RoundMode::Ceil => !self.neg,
58 RoundMode::Truncate => false,
59 RoundMode::HalfUp => remainder >= half,
60 RoundMode::HalfDown => remainder > half,
61 RoundMode::HalfEven => remainder > half || (remainder == half && truncated % 2 == 1),
62 RoundMode::Fract => false,
63 }
64 }
65
66 #[inline(always)]
68 pub fn floor(&self) -> Self {
69 self.round(0, RoundMode::Floor)
70 }
71 #[inline(always)]
73 pub fn ceil(&self) -> Self {
74 self.round(0, RoundMode::Ceil)
75 }
76 #[inline(always)]
78 pub fn trunc(&self) -> Self {
79 self.round(0, RoundMode::Truncate)
80 }
81 #[inline(always)]
83 pub fn fract(&self) -> Self {
84 self.round(0, RoundMode::Fract)
85 }
86}