Source code

Revision control

Copy as Markdown

Other Tools

use crate::constants::{MAX_I32_SCALE, POWERS_10, U32_MASK, U32_MAX};
use crate::decimal::Decimal;
use crate::ops::common::Dec64;
use core::cmp::Ordering;
pub(crate) fn cmp_impl(d1: &Decimal, d2: &Decimal) -> Ordering {
if d2.is_zero() {
return if d1.is_zero() {
return Ordering::Equal;
} else if d1.is_sign_negative() {
Ordering::Less
} else {
Ordering::Greater
};
}
if d1.is_zero() {
return if d2.is_sign_negative() {
Ordering::Greater
} else {
Ordering::Less
};
}
// If the sign is different, then it's an easy answer
if d1.is_sign_negative() != d2.is_sign_negative() {
return if d1.is_sign_negative() {
Ordering::Less
} else {
Ordering::Greater
};
}
// Otherwise, do a deep comparison
let d1 = Dec64::new(d1);
let d2 = Dec64::new(d2);
// We know both signs are the same here so flip it here.
// Negative is handled differently. i.e. 0.5 > 0.01 however -0.5 < -0.01
if d1.negative {
cmp_internal(&d2, &d1)
} else {
cmp_internal(&d1, &d2)
}
}
pub(in crate::ops) fn cmp_internal(d1: &Dec64, d2: &Dec64) -> Ordering {
// This function ignores sign
let mut d1_low = d1.low64;
let mut d1_high = d1.hi;
let mut d2_low = d2.low64;
let mut d2_high = d2.hi;
// If the scale factors aren't equal then
if d1.scale != d2.scale {
let mut diff = d2.scale as i32 - d1.scale as i32;
if diff < 0 {
diff = -diff;
if !rescale(&mut d2_low, &mut d2_high, diff as u32) {
return Ordering::Less;
}
} else if !rescale(&mut d1_low, &mut d1_high, diff as u32) {
return Ordering::Greater;
}
}
// They're the same scale, do a standard bitwise comparison
let hi_order = d1_high.cmp(&d2_high);
if hi_order != Ordering::Equal {
return hi_order;
}
d1_low.cmp(&d2_low)
}
fn rescale(low64: &mut u64, high: &mut u32, diff: u32) -> bool {
let mut diff = diff as i32;
// We need to modify d1 by 10^diff to get it to the same scale as d2
loop {
let power = if diff >= MAX_I32_SCALE {
POWERS_10[9]
} else {
POWERS_10[diff as usize]
} as u64;
let tmp_lo_32 = (*low64 & U32_MASK) * power;
let mut tmp = (*low64 >> 32) * power + (tmp_lo_32 >> 32);
*low64 = (tmp_lo_32 & U32_MASK) + (tmp << 32);
tmp >>= 32;
tmp = tmp.wrapping_add((*high as u64) * power);
// Indicates > 96 bits
if tmp > U32_MAX {
return false;
}
*high = tmp as u32;
// Keep scaling if there is more to go
diff -= MAX_I32_SCALE;
if diff <= 0 {
break;
}
}
true
}