1use core::ops::Neg;
11
12use fpdec_core::ten_pow;
13
14use crate::Decimal;
15
16trait DivModInt: Sized {
18 fn divmod(self, rhs: Self) -> (Self, Self);
19 fn div_floor(self, rhs: Self) -> Self;
20 fn div_ceil(self, rhs: Self) -> Self;
21}
22
23impl DivModInt for i128 {
24 #[allow(clippy::integer_division)]
25 #[inline(always)]
26 fn divmod(self, rhs: Self) -> (Self, Self) {
27 (self / rhs, self % rhs)
28 }
29 #[inline]
30 fn div_floor(self, rhs: Self) -> Self {
31 let (q, r) = self.divmod(rhs);
32 if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
33 q - 1
34 } else {
35 q
36 }
37 }
38 #[inline]
39 fn div_ceil(self, rhs: Self) -> Self {
40 let (q, r) = self.divmod(rhs);
41 if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) {
42 q + 1
43 } else {
44 q
45 }
46 }
47}
48
49impl Neg for Decimal {
50 type Output = Self;
51
52 #[inline(always)]
59 fn neg(self) -> Self::Output {
60 Self::Output {
61 coeff: -self.coeff,
62 n_frac_digits: self.n_frac_digits,
63 }
64 }
65}
66
67impl Neg for &Decimal {
68 type Output = <Decimal as Neg>::Output;
69
70 #[inline(always)]
77 fn neg(self) -> Self::Output {
78 Self::Output {
79 coeff: -self.coeff,
80 n_frac_digits: self.n_frac_digits,
81 }
82 }
83}
84
85impl Decimal {
86 #[inline(always)]
88 pub const fn abs(&self) -> Self {
89 Self {
90 coeff: self.coefficient().abs(),
91 n_frac_digits: self.n_frac_digits,
92 }
93 }
94
95 #[inline(always)]
101 pub fn signum(&self) -> Self {
102 Self::from(self.coefficient().signum())
103 }
104
105 #[inline]
117 pub fn floor(&self) -> Self {
118 match self.n_frac_digits {
119 0 => *self,
120 n => Self {
121 coeff: DivModInt::div_floor(self.coeff, ten_pow(n)),
123 n_frac_digits: 0,
124 },
125 }
126 }
127
128 #[inline]
140 pub fn ceil(&self) -> Self {
141 match self.n_frac_digits {
142 0 => *self,
143 n => Self {
144 coeff: DivModInt::div_ceil(self.coeff, ten_pow(n)),
146 n_frac_digits: 0,
147 },
148 }
149 }
150
151 #[allow(clippy::integer_division)]
163 #[inline]
164 pub const fn trunc(&self) -> Self {
165 match self.n_frac_digits {
166 0 => *self,
167 n => Self {
168 coeff: self.coeff / ten_pow(n),
169 n_frac_digits: 0,
170 },
171 }
172 }
173
174 #[inline]
186 pub const fn fract(&self) -> Self {
187 match self.n_frac_digits {
188 0 => Self::ZERO,
189 n => Self {
190 coeff: self.coeff % ten_pow(n),
191 n_frac_digits: n,
192 },
193 }
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200
201 #[test]
202 fn test_neg() {
203 let val = 1234567890_i128;
204 let x: Decimal = Decimal::new_raw(val, 2);
205 let y = -x;
206 assert_eq!(x.coefficient(), -y.coefficient());
207 let z = -y;
208 assert_eq!(x.coefficient(), z.coefficient());
209 let a = &x;
210 let b = -a;
211 assert_eq!(a.coefficient(), -b.coefficient());
212 }
213
214 #[test]
215 fn test_neg_corner_cases() {
216 let x = Decimal::MAX;
217 let y = Decimal::MIN;
218 assert_eq!(x, -y);
219 assert_eq!(-x, y);
220 }
221
222 #[test]
223 fn test_abs() {
224 let x = Decimal::new_raw(-123456789, 4);
225 let y = x.abs();
226 assert_eq!(-x.coefficient(), y.coefficient());
227 let z = y.abs();
228 assert_eq!(y.coefficient(), z.coefficient());
229 let a = &x;
230 let b = a.abs();
231 assert_eq!(-a.coefficient(), b.coefficient());
232 }
233
234 #[test]
235 fn test_signum() {
236 assert_eq!(Decimal::new_raw(123, 0).signum(), Decimal::ONE);
237 assert_eq!(Decimal::new_raw(0, 0).signum(), Decimal::ZERO);
238 assert_eq!(Decimal::new_raw(-123, 0).signum(), Decimal::NEG_ONE);
239 }
240
241 #[test]
242 fn test_floor() {
243 let x = Decimal::new_raw(123, 0);
244 let y = x.floor();
245 assert_eq!(y.n_frac_digits(), 0);
246 assert_eq!(y.coefficient(), x.coefficient());
247 let x = Decimal::new_raw(123456789, 5);
248 let y = x.floor();
249 assert_eq!(y.coefficient(), 1234);
250 assert_eq!(y.n_frac_digits(), 0);
251 let z = y.floor();
252 assert_eq!(y.coefficient(), z.coefficient());
253 let x = Decimal::new_raw(-987, 9);
254 let y = x.floor();
255 assert_eq!(y.coefficient(), -1);
256 assert_eq!(y.n_frac_digits(), 0);
257 let z = y.floor();
258 assert_eq!(y.coefficient(), z.coefficient());
259 let a = &x;
260 let b = a.floor();
261 assert_eq!(b.coefficient(), y.coefficient());
262 }
263
264 #[test]
265 fn test_ceil() {
266 let x = Decimal::new_raw(123, 0);
267 let y = x.ceil();
268 assert_eq!(y.coefficient(), x.coefficient());
269 assert_eq!(y.n_frac_digits(), 0);
270 let x = Decimal::new_raw(123400001, 5);
271 let y = x.ceil();
272 assert_eq!(y.coefficient(), 1235);
273 assert_eq!(y.n_frac_digits(), 0);
274 let z = y.ceil();
275 assert_eq!(y.coefficient(), z.coefficient());
276 let x = Decimal::new_raw(-987, 6);
277 let y = x.ceil();
278 assert_eq!(y.coefficient(), 0);
279 assert_eq!(y.n_frac_digits(), 0);
280 let z = y.ceil();
281 assert_eq!(y.coefficient(), z.coefficient());
282 let a = &x;
283 let b = a.ceil();
284 assert_eq!(b.coefficient(), y.coefficient());
285 }
286
287 #[test]
288 fn test_trunc() {
289 let x = Decimal::new_raw(12345, 0);
290 let y = x.trunc();
291 assert_eq!(x.coefficient(), y.coefficient());
292 assert_eq!(y.n_frac_digits(), 0);
293 let x = Decimal::new_raw(98765, 3);
294 let y = x.trunc();
295 assert_eq!(y.coefficient(), 98);
296 assert_eq!(y.n_frac_digits(), 0);
297 let x = Decimal::new_raw(999999, 7);
298 let y = x.trunc();
299 assert_eq!(y.coefficient(), 0);
300 assert_eq!(y.n_frac_digits(), 0);
301 let a = &x;
302 let b = a.trunc();
303 assert_eq!(b.coefficient(), y.coefficient());
304 }
305
306 #[test]
307 fn test_fract() {
308 let x = Decimal::new_raw(12345, 0);
309 let y = x.fract();
310 assert_eq!(y.coefficient(), 0);
311 assert_eq!(y.n_frac_digits(), 0);
312 let x = Decimal::new_raw(987654, 3);
313 let y = x.fract();
314 assert_eq!(y.coefficient(), 654);
315 assert_eq!(y.n_frac_digits(), 3);
316 let x = Decimal::new_raw(9999, 5);
317 let y = x.fract();
318 assert_eq!(y.coefficient(), 9999);
319 assert_eq!(y.n_frac_digits(), 5);
320 let a = &x;
321 let b = a.fract();
322 assert_eq!(b.coefficient(), y.coefficient());
323 }
324}