From 2ba0b65c27724b99f2624c4245698e8ef36a2cf2 Mon Sep 17 00:00:00 2001 From: Son Date: Tue, 7 Feb 2017 20:58:34 +1100 Subject: [PATCH] Improve fmt float * Move to a separate float mod * Add more tests for f64 f32 lower exp upper exp * Use assert_eq for a clearer error message --- src/libcore/fmt/float.rs | 94 ++++++++++++++++++++++++++++++++++++ src/libcore/fmt/mod.rs | 87 ++------------------------------- src/libcoretest/fmt/float.rs | 32 +++++++++--- 3 files changed, 123 insertions(+), 90 deletions(-) create mode 100644 src/libcore/fmt/float.rs diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs new file mode 100644 index 0000000000000..50248fabfcd45 --- /dev/null +++ b/src/libcore/fmt/float.rs @@ -0,0 +1,94 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug}; +use num::flt2dec; + +// Common code of floating point Debug and Display. +fn float_to_decimal_common(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result + where T: flt2dec::DecodableFloat +{ + let force_sign = fmt.sign_plus(); + let sign = match (force_sign, negative_zero) { + (false, false) => flt2dec::Sign::Minus, + (false, true) => flt2dec::Sign::MinusRaw, + (true, false) => flt2dec::Sign::MinusPlus, + (true, true) => flt2dec::Sign::MinusPlusRaw, + }; + + let mut buf = [0; 1024]; // enough for f32 and f64 + let mut parts = [flt2dec::Part::Zero(0); 16]; + let formatted = if let Some(precision) = fmt.precision { + flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign, + precision, false, &mut buf, &mut parts) + } else { + flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign, + 0, false, &mut buf, &mut parts) + }; + fmt.pad_formatted_parts(&formatted) +} + +// Common code of floating point LowerExp and UpperExp. +fn float_to_exponential_common(fmt: &mut Formatter, num: &T, upper: bool) -> Result + where T: flt2dec::DecodableFloat +{ + let force_sign = fmt.sign_plus(); + let sign = match force_sign { + false => flt2dec::Sign::Minus, + true => flt2dec::Sign::MinusPlus, + }; + + let mut buf = [0; 1024]; // enough for f32 and f64 + let mut parts = [flt2dec::Part::Zero(0); 16]; + let formatted = if let Some(precision) = fmt.precision { + // 1 integral digit + `precision` fractional digits = `precision + 1` total digits + flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign, + precision + 1, upper, &mut buf, &mut parts) + } else { + flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign, + (0, 0), upper, &mut buf, &mut parts) + }; + fmt.pad_formatted_parts(&formatted) +} + +macro_rules! floating { + ($ty:ident) => ( + #[stable(feature = "rust1", since = "1.0.0")] + impl Debug for $ty { + fn fmt(&self, fmt: &mut Formatter) -> Result { + float_to_decimal_common(fmt, self, true) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl Display for $ty { + fn fmt(&self, fmt: &mut Formatter) -> Result { + float_to_decimal_common(fmt, self, false) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl LowerExp for $ty { + fn fmt(&self, fmt: &mut Formatter) -> Result { + float_to_exponential_common(fmt, self, false) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl UpperExp for $ty { + fn fmt(&self, fmt: &mut Formatter) -> Result { + float_to_exponential_common(fmt, self, true) + } + } + ) +} + +floating! { f32 } +floating! { f64 } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index a989f914db616..eb086c201812a 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -21,6 +21,10 @@ use result; use slice; use str; +mod float; +mod num; +mod builders; + #[unstable(feature = "fmt_flags_align", issue = "27726")] /// Possible alignments returned by `Formatter::align` #[derive(Debug)] @@ -38,9 +42,6 @@ pub enum Alignment { #[stable(feature = "debug_builders", since = "1.2.0")] pub use self::builders::{DebugStruct, DebugTuple, DebugSet, DebugList, DebugMap}; -mod num; -mod builders; - #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "0")] #[doc(hidden)] @@ -1511,86 +1512,6 @@ impl<'a, T: ?Sized> Pointer for &'a mut T { } } -// Common code of floating point Debug and Display. -fn float_to_decimal_common(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result - where T: flt2dec::DecodableFloat -{ - let force_sign = fmt.sign_plus(); - let sign = match (force_sign, negative_zero) { - (false, false) => flt2dec::Sign::Minus, - (false, true) => flt2dec::Sign::MinusRaw, - (true, false) => flt2dec::Sign::MinusPlus, - (true, true) => flt2dec::Sign::MinusPlusRaw, - }; - - let mut buf = [0; 1024]; // enough for f32 and f64 - let mut parts = [flt2dec::Part::Zero(0); 16]; - let formatted = if let Some(precision) = fmt.precision { - flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign, - precision, false, &mut buf, &mut parts) - } else { - flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign, - 0, false, &mut buf, &mut parts) - }; - fmt.pad_formatted_parts(&formatted) -} - -// Common code of floating point LowerExp and UpperExp. -fn float_to_exponential_common(fmt: &mut Formatter, num: &T, upper: bool) -> Result - where T: flt2dec::DecodableFloat -{ - let force_sign = fmt.sign_plus(); - let sign = match force_sign { - false => flt2dec::Sign::Minus, - true => flt2dec::Sign::MinusPlus, - }; - - let mut buf = [0; 1024]; // enough for f32 and f64 - let mut parts = [flt2dec::Part::Zero(0); 16]; - let formatted = if let Some(precision) = fmt.precision { - // 1 integral digit + `precision` fractional digits = `precision + 1` total digits - flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign, - precision + 1, upper, &mut buf, &mut parts) - } else { - flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign, - (0, 0), upper, &mut buf, &mut parts) - }; - fmt.pad_formatted_parts(&formatted) -} - -macro_rules! floating { ($ty:ident) => { - - #[stable(feature = "rust1", since = "1.0.0")] - impl Debug for $ty { - fn fmt(&self, fmt: &mut Formatter) -> Result { - float_to_decimal_common(fmt, self, true) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl Display for $ty { - fn fmt(&self, fmt: &mut Formatter) -> Result { - float_to_decimal_common(fmt, self, false) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl LowerExp for $ty { - fn fmt(&self, fmt: &mut Formatter) -> Result { - float_to_exponential_common(fmt, self, false) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl UpperExp for $ty { - fn fmt(&self, fmt: &mut Formatter) -> Result { - float_to_exponential_common(fmt, self, true) - } - } -} } -floating! { f32 } -floating! { f64 } - // Implementation of Display/Debug for various core types #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcoretest/fmt/float.rs b/src/libcoretest/fmt/float.rs index 16cd2feddc0b8..695001312e4d5 100644 --- a/src/libcoretest/fmt/float.rs +++ b/src/libcoretest/fmt/float.rs @@ -9,11 +9,29 @@ // except according to those terms. #[test] -fn test_format_float() { - assert!("1" == format!("{:.0}", 1.0f64)); - assert!("9" == format!("{:.0}", 9.4f64)); - assert!("10" == format!("{:.0}", 9.9f64)); - assert!("9.8" == format!("{:.1}", 9.849f64)); - assert!("9.9" == format!("{:.1}", 9.851f64)); - assert!("1" == format!("{:.0}", 0.5f64)); +fn test_format_f64() { + assert_eq!("1", format!("{:.0}", 1.0f64)); + assert_eq!("9", format!("{:.0}", 9.4f64)); + assert_eq!("10", format!("{:.0}", 9.9f64)); + assert_eq!("9.8", format!("{:.1}", 9.849f64)); + assert_eq!("9.9", format!("{:.1}", 9.851f64)); + assert_eq!("1", format!("{:.0}", 0.5f64)); + assert_eq!("1.23456789e6", format!("{:e}", 1234567.89f64)); + assert_eq!("1.23456789e3", format!("{:e}", 1234.56789f64)); + assert_eq!("1.23456789E6", format!("{:E}", 1234567.89f64)); + assert_eq!("1.23456789E3", format!("{:E}", 1234.56789f64)); +} + +#[test] +fn test_format_f32() { + assert_eq!("1", format!("{:.0}", 1.0f32)); + assert_eq!("9", format!("{:.0}", 9.4f32)); + assert_eq!("10", format!("{:.0}", 9.9f32)); + assert_eq!("9.8", format!("{:.1}", 9.849f32)); + assert_eq!("9.9", format!("{:.1}", 9.851f32)); + assert_eq!("1", format!("{:.0}", 0.5f32)); + assert_eq!("1.2345679e6", format!("{:e}", 1234567.89f32)); + assert_eq!("1.2345679e3", format!("{:e}", 1234.56789f32)); + assert_eq!("1.2345679E6", format!("{:E}", 1234567.89f32)); + assert_eq!("1.2345679E3", format!("{:E}", 1234.56789f32)); }