From 42cd434ab9ba629d11213164aa99fde4dbcd2a0d Mon Sep 17 00:00:00 2001 From: Shane Carr Date: Mon, 21 Mar 2022 18:49:01 -0700 Subject: [PATCH 1/2] DoublePrecision::Floating + improve docs --- ffi/diplomat/src/fixed_decimal.rs | 2 +- utils/fixed_decimal/src/decimal.rs | 46 +++++++++++++++++++++--------- utils/fixed_decimal/src/lib.rs | 1 + 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/ffi/diplomat/src/fixed_decimal.rs b/ffi/diplomat/src/fixed_decimal.rs index 8697ccb7373..a3070bd6d18 100644 --- a/ffi/diplomat/src/fixed_decimal.rs +++ b/ffi/diplomat/src/fixed_decimal.rs @@ -44,7 +44,7 @@ pub mod ffi { /// See [the Rust docs](https://unicode-org.github.io/icu4x-docs/doc/fixed_decimal/decimal/struct.FixedDecimal.html#method.from_f64) for more information. pub fn create_from_f64_with_max_precision(f: f64) -> Option> { Some(Box::new(ICU4XFixedDecimal( - FixedDecimal::new_from_f64(f, DoublePrecision::Maximum).ok()?, + FixedDecimal::new_from_f64(f, DoublePrecision::Floating).ok()?, ))) } diff --git a/utils/fixed_decimal/src/decimal.rs b/utils/fixed_decimal/src/decimal.rs index 6718933ee1b..3007f20d5f7 100644 --- a/utils/fixed_decimal/src/decimal.rs +++ b/utils/fixed_decimal/src/decimal.rs @@ -882,7 +882,7 @@ pub enum DoublePrecision { /// /// This results in a FixedDecimal having enough digits to recover the original floating point /// value, with no trailing zeros. - Maximum, + Floating, } /// Specifies how numbers should be rounded @@ -901,24 +901,41 @@ pub enum RoundingMode { #[cfg(feature = "ryu")] impl FixedDecimal { - /// Construct a [`FixedDecimal`] from an f64. This uses `ryu` and - /// goes through an intermediate string representation, so is not - /// fully efficient. See [icu4x#166](https://github.com/unicode-org/icu4x/issues/166) for - /// more details. + /// Construct a [`FixedDecimal`] from an f64. + /// + /// Since f64 values do not carry a notion of their precision, the second argument to this + /// function specifies the type of precision associated with the f64. For more information, + /// see [`DoublePrecision`]. + /// + /// This function uses `ryu`, which is an efficient double-to-string algorithm, but other + /// implementations may yield higher performance; for more details, see + /// [icu4x#166](https://github.com/unicode-org/icu4x/issues/166). /// /// This function can be made available with the `"ryu"` feature. /// /// ```rust - /// use fixed_decimal::{DoublePrecision, FixedDecimal}; + /// use fixed_decimal::{DoublePrecision, FixedDecimal, RoundingMode}; /// use writeable::Writeable; /// - /// let decimal = FixedDecimal::new_from_f64(0.012345678, DoublePrecision::Maximum).unwrap(); + /// let decimal = FixedDecimal::new_from_f64( + /// -5.1, + /// DoublePrecision::Magnitude(-2, RoundingMode::Unnecessary) + /// ) + /// .expect("Finite quantity with limited precision"); + /// assert_eq!(decimal.write_to_string(), "-5.10"); + /// + /// let decimal = FixedDecimal::new_from_f64( + /// 0.012345678, + /// DoublePrecision::Floating + /// ) + /// .expect("Finite quantity"); /// assert_eq!(decimal.write_to_string(), "0.012345678"); /// - /// let decimal = FixedDecimal::new_from_f64(-123456.78, DoublePrecision::Maximum).unwrap(); - /// assert_eq!(decimal.write_to_string(), "-123456.78"); - /// - /// let decimal = FixedDecimal::new_from_f64(12345678000., DoublePrecision::Maximum).unwrap(); + /// let decimal = FixedDecimal::new_from_f64( + /// 12345678000., + /// DoublePrecision::Integer + /// ) + /// .expect("Finite, integer-valued quantity"); /// assert_eq!(decimal.write_to_string(), "12345678000"); /// ``` pub fn new_from_f64(float: f64, precision: DoublePrecision) -> Result { @@ -932,7 +949,7 @@ impl FixedDecimal { decimal.lower_magnitude = 0; } match precision { - DoublePrecision::Maximum => (), + DoublePrecision::Floating => (), DoublePrecision::Integer => { if lowest_magnitude < 0 { return Err(Error::Limit); @@ -989,6 +1006,7 @@ impl FixedDecimal { decimal.check_invariants(); Ok(decimal) } + /// Internal function for parsing directly from floats using ryƫ fn new_from_f64_raw(float: f64) -> Result { if !float.is_finite() { @@ -1165,12 +1183,12 @@ fn test_float() { let cases = [ TestCase { input: 1.234567, - precision: DoublePrecision::Maximum, + precision: DoublePrecision::Floating, expected: "1.234567", }, TestCase { input: 888999., - precision: DoublePrecision::Maximum, + precision: DoublePrecision::Floating, expected: "888999", }, // HalfExpand tests diff --git a/utils/fixed_decimal/src/lib.rs b/utils/fixed_decimal/src/lib.rs index fe8b5ec40d7..6782ce443c6 100644 --- a/utils/fixed_decimal/src/lib.rs +++ b/utils/fixed_decimal/src/lib.rs @@ -48,6 +48,7 @@ mod uint_iterator; pub use decimal::DoublePrecision; pub use decimal::FixedDecimal; +pub use decimal::RoundingMode; use displaydoc::Display; pub use signum::Signum; From 33d6849aa2d25754faa45db298554479563cbf6f Mon Sep 17 00:00:00 2001 From: Shane Carr Date: Mon, 21 Mar 2022 18:50:08 -0700 Subject: [PATCH 2/2] Rename function --- ffi/diplomat/src/fixed_decimal.rs | 6 +++--- utils/fixed_decimal/src/decimal.rs | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ffi/diplomat/src/fixed_decimal.rs b/ffi/diplomat/src/fixed_decimal.rs index a3070bd6d18..850f18fb03e 100644 --- a/ffi/diplomat/src/fixed_decimal.rs +++ b/ffi/diplomat/src/fixed_decimal.rs @@ -44,7 +44,7 @@ pub mod ffi { /// See [the Rust docs](https://unicode-org.github.io/icu4x-docs/doc/fixed_decimal/decimal/struct.FixedDecimal.html#method.from_f64) for more information. pub fn create_from_f64_with_max_precision(f: f64) -> Option> { Some(Box::new(ICU4XFixedDecimal( - FixedDecimal::new_from_f64(f, DoublePrecision::Floating).ok()?, + FixedDecimal::try_from_f64(f, DoublePrecision::Floating).ok()?, ))) } @@ -57,7 +57,7 @@ pub mod ffi { rounding_mode: ICU4XFixedDecimalRoundingMode, ) -> Option> { Some(Box::new(ICU4XFixedDecimal( - FixedDecimal::new_from_f64( + FixedDecimal::try_from_f64( f, DoublePrecision::Magnitude(precision, rounding_mode.into()), ) @@ -74,7 +74,7 @@ pub mod ffi { rounding_mode: ICU4XFixedDecimalRoundingMode, ) -> Option> { Some(Box::new(ICU4XFixedDecimal( - FixedDecimal::new_from_f64( + FixedDecimal::try_from_f64( f, DoublePrecision::SignificantDigits(digits, rounding_mode.into()), ) diff --git a/utils/fixed_decimal/src/decimal.rs b/utils/fixed_decimal/src/decimal.rs index 3007f20d5f7..2fc62b66cbf 100644 --- a/utils/fixed_decimal/src/decimal.rs +++ b/utils/fixed_decimal/src/decimal.rs @@ -917,28 +917,28 @@ impl FixedDecimal { /// use fixed_decimal::{DoublePrecision, FixedDecimal, RoundingMode}; /// use writeable::Writeable; /// - /// let decimal = FixedDecimal::new_from_f64( + /// let decimal = FixedDecimal::try_from_f64( /// -5.1, /// DoublePrecision::Magnitude(-2, RoundingMode::Unnecessary) /// ) /// .expect("Finite quantity with limited precision"); /// assert_eq!(decimal.write_to_string(), "-5.10"); /// - /// let decimal = FixedDecimal::new_from_f64( + /// let decimal = FixedDecimal::try_from_f64( /// 0.012345678, /// DoublePrecision::Floating /// ) /// .expect("Finite quantity"); /// assert_eq!(decimal.write_to_string(), "0.012345678"); /// - /// let decimal = FixedDecimal::new_from_f64( + /// let decimal = FixedDecimal::try_from_f64( /// 12345678000., /// DoublePrecision::Integer /// ) /// .expect("Finite, integer-valued quantity"); /// assert_eq!(decimal.write_to_string(), "12345678000"); /// ``` - pub fn new_from_f64(float: f64, precision: DoublePrecision) -> Result { + pub fn try_from_f64(float: f64, precision: DoublePrecision) -> Result { let mut decimal = Self::new_from_f64_raw(float)?; let n_digits = decimal.digits.len(); // magnitude of the lowest digit in self.digits @@ -1356,7 +1356,7 @@ fn test_float() { ]; for case in &cases { - let dec = FixedDecimal::new_from_f64(case.input, case.precision).unwrap(); + let dec = FixedDecimal::try_from_f64(case.input, case.precision).unwrap(); writeable::assert_writeable_eq!(dec, case.expected, "{:?}", case); } }