From 797a27efd79213ae6afd735fa55c45c66560aec0 Mon Sep 17 00:00:00 2001 From: Younies Mahmoud Date: Thu, 17 Oct 2024 15:51:52 +0200 Subject: [PATCH] Refactor module imports and add rounding module --- utils/fixed_decimal/src/lib.rs | 5 +- utils/fixed_decimal/src/rounding.rs | 138 ++++++++++++++++++++++++++ utils/fixed_decimal/src/variations.rs | 133 ------------------------- 3 files changed, 141 insertions(+), 135 deletions(-) create mode 100644 utils/fixed_decimal/src/rounding.rs diff --git a/utils/fixed_decimal/src/lib.rs b/utils/fixed_decimal/src/lib.rs index 7f01f8fb71..104fdb97dc 100644 --- a/utils/fixed_decimal/src/lib.rs +++ b/utils/fixed_decimal/src/lib.rs @@ -55,6 +55,7 @@ mod compact; mod decimal; mod integer; mod ops; +mod rounding; mod scientific; mod signed_decimal; mod uint_iterator; @@ -74,10 +75,10 @@ pub use compact::CompactDecimal; pub use decimal::UnsignedFixedDecimal; use displaydoc::Display; pub use integer::FixedInteger; +pub use rounding::RoundingIncrement; +pub use rounding::RoundingMode; pub use scientific::ScientificDecimal; pub use signed_decimal::SignedFixedDecimal; -pub use variations::RoundingIncrement; -pub use variations::RoundingMode; pub use variations::Sign; pub use variations::SignDisplay; diff --git a/utils/fixed_decimal/src/rounding.rs b/utils/fixed_decimal/src/rounding.rs new file mode 100644 index 0000000000..08da7cb83c --- /dev/null +++ b/utils/fixed_decimal/src/rounding.rs @@ -0,0 +1,138 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! This file contains the implementation of the rounding algorithm and the related functions & types. + +// Adapters to convert runtime dispatched calls into const-inlined methods. +// This allows reducing the codesize for the common case of no increment. + +#[derive(Copy, Clone, PartialEq)] +struct NoIncrement; + +trait IncrementLike: Copy + Sized + PartialEq { + const MULTIPLES_OF_1: Option; + const MULTIPLES_OF_2: Option; + const MULTIPLES_OF_5: Option; + const MULTIPLES_OF_25: Option; +} + +impl IncrementLike for RoundingIncrement { + const MULTIPLES_OF_1: Option = Some(Self::MultiplesOf1); + + const MULTIPLES_OF_2: Option = Some(Self::MultiplesOf2); + + const MULTIPLES_OF_5: Option = Some(Self::MultiplesOf5); + + const MULTIPLES_OF_25: Option = Some(Self::MultiplesOf25); +} + +impl IncrementLike for NoIncrement { + const MULTIPLES_OF_1: Option = Some(Self); + + const MULTIPLES_OF_2: Option = None; + + const MULTIPLES_OF_5: Option = None; + + const MULTIPLES_OF_25: Option = None; +} + +/// Mode used in a rounding operation. +/// +/// # Comparative table of rounding modes +/// +/// | Value | Ceil | Expand | Floor | Trunc | HalfCeil | HalfExpand | HalfFloor | HalfTrunc | HalfEven | +/// |:-----:|:----:|:------:|:-----:|:-----:|:--------:|:----------:|:---------:|:---------:|:--------:| +/// | +1.8 | +2 | +2 | +1 | +1 | +2 | +2 | +2 | +2 | +2 | +/// | +1.5 | " | " | " | " | " | " | +1 | +1 | " | +/// | +1.2 | " | " | " | " | +1 | +1 | " | " | +1 | +/// | +0.8 | +1 | +1 | 0 | 0 | " | " | " | " | " | +/// | +0.5 | " | " | " | " | " | " | 0 | 0 | 0 | +/// | +0.2 | " | " | " | " | 0 | 0 | " | " | " | +/// | -0.2 | 0 | -1 | -1 | " | " | " | " | " | " | +/// | -0.5 | " | " | " | " | " | -1 | -1 | " | " | +/// | -0.8 | " | " | " | " | -1 | " | " | -1 | -1 | +/// | -1.2 | -1 | -2 | -2 | -1 | " | " | " | " | " | +/// | -1.5 | " | " | " | " | " | -2 | -2 | " | -2 | +/// | -1.8 | " | " | " | " | -2 | " | " | -2 | " | +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[non_exhaustive] +pub enum RoundingMode { + /// Round up, or towards positive infinity. + Ceil, + /// Round away from zero, or towards infinity. + Expand, + /// Round down, or towards negative infinity. + Floor, + /// Round towards zero, or away from infinity. + Trunc, + /// Round to the nearest integer, resolving ties by rounding up. + HalfCeil, + /// Round to the nearest integer, resolving ties by rounding away from zero. + HalfExpand, + /// Round to the nearest integer, resolving ties by rounding down. + HalfFloor, + /// Round to the nearest integer, resolving ties by rounding towards zero. + HalfTrunc, + /// Round to the nearest integer, resolving ties by rounding towards the nearest even integer. + HalfEven, +} + +/// Increment used in a rounding operation. +/// +/// Forces a rounding operation to round to only multiples of the specified increment. +/// +/// # Example +/// +/// ``` +/// use fixed_decimal::{FixedDecimal, RoundingIncrement, RoundingMode}; +/// use writeable::assert_writeable_eq; +/// # use std::str::FromStr; +/// let dec = FixedDecimal::from_str("-7.266").unwrap(); +/// let mode = RoundingMode::Expand; +/// let increments = [ +/// // .266 normally expands to .27 when rounding on position -2... +/// (RoundingIncrement::MultiplesOf1, "-7.27"), +/// // ...however, when rounding to multiples of 2, .266 expands to .28, since the next multiple +/// // of 2 bigger than the least significant digit of the rounded value (7) is 8. +/// (RoundingIncrement::MultiplesOf2, "-7.28"), +/// // .266 expands to .30, since the next multiple of 5 bigger than 7 is 10. +/// (RoundingIncrement::MultiplesOf5, "-7.30"), +/// // .266 expands to .50, since the next multiple of 25 bigger than 27 is 50. +/// // Note how we compare against 27 instead of only 7, because the increment applies to +/// // the two least significant digits of the rounded value instead of only the least +/// // significant digit. +/// (RoundingIncrement::MultiplesOf25, "-7.50"), +/// ]; +/// +/// for (increment, expected) in increments { +/// assert_writeable_eq!( +/// dec.clone().rounded_with_mode_and_increment( +/// -2, +/// mode, +/// increment +/// ), +/// expected +/// ); +/// } +/// ``` +#[derive(Debug, Eq, PartialEq, Clone, Copy, Default)] +#[non_exhaustive] +pub enum RoundingIncrement { + /// Round the least significant digit to any digit (0-9). + /// + /// This is the default rounding increment for all the methods that don't take a + /// `RoundingIncrement` as an argument. + #[default] + MultiplesOf1, + /// Round the least significant digit to multiples of two (0, 2, 4, 6, 8). + MultiplesOf2, + /// Round the least significant digit to multiples of five (0, 5). + MultiplesOf5, + /// Round the two least significant digits to multiples of twenty-five (0, 25, 50, 75). + /// + /// With this increment, the rounding position index will match the least significant digit + /// of the multiple of 25; e.g. the number .264 expanded at position -2 using increments of 25 + /// will give .50 as a result, since the next multiple of 25 bigger than 26 is 50. + MultiplesOf25, +} diff --git a/utils/fixed_decimal/src/variations.rs b/utils/fixed_decimal/src/variations.rs index 696007dc0b..e2133732a0 100644 --- a/utils/fixed_decimal/src/variations.rs +++ b/utils/fixed_decimal/src/variations.rs @@ -76,139 +76,6 @@ pub enum SignDisplay { Negative, } -// Adapters to convert runtime dispatched calls into const-inlined methods. -// This allows reducing the codesize for the common case of no increment. - -#[derive(Copy, Clone, PartialEq)] -struct NoIncrement; - -trait IncrementLike: Copy + Sized + PartialEq { - const MULTIPLES_OF_1: Option; - const MULTIPLES_OF_2: Option; - const MULTIPLES_OF_5: Option; - const MULTIPLES_OF_25: Option; -} - -impl IncrementLike for RoundingIncrement { - const MULTIPLES_OF_1: Option = Some(Self::MultiplesOf1); - - const MULTIPLES_OF_2: Option = Some(Self::MultiplesOf2); - - const MULTIPLES_OF_5: Option = Some(Self::MultiplesOf5); - - const MULTIPLES_OF_25: Option = Some(Self::MultiplesOf25); -} - -impl IncrementLike for NoIncrement { - const MULTIPLES_OF_1: Option = Some(Self); - - const MULTIPLES_OF_2: Option = None; - - const MULTIPLES_OF_5: Option = None; - - const MULTIPLES_OF_25: Option = None; -} - -/// Mode used in a rounding operation. -/// -/// # Comparative table of rounding modes -/// -/// | Value | Ceil | Expand | Floor | Trunc | HalfCeil | HalfExpand | HalfFloor | HalfTrunc | HalfEven | -/// |:-----:|:----:|:------:|:-----:|:-----:|:--------:|:----------:|:---------:|:---------:|:--------:| -/// | +1.8 | +2 | +2 | +1 | +1 | +2 | +2 | +2 | +2 | +2 | -/// | +1.5 | " | " | " | " | " | " | +1 | +1 | " | -/// | +1.2 | " | " | " | " | +1 | +1 | " | " | +1 | -/// | +0.8 | +1 | +1 | 0 | 0 | " | " | " | " | " | -/// | +0.5 | " | " | " | " | " | " | 0 | 0 | 0 | -/// | +0.2 | " | " | " | " | 0 | 0 | " | " | " | -/// | -0.2 | 0 | -1 | -1 | " | " | " | " | " | " | -/// | -0.5 | " | " | " | " | " | -1 | -1 | " | " | -/// | -0.8 | " | " | " | " | -1 | " | " | -1 | -1 | -/// | -1.2 | -1 | -2 | -2 | -1 | " | " | " | " | " | -/// | -1.5 | " | " | " | " | " | -2 | -2 | " | -2 | -/// | -1.8 | " | " | " | " | -2 | " | " | -2 | " | -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[non_exhaustive] -pub enum RoundingMode { - /// Round up, or towards positive infinity. - Ceil, - /// Round away from zero, or towards infinity. - Expand, - /// Round down, or towards negative infinity. - Floor, - /// Round towards zero, or away from infinity. - Trunc, - /// Round to the nearest integer, resolving ties by rounding up. - HalfCeil, - /// Round to the nearest integer, resolving ties by rounding away from zero. - HalfExpand, - /// Round to the nearest integer, resolving ties by rounding down. - HalfFloor, - /// Round to the nearest integer, resolving ties by rounding towards zero. - HalfTrunc, - /// Round to the nearest integer, resolving ties by rounding towards the nearest even integer. - HalfEven, -} - -/// Increment used in a rounding operation. -/// -/// Forces a rounding operation to round to only multiples of the specified increment. -/// -/// # Example -/// -/// ``` -/// use fixed_decimal::{FixedDecimal, RoundingIncrement, RoundingMode}; -/// use writeable::assert_writeable_eq; -/// # use std::str::FromStr; -/// let dec = FixedDecimal::from_str("-7.266").unwrap(); -/// let mode = RoundingMode::Expand; -/// let increments = [ -/// // .266 normally expands to .27 when rounding on position -2... -/// (RoundingIncrement::MultiplesOf1, "-7.27"), -/// // ...however, when rounding to multiples of 2, .266 expands to .28, since the next multiple -/// // of 2 bigger than the least significant digit of the rounded value (7) is 8. -/// (RoundingIncrement::MultiplesOf2, "-7.28"), -/// // .266 expands to .30, since the next multiple of 5 bigger than 7 is 10. -/// (RoundingIncrement::MultiplesOf5, "-7.30"), -/// // .266 expands to .50, since the next multiple of 25 bigger than 27 is 50. -/// // Note how we compare against 27 instead of only 7, because the increment applies to -/// // the two least significant digits of the rounded value instead of only the least -/// // significant digit. -/// (RoundingIncrement::MultiplesOf25, "-7.50"), -/// ]; -/// -/// for (increment, expected) in increments { -/// assert_writeable_eq!( -/// dec.clone().rounded_with_mode_and_increment( -/// -2, -/// mode, -/// increment -/// ), -/// expected -/// ); -/// } -/// ``` -#[derive(Debug, Eq, PartialEq, Clone, Copy, Default)] -#[non_exhaustive] -pub enum RoundingIncrement { - /// Round the least significant digit to any digit (0-9). - /// - /// This is the default rounding increment for all the methods that don't take a - /// `RoundingIncrement` as an argument. - #[default] - MultiplesOf1, - /// Round the least significant digit to multiples of two (0, 2, 4, 6, 8). - MultiplesOf2, - /// Round the least significant digit to multiples of five (0, 5). - MultiplesOf5, - /// Round the two least significant digits to multiples of twenty-five (0, 25, 50, 75). - /// - /// With this increment, the rounding position index will match the least significant digit - /// of the multiple of 25; e.g. the number .264 expanded at position -2 using increments of 25 - /// will give .50 as a result, since the next multiple of 25 bigger than 26 is 50. - MultiplesOf25, -} - /// The `Signed` struct represents a numeric value with an associated sign. #[derive(Debug, Clone, PartialEq)] pub struct Signed {