Skip to content

Commit

Permalink
Refactor module imports and add rounding module
Browse files Browse the repository at this point in the history
  • Loading branch information
younies committed Oct 17, 2024
1 parent b292bc7 commit 797a27e
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 135 deletions.
5 changes: 3 additions & 2 deletions utils/fixed_decimal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ mod compact;
mod decimal;
mod integer;
mod ops;
mod rounding;
mod scientific;
mod signed_decimal;
mod uint_iterator;
Expand All @@ -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;

Expand Down
138 changes: 138 additions & 0 deletions utils/fixed_decimal/src/rounding.rs
Original file line number Diff line number Diff line change
@@ -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<Self>;
const MULTIPLES_OF_2: Option<Self>;
const MULTIPLES_OF_5: Option<Self>;
const MULTIPLES_OF_25: Option<Self>;
}

impl IncrementLike for RoundingIncrement {
const MULTIPLES_OF_1: Option<Self> = Some(Self::MultiplesOf1);

const MULTIPLES_OF_2: Option<Self> = Some(Self::MultiplesOf2);

const MULTIPLES_OF_5: Option<Self> = Some(Self::MultiplesOf5);

const MULTIPLES_OF_25: Option<Self> = Some(Self::MultiplesOf25);
}

impl IncrementLike for NoIncrement {
const MULTIPLES_OF_1: Option<Self> = Some(Self);

const MULTIPLES_OF_2: Option<Self> = None;

const MULTIPLES_OF_5: Option<Self> = None;

const MULTIPLES_OF_25: Option<Self> = 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,
}
133 changes: 0 additions & 133 deletions utils/fixed_decimal/src/variations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self>;
const MULTIPLES_OF_2: Option<Self>;
const MULTIPLES_OF_5: Option<Self>;
const MULTIPLES_OF_25: Option<Self>;
}

impl IncrementLike for RoundingIncrement {
const MULTIPLES_OF_1: Option<Self> = Some(Self::MultiplesOf1);

const MULTIPLES_OF_2: Option<Self> = Some(Self::MultiplesOf2);

const MULTIPLES_OF_5: Option<Self> = Some(Self::MultiplesOf5);

const MULTIPLES_OF_25: Option<Self> = Some(Self::MultiplesOf25);
}

impl IncrementLike for NoIncrement {
const MULTIPLES_OF_1: Option<Self> = Some(Self);

const MULTIPLES_OF_2: Option<Self> = None;

const MULTIPLES_OF_5: Option<Self> = None;

const MULTIPLES_OF_25: Option<Self> = 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<T> {
Expand Down

0 comments on commit 797a27e

Please sign in to comment.