rust_fixed_point_decimal/binops/
cmp.rs1use std::cmp::Ordering;
11
12use rust_fixed_point_decimal_core::{checked_adjust_prec, checked_mul_pow_ten};
13
14use crate::{
15 prec_constraints::{PrecLimitCheck, True},
16 Decimal, MAX_PREC,
17};
18
19impl<const P: u8, const Q: u8> PartialEq<Decimal<Q>> for Decimal<P>
20where
21 PrecLimitCheck<{ P <= MAX_PREC }>: True,
22 PrecLimitCheck<{ Q <= MAX_PREC }>: True,
23{
24 fn eq(&self, other: &Decimal<Q>) -> bool {
25 match checked_adjust_prec(self.coeff, P, other.coeff, Q) {
26 (Some(a), Some(b)) => a == b,
27 _ => false,
28 }
29 }
30}
31
32impl<const P: u8, const Q: u8> PartialOrd<Decimal<Q>> for Decimal<P>
33where
34 PrecLimitCheck<{ P <= MAX_PREC }>: True,
35 PrecLimitCheck<{ Q <= MAX_PREC }>: True,
36{
37 fn partial_cmp(&self, other: &Decimal<Q>) -> Option<Ordering> {
38 match checked_adjust_prec(self.coeff, P, other.coeff, Q) {
39 (Some(a), Some(b)) => a.partial_cmp(&b),
40 (None, Some(_)) => {
41 if self.coeff > 0 {
42 Some(Ordering::Greater)
43 } else {
44 Some(Ordering::Less)
45 }
46 }
47 (Some(_), None) => {
48 if other.coeff < 0 {
49 Some(Ordering::Greater)
50 } else {
51 Some(Ordering::Less)
52 }
53 }
54 (None, None) => None,
56 }
57 }
58}
59
60impl<const P: u8> Decimal<P>
61where
62 PrecLimitCheck<{ P <= MAX_PREC }>: True,
63{
64 #[inline(always)]
66 pub fn eq_zero(&self) -> bool {
67 self.coeff == 0
68 }
69
70 #[inline(always)]
72 pub fn eq_one(&self) -> bool {
73 self.coeff == Self::ONE.coeff
74 }
75
76 #[inline(always)]
78 pub fn is_negative(&self) -> bool {
79 self.coeff < 0
80 }
81
82 #[inline(always)]
84 pub fn is_positive(&self) -> bool {
85 self.coeff > 0
86 }
87}
88
89#[cfg(test)]
90mod cmp_decimals_tests {
91 use std::cmp::{max, min, Ordering};
92
93 use crate::Decimal;
94
95 #[test]
96 fn test_eq_same_prec() {
97 let x = Decimal::<1>::new_raw(178);
98 assert!(x.eq(&x));
99 let y = x.clone();
100 assert!(x.eq(&y));
101 assert_eq!(x, y);
102 assert_eq!(y, x);
103 assert!(!(y.ne(&x)));
104 }
105
106 #[test]
107 fn test_eq_different_prec() {
108 let x = Decimal::<1>::new_raw(178);
109 let y = Decimal::<4>::new_raw(178000);
110 assert!(x.eq(&y));
111 assert_eq!(x, y);
112 assert_eq!(y, x);
113 assert!(!(y.ne(&x)));
114 }
115
116 #[test]
117 fn test_ne_same_prec() {
118 let x = Decimal::<7>::new_raw(-178000);
119 let y = Decimal::<7>::new_raw(178000);
120 assert_ne!(x, y);
121 assert_eq!(x.partial_cmp(&y), Some(Ordering::Less));
122 assert_eq!(x.cmp(&y), Ordering::Less);
123 assert!(x < y);
124 assert!(y > x);
125 }
126
127 #[test]
128 fn test_ne_different_prec() {
129 let x = Decimal::<7>::new_raw(178001);
130 let y = Decimal::<4>::new_raw(178);
131 assert_ne!(x, y);
132 assert_eq!(x.partial_cmp(&y), Some(Ordering::Greater));
133 assert!(x > y);
134 assert!(y < x);
135 }
136
137 #[test]
138 fn test_cmp_max() {
139 assert_eq!(Decimal::<5>::MAX, Decimal::<5>::MAX);
140 assert_ne!(Decimal::<2>::MAX, Decimal::<9>::MAX);
141 assert!(Decimal::<2>::MAX > Decimal::<3>::MAX);
142 assert!(Decimal::<6>::MAX < Decimal::<4>::MAX);
143 }
144
145 #[test]
146 fn test_cmp_min() {
147 assert_eq!(Decimal::<5>::MIN, Decimal::<5>::MIN);
148 assert_ne!(Decimal::<2>::MIN, Decimal::<9>::MIN);
149 assert!(Decimal::<2>::MIN < Decimal::<3>::MIN);
150 assert!(Decimal::<6>::MIN > Decimal::<4>::MIN);
151 }
152
153 #[test]
154 fn test_min_max() {
155 let x = Decimal::<2>::new_raw(12345);
156 let y = Decimal::<2>::new_raw(12344);
157 assert_eq!(min(x, y), y);
158 assert_eq!(min(x, x), x);
159 assert_eq!(max(x, y), x);
160 assert_eq!(max(x, x), x);
161 }
162
163 #[test]
164 fn test_eq_zero() {
165 assert!(Decimal::<0>::eq_zero(&Decimal::<0>::ZERO));
166 assert!(Decimal::<1>::eq_zero(&Decimal::<1>::ZERO));
167 assert!(Decimal::<2>::eq_zero(&Decimal::<2>::ZERO));
168 assert!(Decimal::<3>::eq_zero(&Decimal::<3>::ZERO));
169 assert!(Decimal::<4>::eq_zero(&Decimal::<4>::ZERO));
170 assert!(Decimal::<5>::eq_zero(&Decimal::<5>::ZERO));
171 assert!(Decimal::<6>::eq_zero(&Decimal::<6>::ZERO));
172 assert!(Decimal::<7>::eq_zero(&Decimal::<7>::ZERO));
173 assert!(Decimal::<8>::eq_zero(&Decimal::<8>::ZERO));
174 assert!(Decimal::<9>::eq_zero(&Decimal::<9>::ZERO));
175 assert!(!Decimal::<0>::eq_zero(&Decimal::<0>::ONE));
176 assert!(!Decimal::<1>::eq_zero(&Decimal::<1>::ONE));
177 assert!(!Decimal::<2>::eq_zero(&Decimal::<2>::ONE));
178 assert!(!Decimal::<3>::eq_zero(&Decimal::<3>::ONE));
179 assert!(!Decimal::<4>::eq_zero(&Decimal::<4>::ONE));
180 assert!(!Decimal::<5>::eq_zero(&Decimal::<5>::ONE));
181 assert!(!Decimal::<6>::eq_zero(&Decimal::<6>::ONE));
182 assert!(!Decimal::<7>::eq_zero(&Decimal::<7>::ONE));
183 assert!(!Decimal::<8>::eq_zero(&Decimal::<8>::ONE));
184 assert!(!Decimal::<9>::eq_zero(&Decimal::<9>::ONE));
185 }
186
187 #[test]
188 fn test_eq_one() {
189 assert!(Decimal::<0>::eq_one(&Decimal::<0>::ONE));
190 assert!(Decimal::<1>::eq_one(&Decimal::<1>::ONE));
191 assert!(Decimal::<2>::eq_one(&Decimal::<2>::ONE));
192 assert!(Decimal::<3>::eq_one(&Decimal::<3>::ONE));
193 assert!(Decimal::<4>::eq_one(&Decimal::<4>::ONE));
194 assert!(Decimal::<5>::eq_one(&Decimal::<5>::ONE));
195 assert!(Decimal::<6>::eq_one(&Decimal::<6>::ONE));
196 assert!(Decimal::<7>::eq_one(&Decimal::<7>::ONE));
197 assert!(Decimal::<8>::eq_one(&Decimal::<8>::ONE));
198 assert!(Decimal::<9>::eq_one(&Decimal::<9>::ONE));
199 assert!(!Decimal::<0>::eq_one(&Decimal::<0>::ZERO));
200 assert!(!Decimal::<1>::eq_one(&Decimal::<1>::ZERO));
201 assert!(!Decimal::<2>::eq_one(&Decimal::<2>::ZERO));
202 assert!(!Decimal::<3>::eq_one(&Decimal::<3>::ZERO));
203 assert!(!Decimal::<4>::eq_one(&Decimal::<4>::ZERO));
204 assert!(!Decimal::<5>::eq_one(&Decimal::<5>::ZERO));
205 assert!(!Decimal::<6>::eq_one(&Decimal::<6>::ZERO));
206 assert!(!Decimal::<7>::eq_one(&Decimal::<7>::ZERO));
207 assert!(!Decimal::<8>::eq_one(&Decimal::<8>::ZERO));
208 assert!(!Decimal::<9>::eq_one(&Decimal::<9>::ZERO));
209 }
210}
211
212macro_rules! impl_decimal_eq_uint {
220 () => {
221 impl_decimal_eq_uint!(u16, u32, u64);
222 };
223 ($($t:ty),*) => {
224 $(
225 impl<const P: u8> PartialEq<$t> for Decimal<P>
226 where
227 PrecLimitCheck<{ P <= MAX_PREC }>: True,
228 {
229 #[inline(always)]
230 fn eq(&self, other: &$t) -> bool {
231 if self.is_negative() {
232 return false;
233 }
234 match checked_mul_pow_ten((*other) as i128, P) {
235 Some(coeff) => self.coeff == coeff,
236 None => false,
237 }
238 }
239 }
240 )*
241 }
242}
243
244impl_decimal_eq_uint!();
245
246macro_rules! impl_decimal_eq_signed_int {
247 () => {
248 impl_decimal_eq_signed_int!(i8, i16, i32, i64, i128);
249 };
250 ($($t:ty),*) => {
251 $(
252 impl<const P: u8> PartialEq<$t> for Decimal<P>
253 where
254 PrecLimitCheck<{ P <= MAX_PREC }>: True,
255 {
256 #[inline(always)]
257 fn eq(&self, other: &$t) -> bool {
258 match checked_mul_pow_ten((*other) as i128, P) {
259 Some(coeff) => self.coeff == coeff,
260 None => false,
261 }
262 }
263 }
264 )*
265 }
266}
267
268impl_decimal_eq_signed_int!();
269
270macro_rules! impl_int_eq_decimal {
271 () => {
272 impl_int_eq_decimal!(i8, u16, i16, u32, i32, u64, i64, i128);
273 };
274 ($($t:ty),*) => {
275 $(
276 impl<const Q: u8> PartialEq<Decimal<Q>> for $t
277 where
278 PrecLimitCheck<{ Q <= MAX_PREC }>: True,
279 Decimal<Q>: PartialEq<$t>,
280 {
281 #[inline(always)]
282 fn eq(&self, other: &Decimal<Q>) -> bool {
283 PartialEq::eq(other, self)
284 }
285 }
286 )*
287 }
288}
289
290impl_int_eq_decimal!();
291
292macro_rules! impl_decimal_cmp_signed_int {
293 () => {
294 impl_decimal_cmp_signed_int!(i8, i16, i32, i64, i128);
295 };
296 ($($t:ty),*) => {
297 $(
298 impl<const P: u8> PartialOrd<$t> for Decimal<P>
299 where
300 PrecLimitCheck<{ P <= MAX_PREC }>: True,
301 {
302 #[inline(always)]
303 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
304 match checked_mul_pow_ten((*other) as i128, P) {
305 Some(coeff) => self.coeff.partial_cmp(&coeff),
306 None => {
307 if *other >= 0 {
308 Some(Ordering::Less)
309 } else {
310 Some(Ordering::Greater)
311 }
312 },
313 }
314 }
315 }
316 )*
317 }
318}
319
320impl_decimal_cmp_signed_int!();
321
322macro_rules! impl_signed_int_cmp_decimal {
323 () => {
324 impl_signed_int_cmp_decimal!(i8, i16, i32, i64, i128);
325 };
326 ($($t:ty),*) => {
327 $(
328 impl<const Q: u8> PartialOrd<Decimal<Q>> for $t
329 where
330 PrecLimitCheck<{ Q <= MAX_PREC }>: True,
331 {
332 #[inline(always)]
333 fn partial_cmp(&self, other: &Decimal<Q>) -> Option<Ordering> {
334 match checked_mul_pow_ten((*self) as i128, Q) {
335 Some(coeff) => coeff.partial_cmp(&other.coeff),
336 None => {
337 if *self < 0 {
338 Some(Ordering::Less)
339 } else {
340 Some(Ordering::Greater)
341 }
342 },
343 }
344 }
345 }
346 )*
347 }
348}
349
350impl_signed_int_cmp_decimal!();
351
352macro_rules! impl_decimal_cmp_uint {
353 () => {
354 impl_decimal_cmp_uint!(u16, u32, u64);
355 };
356 ($($t:ty),*) => {
357 $(
358 impl<const P: u8> PartialOrd<$t> for Decimal<P>
359 where
360 PrecLimitCheck<{ P <= MAX_PREC }>: True,
361 {
362 #[inline(always)]
363 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
364 if self.is_negative() {
365 return Some(Ordering::Less);
366 }
367 match checked_mul_pow_ten((*other) as i128, P) {
368 Some(coeff) => self.coeff.partial_cmp(&coeff),
369 None => Some(Ordering::Less),
370 }
371 }
372 }
373 )*
374 }
375}
376
377impl_decimal_cmp_uint!();
378
379macro_rules! impl_uint_cmp_decimal {
380 () => {
381 impl_uint_cmp_decimal!(u16, u32, u64);
382 };
383 ($($t:ty),*) => {
384 $(
385 impl<const Q: u8> PartialOrd<Decimal<Q>> for $t
386 where
387 PrecLimitCheck<{ Q <= MAX_PREC }>: True,
388 {
389 #[inline(always)]
390 fn partial_cmp(&self, other: &Decimal<Q>) -> Option<Ordering> {
391 if other.is_negative() {
392 return Some(Ordering::Greater);
393 }
394 match checked_mul_pow_ten((*self) as i128, Q) {
395 Some(coeff) => coeff.partial_cmp(&other.coeff),
396 None => Some(Ordering::Greater),
397 }
398 }
399 }
400 )*
401 }
402}
403
404impl_uint_cmp_decimal!();
405
406#[cfg(test)]
407mod cmp_decimals_and_ints_tests {
408 use std::cmp::Ordering;
409
410 use crate::Decimal;
411
412 #[test]
413 fn test_eq() {
414 let x = Decimal::<1>::new_raw(170);
415 assert!(x.eq(&x));
416 let y = 17_u32;
417 assert!(x.eq(&y));
418 assert!(y.eq(&x));
419 let y = 17_i128;
420 assert_eq!(x, y);
421 assert_eq!(y, x);
422 }
423
424 #[test]
425 fn test_ne() {
426 let x = Decimal::<7>::new_raw(-178000);
427 let y = 0_i8;
428 assert_ne!(x, y);
429 assert_eq!(x.partial_cmp(&y), Some(Ordering::Less));
430 assert!(x < y);
431 assert!(y > x);
432 let y = 1_u32;
433 assert_ne!(x, y);
434 assert_eq!(x.partial_cmp(&y), Some(Ordering::Less));
435 assert!(x < y);
436 assert!(y > x);
437 let x = Decimal::<1>::new_raw(178);
438 let y = 18_u64;
439 assert_ne!(x, y);
440 assert!(x <= y);
441 assert!(y >= x);
442 }
443}