Skip to content

Commit

Permalink
feat: add quantize_toward_zero method to Decimal (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
MathisWellmann authored Oct 24, 2024
1 parent 47fe246 commit f36b7ae
Showing 1 changed file with 48 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,31 @@ where
pub fn is_zero(&self) -> bool {
self.0 == I::ZERO
}

/// Round a number to a multiple of a given `quantum` toward zero.
/// general ref: <https://en.wikipedia.org/wiki/Quantization_(signal_processing)>
///
/// By default, rust is rounding towards zero and so does this method.
///
/// # Example:
/// ```rust
/// use const_decimal::Decimal;
/// // 11.65
/// let d = Decimal::<i64, 5>::try_from_scaled(1165, 2).unwrap();
/// // Allow only increments of 0.5
/// let quantum = Decimal::<i64, 5>::try_from_scaled(5, 1).unwrap();
/// let q = d.quantize_round_to_zero(quantum);
/// // 11.5 rounded down to the nearest `quantum`.
/// assert_eq!(q, Decimal::try_from_scaled(115, 1).unwrap());
/// ```
#[inline]
#[must_use]
pub fn quantize_round_to_zero(&self, quantum: Self) -> Self {
// SAFETY: We know the multiplication cannot overflow as we previously divided
// by the same number (and rust is rounding towards zero by default).
#[allow(clippy::arithmetic_side_effects)]
Self((self.0 / quantum.0) * quantum.0)
}
}

impl<I, const D: u8> num_traits::Zero for Decimal<I, D>
Expand Down Expand Up @@ -382,6 +407,29 @@ mod tests {

assert_eq!(out, Decimal::ONE / Decimal::TWO);
}

#[test]
fn [<$underlying _ $decimals _quantize_toward_zero_0>]() {
let quantum = Decimal::<$underlying, $decimals>::try_from_scaled(5, 1).unwrap();
let original = Decimal::<$underlying, $decimals>::try_from_scaled(61, 1).unwrap();
assert_eq!(original.quantize_round_to_zero(quantum), Decimal::try_from_scaled(60, 1).unwrap());
let original = Decimal::<$underlying, $decimals>::try_from_scaled(49, 1).unwrap();
assert_eq!(original.quantize_round_to_zero(quantum), Decimal::try_from_scaled(45, 1).unwrap());
let original = Decimal::<$underlying, $decimals>::try_from_scaled(44, 1).unwrap();
assert_eq!(original.quantize_round_to_zero(quantum), Decimal::try_from_scaled(40, 1).unwrap());

let quantum = Decimal::<$underlying, $decimals>::try_from_scaled(2, 1).unwrap();
let original = Decimal::<$underlying, $decimals>::try_from_scaled(61, 1).unwrap();
assert_eq!(original.quantize_round_to_zero(quantum), Decimal::try_from_scaled(60, 1).unwrap());
let original = Decimal::<$underlying, $decimals>::try_from_scaled(49, 1).unwrap();
assert_eq!(original.quantize_round_to_zero(quantum), Decimal::try_from_scaled(48, 1).unwrap());
let original = Decimal::<$underlying, $decimals>::try_from_scaled(44, 1).unwrap();
assert_eq!(original.quantize_round_to_zero(quantum), Decimal::try_from_scaled(44, 1).unwrap());

let quantum = Decimal::<$underlying, $decimals>::try_from_scaled(4, 1).unwrap();
let original = Decimal::<$underlying, $decimals>::try_from_scaled(123, 1).unwrap();
assert_eq!(original.quantize_round_to_zero(quantum), Decimal::try_from_scaled(120, 1).unwrap());
}
}
};
}
Expand Down

0 comments on commit f36b7ae

Please sign in to comment.