use crate::mem::MaybeUninit;
use crate::num::flt2dec;
+#[doc(hidden)]
+trait GeneralFormat: PartialOrd {
+ /// Determines if a value should use exponential based on its magnitude, given the precondition
+ /// that it will not be rounded any further before it is displayed.
+ fn already_rounded_value_should_use_exponential(&self) -> bool;
+}
+
+macro_rules! impl_general_format {
+ ($($t:ident)*) => {
+ $(impl GeneralFormat for $t {
+ fn already_rounded_value_should_use_exponential(&self) -> bool {
+ let abs = $t::abs_private(*self);
+ (abs != 0.0 && abs < 1e-4) || abs >= 1e+16
+ }
+ })*
+ }
+}
+
+impl_general_format! { f32 f64 }
+
// Don't inline this so callers don't use the stack space this function
// requires unless they have to.
#[inline(never)]
fmt.pad_formatted_parts(&formatted)
}
-// Common code of floating point Debug and Display.
-fn float_to_decimal_common<T>(fmt: &mut Formatter<'_>, num: &T, min_precision: usize) -> Result
+fn float_to_decimal_display<T>(fmt: &mut Formatter<'_>, num: &T) -> Result
where
T: flt2dec::DecodableFloat,
{
if let Some(precision) = fmt.precision {
float_to_decimal_common_exact(fmt, num, sign, precision)
} else {
+ let min_precision = 0;
float_to_decimal_common_shortest(fmt, num, sign, min_precision)
}
}
}
}
+fn float_to_general_debug<T>(fmt: &mut Formatter<'_>, num: &T) -> Result
+where
+ T: flt2dec::DecodableFloat + GeneralFormat,
+{
+ let force_sign = fmt.sign_plus();
+ let sign = match force_sign {
+ false => flt2dec::Sign::Minus,
+ true => flt2dec::Sign::MinusPlus,
+ };
+
+ if let Some(precision) = fmt.precision {
+ // this behavior of {:.PREC?} predates exponential formatting for {:?}
+ float_to_decimal_common_exact(fmt, num, sign, precision)
+ } else {
+ // since there is no precision, there will be no rounding
+ if num.already_rounded_value_should_use_exponential() {
+ let upper = false;
+ float_to_exponential_common_shortest(fmt, num, sign, upper)
+ } else {
+ let min_precision = 1;
+ float_to_decimal_common_shortest(fmt, num, sign, min_precision)
+ }
+ }
+}
+
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, 1)
+ float_to_general_debug(fmt, self)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Display for $ty {
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
- float_to_decimal_common(fmt, self, 0)
+ float_to_decimal_display(fmt, self)
}
}
assert_eq!("1.23456789E3", format!("{:E}", 1234.56789f64));
assert_eq!("0.0", format!("{:?}", 0.0f64));
assert_eq!("1.01", format!("{:?}", 1.01f64));
+
+ let high_cutoff = 1e16_f64;
+ assert_eq!("1e16", format!("{:?}", high_cutoff));
+ assert_eq!("-1e16", format!("{:?}", -high_cutoff));
+ assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f64::EPSILON))));
+ assert_eq!("-3.0", format!("{:?}", -3f64));
+ assert_eq!("0.0001", format!("{:?}", 0.0001f64));
+ assert_eq!("9e-5", format!("{:?}", 0.00009f64));
+ assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f64));
+ assert_eq!("1234.6", format!("{:.1?}", 1234.56789f64));
}
#[test]
assert_eq!("1.2345679E3", format!("{:E}", 1234.56789f32));
assert_eq!("0.0", format!("{:?}", 0.0f32));
assert_eq!("1.01", format!("{:?}", 1.01f32));
+
+ let high_cutoff = 1e16_f32;
+ assert_eq!("1e16", format!("{:?}", high_cutoff));
+ assert_eq!("-1e16", format!("{:?}", -high_cutoff));
+ assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f32::EPSILON))));
+ assert_eq!("-3.0", format!("{:?}", -3f32));
+ assert_eq!("0.0001", format!("{:?}", 0.0001f32));
+ assert_eq!("9e-5", format!("{:?}", 0.00009f32));
+ assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f32));
+ assert_eq!("1234.6", format!("{:.1?}", 1234.56789f32));
+}
+
+fn is_exponential(s: &str) -> bool {
+ s.contains("e") || s.contains("E")
}