1use crate::decimal::{DEFAULT_DIVISION_SCALE, Decimal, MAX_SUPPORTED_SCALE};
2use std::{
3 cmp::Ordering,
4 iter::{Product, Sum},
5 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
6};
7
8impl Decimal {
9 fn checked_add_impl(self, rhs: Self) -> Option<Self> {
10 let target_scale = self.scale.max(rhs.scale);
11 let lhs = Self::align_to_scale(self.mantissa, self.scale, target_scale)?;
12 let rhs = Self::align_to_scale(rhs.mantissa, rhs.scale, target_scale)?;
13
14 Some(Self {
15 mantissa: lhs.checked_add(rhs)?,
16 scale: target_scale,
17 })
18 }
19
20 #[must_use]
23 pub fn checked_add(self, rhs: Self) -> Option<Self> {
24 self.checked_add_impl(rhs)
25 }
26
27 #[must_use]
30 pub fn checked_sub(self, rhs: Self) -> Option<Self> {
31 self.checked_add_impl(Self {
32 mantissa: rhs.mantissa.checked_neg()?,
33 scale: rhs.scale,
34 })
35 }
36
37 #[must_use]
40 pub fn checked_mul(self, rhs: Self) -> Option<Self> {
41 self.checked_mul_impl(rhs)
42 }
43
44 #[must_use]
47 pub fn checked_div(self, rhs: Self) -> Option<Self> {
48 self.checked_div_impl(rhs)
49 }
50
51 fn checked_mul_impl(self, rhs: Self) -> Option<Self> {
52 let lhs = self.normalize();
55 let rhs = rhs.normalize();
56 let scale = lhs.scale.checked_add(rhs.scale)?;
57 let mantissa = lhs.mantissa.checked_mul(rhs.mantissa)?;
58 Self::checked_from_mantissa_scale(mantissa, scale)
59 }
60
61 fn checked_div_impl(self, rhs: Self) -> Option<Self> {
62 if rhs.is_zero() {
63 return None;
64 }
65
66 let lhs = self.normalize();
67 let rhs = rhs.normalize();
68 let mut target_scale = DEFAULT_DIVISION_SCALE;
69
70 loop {
72 if let Some((numerator, denominator)) = Self::division_operands(lhs, rhs, target_scale)
73 {
74 let mantissa = Self::div_round_half_away_from_zero(numerator, denominator)?;
75 if let Some(value) = Self::checked_from_mantissa_scale(mantissa, target_scale) {
76 return Some(value.normalize());
77 }
78 }
79
80 if target_scale == 0 {
81 return None;
82 }
83
84 target_scale = target_scale.saturating_sub(1);
85 }
86 }
87
88 fn checked_rem_impl(self, rhs: Self) -> Option<Self> {
89 if rhs.is_zero() {
90 return None;
91 }
92
93 let target_scale = self.scale.max(rhs.scale);
94 let lhs = Self::align_to_scale(self.mantissa, self.scale, target_scale)?;
95 let rhs = Self::align_to_scale(rhs.mantissa, rhs.scale, target_scale)?;
96
97 Some(Self {
98 mantissa: lhs.checked_rem(rhs)?,
99 scale: target_scale,
100 })
101 }
102
103 #[must_use]
105 pub const fn round_dp(&self, dp: u32) -> Self {
106 if self.scale <= dp {
107 return *self;
108 }
109
110 let diff = self.scale - dp;
111 let Some(divisor) = Self::checked_pow10(diff) else {
112 return *self;
113 };
114 let quotient = self.mantissa / divisor;
115 let remainder = self.mantissa % divisor;
116
117 let should_round = remainder.unsigned_abs() >= divisor.unsigned_abs() / 2;
119 let rounded = if should_round {
120 if self.mantissa.is_negative() {
121 quotient.saturating_sub(1)
122 } else {
123 quotient.saturating_add(1)
124 }
125 } else {
126 quotient
127 };
128
129 Self {
130 mantissa: rounded,
131 scale: dp,
132 }
133 }
134
135 #[must_use]
137 pub const fn trunc_dp(&self, dp: u32) -> Self {
138 if self.scale <= dp {
139 return *self;
140 }
141
142 let diff = self.scale - dp;
143 let Some(divisor) = Self::checked_pow10(diff) else {
144 return *self;
145 };
146
147 Self {
148 mantissa: self.mantissa / divisor,
149 scale: dp,
150 }
151 }
152
153 #[must_use]
155 pub const fn abs(&self) -> Self {
156 Self {
157 mantissa: self.mantissa.saturating_abs(),
158 scale: self.scale,
159 }
160 }
161
162 #[must_use]
164 pub const fn floor_dp0(&self) -> Self {
165 if self.scale == 0 {
166 return *self;
167 }
168
169 let Some(divisor) = Self::checked_pow10(self.scale) else {
170 return *self;
171 };
172 let quotient = self.mantissa / divisor;
173 let remainder = self.mantissa % divisor;
174 let integer = if self.mantissa.is_negative() && remainder != 0 {
175 quotient.saturating_sub(1)
176 } else {
177 quotient
178 };
179
180 Self {
181 mantissa: integer,
182 scale: 0,
183 }
184 }
185
186 #[must_use]
188 pub const fn ceil_dp0(&self) -> Self {
189 if self.scale == 0 {
190 return *self;
191 }
192
193 let Some(divisor) = Self::checked_pow10(self.scale) else {
194 return *self;
195 };
196 let quotient = self.mantissa / divisor;
197 let remainder = self.mantissa % divisor;
198 let integer = if self.mantissa.is_positive() && remainder != 0 {
199 quotient.saturating_add(1)
200 } else {
201 quotient
202 };
203
204 Self {
205 mantissa: integer,
206 scale: 0,
207 }
208 }
209
210 #[must_use]
212 pub fn saturating_add(self, rhs: Self) -> Self {
213 if let Some(sum) = self.checked_add_impl(rhs) {
214 return sum;
215 }
216
217 let target_scale = self.scale.max(rhs.scale);
218
219 if self.is_sign_negative() == rhs.is_sign_negative() {
220 return Self::saturating_extreme(target_scale, self.is_sign_negative());
221 }
222
223 match self.cmp_decimal(&rhs) {
224 Ordering::Equal => Self {
225 mantissa: 0,
226 scale: target_scale,
227 },
228 Ordering::Greater => Self::saturating_extreme(target_scale, self.is_sign_negative()),
229 Ordering::Less => Self::saturating_extreme(target_scale, rhs.is_sign_negative()),
230 }
231 }
232
233 #[must_use]
235 pub fn saturating_sub(self, rhs: Self) -> Self {
236 self.saturating_add(Self {
237 mantissa: rhs.mantissa.saturating_neg(),
238 scale: rhs.scale,
239 })
240 }
241
242 #[must_use]
244 pub fn checked_rem(self, rhs: Self) -> Option<Self> {
245 self.checked_rem_impl(rhs)
246 }
247
248 #[must_use]
251 pub const fn checked_abs(&self) -> Option<Self> {
252 let Some(mantissa) = self.mantissa.checked_abs() else {
253 return None;
254 };
255
256 Some(Self {
257 mantissa,
258 scale: self.scale,
259 })
260 }
261
262 #[must_use]
264 pub fn powu(&self, exp: u64) -> Self {
265 if exp == 0 {
266 return Self::new(1, 0);
267 }
268
269 let mut base = *self;
270 let mut power = exp;
271 let mut acc = Self::new(1, 0);
272
273 while power > 0 {
274 if power & 1 == 1 {
275 acc *= base;
276 }
277
278 power >>= 1;
279
280 if power > 0 {
281 base = base * base;
282 }
283 }
284
285 acc
286 }
287
288 #[must_use]
292 pub fn checked_powu(&self, exp: u64) -> Option<Self> {
293 if exp == 0 {
294 return Some(Self::new(1, 0));
295 }
296
297 let mut base = *self;
298 let mut power = exp;
299 let mut acc = Self::new(1, 0);
300
301 while power > 0 {
302 if power & 1 == 1 {
303 acc = acc.checked_mul(base)?;
304 }
305
306 power >>= 1;
307
308 if power > 0 {
309 base = base.checked_mul(base)?;
310 }
311 }
312
313 Some(acc)
314 }
315
316 fn saturating_mul(self, rhs: Self) -> Self {
317 if self.is_zero() || rhs.is_zero() {
318 return Self::ZERO;
319 }
320
321 let scale = self
322 .scale
323 .saturating_add(rhs.scale)
324 .min(MAX_SUPPORTED_SCALE);
325 let negative = self.is_sign_negative() != rhs.is_sign_negative();
326 Self::saturating_extreme(scale, negative)
327 }
328
329 fn align_to_scale(mantissa: i128, current_scale: u32, target_scale: u32) -> Option<i128> {
330 if current_scale == target_scale {
331 return Some(mantissa);
332 }
333
334 let factor = Self::checked_pow10(target_scale.checked_sub(current_scale)?)?;
335 mantissa.checked_mul(factor)
336 }
337
338 fn division_operands(lhs: Self, rhs: Self, target_scale: u32) -> Option<(i128, i128)> {
340 let exponent = i64::from(target_scale) + i64::from(rhs.scale) - i64::from(lhs.scale);
341
342 if exponent >= 0 {
343 let factor = Self::checked_pow10(u32::try_from(exponent).ok()?)?;
344 let numerator = lhs.mantissa.checked_mul(factor)?;
345 return Some((numerator, rhs.mantissa));
346 }
347
348 let factor = Self::checked_pow10(u32::try_from(exponent.unsigned_abs()).ok()?)?;
349 let denominator = rhs.mantissa.checked_mul(factor)?;
350 Some((lhs.mantissa, denominator))
351 }
352
353 fn div_round_half_away_from_zero(numerator: i128, denominator: i128) -> Option<i128> {
355 let quotient = numerator.checked_div(denominator)?;
358 let remainder = numerator.checked_rem(denominator)?;
359
360 if remainder == 0 {
361 return Some(quotient);
362 }
363
364 let twice_remainder = remainder.unsigned_abs().checked_mul(2)?;
365 if twice_remainder < denominator.unsigned_abs() {
366 return Some(quotient);
367 }
368
369 if (numerator < 0) == (denominator < 0) {
370 quotient.checked_add(1)
371 } else {
372 quotient.checked_sub(1)
373 }
374 }
375}
376
377impl Add for Decimal {
378 type Output = Self;
379
380 fn add(self, rhs: Self) -> Self::Output {
381 self.saturating_add(rhs)
382 }
383}
384
385impl AddAssign for Decimal {
386 fn add_assign(&mut self, rhs: Self) {
387 *self = *self + rhs;
388 }
389}
390
391impl Sub for Decimal {
392 type Output = Self;
393
394 fn sub(self, rhs: Self) -> Self::Output {
395 self.saturating_sub(rhs)
396 }
397}
398
399impl SubAssign for Decimal {
400 fn sub_assign(&mut self, rhs: Self) {
401 *self = *self - rhs;
402 }
403}
404
405impl Mul for Decimal {
406 type Output = Self;
407
408 fn mul(self, rhs: Self) -> Self::Output {
409 self.checked_mul_impl(rhs)
410 .unwrap_or_else(|| self.saturating_mul(rhs))
411 }
412}
413
414impl MulAssign for Decimal {
415 fn mul_assign(&mut self, rhs: Self) {
416 *self = *self * rhs;
417 }
418}
419
420impl Neg for Decimal {
421 type Output = Self;
422
423 fn neg(self) -> Self::Output {
424 Self {
425 mantissa: self.mantissa.saturating_neg(),
426 scale: self.scale,
427 }
428 }
429}
430
431impl Product for Decimal {
432 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
433 iter.fold(Self::new_unchecked(1, 0), |acc, value| acc * value)
434 }
435}
436
437impl Div for Decimal {
438 type Output = Self;
439
440 fn div(self, rhs: Self) -> Self::Output {
441 if rhs.is_zero() {
442 return Self::ZERO;
443 }
444
445 self.checked_div_impl(rhs).unwrap_or_else(|| {
446 let negative = self.is_sign_negative() != rhs.is_sign_negative();
447 Self::saturating_extreme(DEFAULT_DIVISION_SCALE, negative)
448 })
449 }
450}
451
452impl DivAssign for Decimal {
453 fn div_assign(&mut self, rhs: Self) {
454 *self = *self / rhs;
455 }
456}
457
458impl Rem for Decimal {
459 type Output = Self;
460
461 fn rem(self, rhs: Self) -> Self::Output {
462 self.checked_rem_impl(rhs).unwrap_or(Self::ZERO)
463 }
464}
465
466impl RemAssign for Decimal {
467 fn rem_assign(&mut self, rhs: Self) {
468 *self = *self % rhs;
469 }
470}
471
472impl Sum for Decimal {
473 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
474 iter.fold(Self::ZERO, |acc, value| acc + value)
475 }
476}