From fc9b234928c1d64cc45686d9e61bb5993d8747fa Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 31 Oct 2020 11:50:34 -0700 Subject: [PATCH 1/5] Add IEEE754 tests --- library/core/tests/num/ieee754.rs | 158 ++++++++++++++++++++++++++++++ library/core/tests/num/mod.rs | 1 + 2 files changed, 159 insertions(+) create mode 100644 library/core/tests/num/ieee754.rs diff --git a/library/core/tests/num/ieee754.rs b/library/core/tests/num/ieee754.rs new file mode 100644 index 0000000000000..f6e5dfc98c793 --- /dev/null +++ b/library/core/tests/num/ieee754.rs @@ -0,0 +1,158 @@ +//! IEEE 754 floating point compliance tests +//! +//! To understand IEEE 754's requirements on a programming language, one must understand that the +//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any +//! one component. That means the hardware, language, and even libraries are considered part of +//! conforming floating point support in a programming environment. +//! +//! A programming language's duty, accordingly, is: +//! 1. offer access to the hardware where the hardware offers support +//! 2. provide operations that fulfill the remaining requirements of the standard +//! 3. provide the ability to write additional software that can fulfill those requirements +//! +//! This may be fulfilled in any combination that the language sees fit. However, to claim that +//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without +//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined +//! as complete support for at least one specified floating point type as an "arithmetic" and +//! "interchange" format, plus specified type conversions to "external character sequences" and +//! integer types. +//! +//! For our purposes, +//! "interchange format" => f32, f64 +//! "arithmetic format" => f32, f64, and any "soft floats" +//! "external character sequence" => str from any float +//! "integer format" => {i,u}{8,16,32,64,128} +//! +//! None of these tests are against Rust's own implementation. They are only tests against the +//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests. +//! Please consider this carefully when adding, removing, or reorganizing these tests. They are +//! here so that it is clear what tests are required by the standard and what can be changed. +use ::core::str::FromStr; + +// IEEE 754 for many tests is applied to specific bit patterns. +// These generally are not applicable to NaN, however. +macro_rules! assert_biteq { + ($lhs:expr, $rhs:expr) => { + assert_eq!($lhs.to_bits(), $rhs.to_bits()) + }; +} + +// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts +// of the formatting infrastructure, which makes it ideal for testing here. +#[allow(unused_macros)] +macro_rules! roundtrip { + ($f:expr => $t:ty) => { + ($f).to_string().parse::<$t>().unwrap() + }; +} + +macro_rules! assert_floats_roundtrip { + ($f:ident) => { + assert_biteq!(f32::$f, roundtrip!(f32::$f => f32)); + assert_biteq!(f64::$f, roundtrip!(f64::$f => f64)); + }; + ($f:expr) => { + assert_biteq!($f as f32, roundtrip!($f => f32)); + assert_biteq!($f as f64, roundtrip!($f => f64)); + } +} + +macro_rules! assert_floats_bitne { + ($lhs:ident, $rhs:ident) => { + assert_ne!(f32::$lhs.to_bits(), f32::$rhs.to_bits()); + assert_ne!(f64::$lhs.to_bits(), f64::$rhs.to_bits()); + }; + ($lhs:expr, $rhs:expr) => { + assert_ne!(f32::to_bits($lhs), f32::to_bits($rhs)); + assert_ne!(f64::to_bits($lhs), f64::to_bits($rhs)); + }; +} + +// We must preserve signs on all numbers. That includes zero. +// -0 and 0 are == normally, so test bit equality. +#[test] +fn preserve_signed_zero() { + assert_floats_roundtrip!(-0.0); + assert_floats_roundtrip!(0.0); + assert_floats_bitne!(0.0, -0.0); +} + +#[test] +fn preserve_signed_infinity() { + assert_floats_roundtrip!(INFINITY); + assert_floats_roundtrip!(NEG_INFINITY); + assert_floats_bitne!(INFINITY, NEG_INFINITY); +} + +#[test] +fn infinity_to_str() { + assert!(match f32::INFINITY.to_string().to_lowercase().as_str() { + "+infinity" | "infinity" => true, + "+inf" | "inf" => true, + _ => false, + }); + assert!( + match f64::INFINITY.to_string().to_lowercase().as_str() { + "+infinity" | "infinity" => true, + "+inf" | "inf" => true, + _ => false, + }, + "Infinity must write to a string as some casing of inf or infinity, with an optional +." + ); +} + +#[test] +fn neg_infinity_to_str() { + assert!(match f32::NEG_INFINITY.to_string().to_lowercase().as_str() { + "-infinity" | "-inf" => true, + _ => false, + }); + assert!( + match f64::NEG_INFINITY.to_string().to_lowercase().as_str() { + "-infinity" | "-inf" => true, + _ => false, + }, + "Negative Infinity must write to a string as some casing of -inf or -infinity" + ) +} + +#[test] +fn nan_to_str() { + assert!( + match f32::NAN.to_string().to_lowercase().as_str() { + "nan" | "+nan" | "-nan" => true, + _ => false, + }, + "NaNs must write to a string as some casing of nan." + ) +} + +// "+"?("inf"|"infinity") in any case => Infinity +#[test] +fn infinity_from_str() { + assert_biteq!(f32::INFINITY, f32::from_str("infinity").unwrap()); + assert_biteq!(f32::INFINITY, f32::from_str("inf").unwrap()); + assert_biteq!(f32::INFINITY, f32::from_str("+infinity").unwrap()); + assert_biteq!(f32::INFINITY, f32::from_str("+inf").unwrap()); + // yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd + assert_biteq!(f32::INFINITY, f32::from_str("+iNfInItY").unwrap()); +} + +// "-inf"|"-infinity" in any case => Negative Infinity +#[test] +fn neg_infinity_from_str() { + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-infinity").unwrap()); + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-inf").unwrap()); + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INF").unwrap()); + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INFinity").unwrap()); +} + +// ("+"|"-"")?"s"?"nan" in any case => qNaN +#[test] +fn qnan_from_str() { + assert!("nan".parse::().unwrap().is_nan()); + assert!("-nan".parse::().unwrap().is_nan()); + assert!("+nan".parse::().unwrap().is_nan()); + assert!("+NAN".parse::().unwrap().is_nan()); + assert!("-NaN".parse::().unwrap().is_nan()); +} diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index e66a73ac1289b..bbb67667dfc05 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -32,6 +32,7 @@ mod flt2dec; mod ops; mod wrapping; +mod ieee754; mod nan; /// Adds the attribute to all items in the block. From 588cc644ad6d6d6419dcd48651ae451557cdc100 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 31 Oct 2020 12:30:22 -0700 Subject: [PATCH 2/5] Add ability to read NaN/Infinity --- library/core/src/num/dec2flt/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index 20ac165c6c798..f008a64ffe653 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -239,13 +239,15 @@ fn dec2flt(s: &str) -> Result { ParseResult::Valid(decimal) => convert(decimal)?, ParseResult::ShortcutToInf => T::INFINITY, ParseResult::ShortcutToZero => T::ZERO, - ParseResult::Invalid => match s { - "inf" => T::INFINITY, - "NaN" => T::NAN, - _ => { + ParseResult::Invalid => { + if s.eq_ignore_ascii_case("nan") { + T::NAN + } else if s.eq_ignore_ascii_case("inf") || s.eq_ignore_ascii_case("infinity") { + T::INFINITY + } else { return Err(pfe_invalid()); } - }, + } }; match sign { From 74db93ed2d0677bbca8ba85617f05eae745363d8 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 31 Oct 2020 13:16:14 -0700 Subject: [PATCH 3/5] Preserve signed zero on roundtrip This commit removes the previous mechanism of differentiating between "Debug" and "Display" formattings for the sign of -0 so as to comply with the IEEE 754 standard's requirements on external character sequences preserving various attributes of a floating point representation. In addition, numerous tests are fixed. --- library/alloc/tests/fmt.rs | 3 +- library/core/src/fmt/float.rs | 19 +- library/core/src/num/flt2dec/mod.rs | 32 +-- library/core/tests/num/flt2dec/mod.rs | 246 +++++++----------- ...float_to_exponential_common.ConstProp.diff | 2 +- 5 files changed, 102 insertions(+), 200 deletions(-) diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs index 757fddd241857..ade3bc2d334b0 100644 --- a/library/alloc/tests/fmt.rs +++ b/library/alloc/tests/fmt.rs @@ -154,8 +154,7 @@ fn test_format_macro_interface() { t!(format!("{:+10.3e}", -1.2345e6f64), " -1.234e6"); // Float edge cases - t!(format!("{}", -0.0), "0"); - t!(format!("{:?}", -0.0), "-0.0"); + t!(format!("{}", -0.0), "-0"); t!(format!("{:?}", 0.0), "0.0"); // sign aware zero padding diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 5908da477e11e..ece3cde001580 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -54,21 +54,14 @@ where } // Common code of floating point Debug and Display. -fn float_to_decimal_common( - fmt: &mut Formatter<'_>, - num: &T, - negative_zero: bool, - min_precision: usize, -) -> Result +fn float_to_decimal_common(fmt: &mut Formatter<'_>, num: &T, min_precision: usize) -> 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 sign = match force_sign { + false => flt2dec::Sign::Minus, + true => flt2dec::Sign::MinusPlus, }; if let Some(precision) = fmt.precision { @@ -156,14 +149,14 @@ macro_rules! floating { #[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, 1) + float_to_decimal_common(fmt, self, 1) } } #[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, 0) + float_to_decimal_common(fmt, self, 0) } } diff --git a/library/core/src/num/flt2dec/mod.rs b/library/core/src/num/flt2dec/mod.rs index e8f9d6574e2d0..93bdf5040e08b 100644 --- a/library/core/src/num/flt2dec/mod.rs +++ b/library/core/src/num/flt2dec/mod.rs @@ -399,14 +399,10 @@ fn digits_to_exp_str<'a>( /// Sign formatting options. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Sign { - /// Prints `-` only for the negative non-zero values. - Minus, // -inf -1 0 0 1 inf nan - /// Prints `-` only for any negative values (including the negative zero). - MinusRaw, // -inf -1 -0 0 1 inf nan - /// Prints `-` for the negative non-zero values, or `+` otherwise. - MinusPlus, // -inf -1 +0 +0 +1 +inf nan - /// Prints `-` for any negative values (including the negative zero), or `+` otherwise. - MinusPlusRaw, // -inf -1 -0 +0 +1 +inf nan + /// Prints `-` for any negative value. + Minus, // -inf -1 -0 0 1 inf nan + /// Prints `-` for any negative value, or `+` otherwise. + MinusPlus, // -inf -1 -0 +0 +1 +inf nan } /// Returns the static byte string corresponding to the sign to be formatted. @@ -414,30 +410,14 @@ pub enum Sign { fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static str { match (*decoded, sign) { (FullDecoded::Nan, _) => "", - (FullDecoded::Zero, Sign::Minus) => "", - (FullDecoded::Zero, Sign::MinusRaw) => { + (_, Sign::Minus) => { if negative { "-" } else { "" } } - (FullDecoded::Zero, Sign::MinusPlus) => "+", - (FullDecoded::Zero, Sign::MinusPlusRaw) => { - if negative { - "-" - } else { - "+" - } - } - (_, Sign::Minus | Sign::MinusRaw) => { - if negative { - "-" - } else { - "" - } - } - (_, Sign::MinusPlus | Sign::MinusPlusRaw) => { + (_, Sign::MinusPlus) => { if negative { "-" } else { diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs index 8e95249a79d19..960a7ca5ff508 100644 --- a/library/core/tests/num/flt2dec/mod.rs +++ b/library/core/tests/num/flt2dec/mod.rs @@ -514,51 +514,38 @@ where let f = &mut f_; assert_eq!(to_string(f, 0.0, Minus, 0), "0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 0), "0"); + assert_eq!(to_string(f, 0.0, Minus, 0), "0"); assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0), "+0"); - assert_eq!(to_string(f, -0.0, Minus, 0), "0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 0), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0), "-0"); + assert_eq!(to_string(f, -0.0, Minus, 0), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0"); + assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 1), "0.0"); assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1), "+0.0"); - assert_eq!(to_string(f, -0.0, Minus, 8), "0.00000000"); - assert_eq!(to_string(f, -0.0, MinusRaw, 8), "-0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8), "+0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000"); assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 0), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 0), "+inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 0), "+inf"); assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 1), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 64), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN"); assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 1), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 8), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf"); assert_eq!(to_string(f, 3.14, Minus, 0), "3.14"); - assert_eq!(to_string(f, 3.14, MinusRaw, 0), "3.14"); + assert_eq!(to_string(f, 3.14, Minus, 0), "3.14"); assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3.14"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0), "+3.14"); assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusRaw, 0), "-3.14"); + assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14"); assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0), "-3.14"); assert_eq!(to_string(f, 3.14, Minus, 1), "3.14"); - assert_eq!(to_string(f, 3.14, MinusRaw, 2), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3), "+3.140"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4), "+3.1400"); + assert_eq!(to_string(f, 3.14, Minus, 2), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400"); + assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusRaw, 8), "-3.14000000"); assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8), "-3.14000000"); assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0.000000000075"); assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000000000075"); @@ -615,68 +602,48 @@ where let f = &mut f_; assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); - assert_eq!(to_string(f, 0.0, MinusRaw, (-4, 16), false), "0"); + assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); assert_eq!(to_string(f, 0.0, MinusPlus, (-4, 16), false), "+0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, (-4, 16), false), "+0"); - assert_eq!(to_string(f, -0.0, Minus, (-4, 16), false), "0"); - assert_eq!(to_string(f, -0.0, MinusRaw, (-4, 16), false), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, (-4, 16), false), "+0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, (-4, 16), false), "-0"); + assert_eq!(to_string(f, -0.0, Minus, (-4, 16), false), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, (-4, 16), false), "-0"); assert_eq!(to_string(f, 0.0, Minus, (0, 0), true), "0E0"); - assert_eq!(to_string(f, 0.0, MinusRaw, (0, 0), false), "0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, (-9, -5), true), "+0E0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, (5, 9), false), "+0e0"); - assert_eq!(to_string(f, -0.0, Minus, (0, 0), true), "0E0"); - assert_eq!(to_string(f, -0.0, MinusRaw, (0, 0), false), "-0e0"); - assert_eq!(to_string(f, -0.0, MinusPlus, (-9, -5), true), "+0E0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, (5, 9), false), "-0e0"); + assert_eq!(to_string(f, 0.0, Minus, (0, 0), false), "0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, (5, 9), false), "+0e0"); + assert_eq!(to_string(f, -0.0, Minus, (0, 0), true), "-0E0"); + assert_eq!(to_string(f, -0.0, MinusPlus, (5, 9), false), "-0e0"); assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), false), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, (-4, 16), true), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, (-4, 16), false), "+inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, (-4, 16), true), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), true), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, (-4, 16), true), "+inf"); assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, (0, 0), true), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, (-9, -5), false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, (5, 9), true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, (5, 9), true), "NaN"); assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, (0, 0), true), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, (-9, -5), false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, (5, 9), true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, (5, 9), true), "-inf"); assert_eq!(to_string(f, 3.14, Minus, (-4, 16), false), "3.14"); - assert_eq!(to_string(f, 3.14, MinusRaw, (-4, 16), false), "3.14"); assert_eq!(to_string(f, 3.14, MinusPlus, (-4, 16), false), "+3.14"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, (-4, 16), false), "+3.14"); assert_eq!(to_string(f, -3.14, Minus, (-4, 16), false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusRaw, (-4, 16), false), "-3.14"); assert_eq!(to_string(f, -3.14, MinusPlus, (-4, 16), false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, (-4, 16), false), "-3.14"); assert_eq!(to_string(f, 3.14, Minus, (0, 0), true), "3.14E0"); - assert_eq!(to_string(f, 3.14, MinusRaw, (0, 0), false), "3.14e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, (-9, -5), true), "+3.14E0"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, (5, 9), false), "+3.14e0"); + assert_eq!(to_string(f, 3.14, Minus, (0, 0), false), "3.14e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, (5, 9), false), "+3.14e0"); assert_eq!(to_string(f, -3.14, Minus, (0, 0), true), "-3.14E0"); - assert_eq!(to_string(f, -3.14, MinusRaw, (0, 0), false), "-3.14e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, (-9, -5), true), "-3.14E0"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, (5, 9), false), "-3.14e0"); + assert_eq!(to_string(f, -3.14, Minus, (0, 0), false), "-3.14e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, (5, 9), false), "-3.14e0"); assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); - assert_eq!(to_string(f, 0.1, MinusRaw, (-4, 16), false), "0.1"); + assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); assert_eq!(to_string(f, 0.1, MinusPlus, (-4, 16), false), "+0.1"); - assert_eq!(to_string(f, 0.1, MinusPlusRaw, (-4, 16), false), "+0.1"); assert_eq!(to_string(f, -0.1, Minus, (-4, 16), false), "-0.1"); - assert_eq!(to_string(f, -0.1, MinusRaw, (-4, 16), false), "-0.1"); assert_eq!(to_string(f, -0.1, MinusPlus, (-4, 16), false), "-0.1"); - assert_eq!(to_string(f, -0.1, MinusPlusRaw, (-4, 16), false), "-0.1"); assert_eq!(to_string(f, 0.1, Minus, (0, 0), true), "1E-1"); - assert_eq!(to_string(f, 0.1, MinusRaw, (0, 0), false), "1e-1"); - assert_eq!(to_string(f, 0.1, MinusPlus, (-9, -5), true), "+1E-1"); - assert_eq!(to_string(f, 0.1, MinusPlusRaw, (5, 9), false), "+1e-1"); + assert_eq!(to_string(f, 0.1, Minus, (0, 0), false), "1e-1"); + assert_eq!(to_string(f, 0.1, MinusPlus, (5, 9), false), "+1e-1"); assert_eq!(to_string(f, -0.1, Minus, (0, 0), true), "-1E-1"); - assert_eq!(to_string(f, -0.1, MinusRaw, (0, 0), false), "-1e-1"); - assert_eq!(to_string(f, -0.1, MinusPlus, (-9, -5), true), "-1E-1"); - assert_eq!(to_string(f, -0.1, MinusPlusRaw, (5, 9), false), "-1e-1"); + assert_eq!(to_string(f, -0.1, Minus, (0, 0), false), "-1e-1"); + assert_eq!(to_string(f, -0.1, MinusPlus, (5, 9), false), "-1e-1"); assert_eq!(to_string(f, 7.5e-11, Minus, (-4, 16), false), "7.5e-11"); assert_eq!(to_string(f, 7.5e-11, Minus, (-11, 10), false), "0.000000000075"); @@ -734,68 +701,51 @@ where let f = &mut f_; assert_eq!(to_string(f, 0.0, Minus, 1, true), "0E0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 1, false), "0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0E0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, false), "+0e0"); - assert_eq!(to_string(f, -0.0, Minus, 1, true), "0E0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 1, false), "-0e0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 1, true), "+0E0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 1, false), "-0e0"); + assert_eq!(to_string(f, 0.0, Minus, 1, false), "0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1, false), "+0e0"); + assert_eq!(to_string(f, -0.0, Minus, 1, true), "-0E0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 1, false), "-0e0"); assert_eq!(to_string(f, 0.0, Minus, 2, true), "0.0E0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 2, false), "0.0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 2, true), "+0.0E0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 2, false), "+0.0e0"); - assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.0000000E0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 8, false), "-0.0000000e0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.0000000E0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, false), "-0.0000000e0"); + assert_eq!(to_string(f, 0.0, Minus, 2, false), "0.0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 2, false), "+0.0e0"); + assert_eq!(to_string(f, -0.0, Minus, 8, false), "-0.0000000e0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8, false), "-0.0000000e0"); assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, false), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 1, true), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 1, false), "+inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 1, true), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, true), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 1, true), "+inf"); assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 8, true), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 8, true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, true), "NaN"); assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 64, true), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64, false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64, true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64, true), "-inf"); assert_eq!(to_string(f, 3.14, Minus, 1, true), "3E0"); - assert_eq!(to_string(f, 3.14, MinusRaw, 1, false), "3e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, 1, true), "+3E0"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 1, false), "+3e0"); + assert_eq!(to_string(f, 3.14, Minus, 1, false), "3e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, 1, false), "+3e0"); assert_eq!(to_string(f, -3.14, Minus, 2, true), "-3.1E0"); - assert_eq!(to_string(f, -3.14, MinusRaw, 2, false), "-3.1e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, 2, true), "-3.1E0"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 2, false), "-3.1e0"); + assert_eq!(to_string(f, -3.14, Minus, 2, false), "-3.1e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, 2, false), "-3.1e0"); assert_eq!(to_string(f, 3.14, Minus, 3, true), "3.14E0"); - assert_eq!(to_string(f, 3.14, MinusRaw, 3, false), "3.14e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.14E0"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 3, false), "+3.14e0"); + assert_eq!(to_string(f, 3.14, Minus, 3, false), "3.14e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, 3, false), "+3.14e0"); assert_eq!(to_string(f, -3.14, Minus, 4, true), "-3.140E0"); - assert_eq!(to_string(f, -3.14, MinusRaw, 4, false), "-3.140e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, 4, true), "-3.140E0"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 4, false), "-3.140e0"); + assert_eq!(to_string(f, -3.14, Minus, 4, false), "-3.140e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, 4, false), "-3.140e0"); assert_eq!(to_string(f, 0.195, Minus, 1, false), "2e-1"); - assert_eq!(to_string(f, 0.195, MinusRaw, 1, true), "2E-1"); - assert_eq!(to_string(f, 0.195, MinusPlus, 1, false), "+2e-1"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 1, true), "+2E-1"); + assert_eq!(to_string(f, 0.195, Minus, 1, true), "2E-1"); + assert_eq!(to_string(f, 0.195, MinusPlus, 1, true), "+2E-1"); assert_eq!(to_string(f, -0.195, Minus, 2, false), "-2.0e-1"); - assert_eq!(to_string(f, -0.195, MinusRaw, 2, true), "-2.0E-1"); - assert_eq!(to_string(f, -0.195, MinusPlus, 2, false), "-2.0e-1"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 2, true), "-2.0E-1"); + assert_eq!(to_string(f, -0.195, Minus, 2, true), "-2.0E-1"); + assert_eq!(to_string(f, -0.195, MinusPlus, 2, true), "-2.0E-1"); assert_eq!(to_string(f, 0.195, Minus, 3, false), "1.95e-1"); - assert_eq!(to_string(f, 0.195, MinusRaw, 3, true), "1.95E-1"); - assert_eq!(to_string(f, 0.195, MinusPlus, 3, false), "+1.95e-1"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 3, true), "+1.95E-1"); + assert_eq!(to_string(f, 0.195, Minus, 3, true), "1.95E-1"); + assert_eq!(to_string(f, 0.195, MinusPlus, 3, true), "+1.95E-1"); assert_eq!(to_string(f, -0.195, Minus, 4, false), "-1.950e-1"); - assert_eq!(to_string(f, -0.195, MinusRaw, 4, true), "-1.950E-1"); - assert_eq!(to_string(f, -0.195, MinusPlus, 4, false), "-1.950e-1"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 4, true), "-1.950E-1"); + assert_eq!(to_string(f, -0.195, Minus, 4, true), "-1.950E-1"); + assert_eq!(to_string(f, -0.195, MinusPlus, 4, true), "-1.950E-1"); assert_eq!(to_string(f, 9.5, Minus, 1, false), "1e1"); assert_eq!(to_string(f, 9.5, Minus, 2, false), "9.5e0"); @@ -1007,68 +957,48 @@ where let f = &mut f_; assert_eq!(to_string(f, 0.0, Minus, 0), "0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 0), "0"); assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0), "+0"); - assert_eq!(to_string(f, -0.0, Minus, 0), "0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 0), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0), "-0"); + assert_eq!(to_string(f, -0.0, Minus, 0), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0"); assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 1), "0.0"); assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1), "+0.0"); - assert_eq!(to_string(f, -0.0, Minus, 8), "0.00000000"); - assert_eq!(to_string(f, -0.0, MinusRaw, 8), "-0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8), "+0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000"); assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 1), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 8), "+inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 64), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 64), "+inf"); assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 1), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 64), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN"); assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 1), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 8), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf"); assert_eq!(to_string(f, 3.14, Minus, 0), "3"); - assert_eq!(to_string(f, 3.14, MinusRaw, 0), "3"); + assert_eq!(to_string(f, 3.14, Minus, 0), "3"); assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0), "+3"); assert_eq!(to_string(f, -3.14, Minus, 0), "-3"); - assert_eq!(to_string(f, -3.14, MinusRaw, 0), "-3"); + assert_eq!(to_string(f, -3.14, Minus, 0), "-3"); assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0), "-3"); assert_eq!(to_string(f, 3.14, Minus, 1), "3.1"); - assert_eq!(to_string(f, 3.14, MinusRaw, 2), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3), "+3.140"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4), "+3.1400"); + assert_eq!(to_string(f, 3.14, Minus, 2), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400"); + assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusRaw, 8), "-3.14000000"); assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8), "-3.14000000"); assert_eq!(to_string(f, 0.195, Minus, 0), "0"); - assert_eq!(to_string(f, 0.195, MinusRaw, 0), "0"); assert_eq!(to_string(f, 0.195, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 0), "+0"); assert_eq!(to_string(f, -0.195, Minus, 0), "-0"); - assert_eq!(to_string(f, -0.195, MinusRaw, 0), "-0"); + assert_eq!(to_string(f, -0.195, Minus, 0), "-0"); assert_eq!(to_string(f, -0.195, MinusPlus, 0), "-0"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 0), "-0"); assert_eq!(to_string(f, 0.195, Minus, 1), "0.2"); - assert_eq!(to_string(f, 0.195, MinusRaw, 2), "0.20"); - assert_eq!(to_string(f, 0.195, MinusPlus, 3), "+0.195"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 4), "+0.1950"); + assert_eq!(to_string(f, 0.195, Minus, 2), "0.20"); + assert_eq!(to_string(f, 0.195, MinusPlus, 4), "+0.1950"); assert_eq!(to_string(f, -0.195, Minus, 5), "-0.19500"); - assert_eq!(to_string(f, -0.195, MinusRaw, 6), "-0.195000"); - assert_eq!(to_string(f, -0.195, MinusPlus, 7), "-0.1950000"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 8), "-0.19500000"); + assert_eq!(to_string(f, -0.195, Minus, 6), "-0.195000"); + assert_eq!(to_string(f, -0.195, MinusPlus, 8), "-0.19500000"); assert_eq!(to_string(f, 999.5, Minus, 0), "1000"); assert_eq!(to_string(f, 999.5, Minus, 1), "999.5"); diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff index caa02abf01936..3a50ed224b552 100644 --- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff +++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff @@ -51,7 +51,7 @@ } bb2: { - discriminant(_6) = 2; // scope 1 at $DIR/funky_arms.rs:21:17: 21:41 + discriminant(_6) = 1; // scope 1 at $DIR/funky_arms.rs:21:17: 21:41 goto -> bb4; // scope 1 at $DIR/funky_arms.rs:19:16: 22:6 } From 6fdb8d8b360b91a10045fe74467b98d218b7ffe9 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 31 Oct 2020 17:21:23 -0700 Subject: [PATCH 4/5] Update signed fmt/-0f32 docs "semantic equivalence" is too strong a phrasing here, which is why actually explaining what kind of circumstances might produce a -0 was chosen instead. --- library/alloc/src/fmt.rs | 5 ++--- library/std/src/primitive_docs.rs | 8 +++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index f9424b1d74744..439b0adde2015 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -157,9 +157,8 @@ //! //! * `+` - This is intended for numeric types and indicates that the sign //! should always be printed. Positive signs are never printed by -//! default, and the negative sign is only printed by default for the -//! `Signed` trait. This flag indicates that the correct sign (`+` or `-`) -//! should always be printed. +//! default, and the negative sign is only printed by default for signed values. +//! This flag indicates that the correct sign (`+` or `-`) should always be printed. //! * `-` - Currently not used //! * `#` - This flag indicates that the "alternate" form of printing should //! be used. The alternate forms are: diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index d4bb2083d00d8..b48718df31c4e 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -805,10 +805,12 @@ mod prim_tuple {} /// often discard insignificant digits: `println!("{}", 1.0f32 / 5.0f32)` will /// print `0.2`. /// -/// Additionally, `f32` can represent a couple of special values: +/// Additionally, `f32` can represent some special values: /// -/// - `-0`: this is just due to how floats are encoded. It is semantically -/// equivalent to `0` and `-0.0 == 0.0` results in `true`. +/// - `-0`: this value exists due to how floats are encoded. -0 == 0 is true, but for other +/// operations they are not equal and the difference can be useful to certain algorithms. +/// For example, operations on negative numbers that underflow to 0 will usually generate -0 +/// instead of +0. /// - [∞](#associatedconstant.INFINITY) and /// [−∞](#associatedconstant.NEG_INFINITY): these result from calculations /// like `1.0 / 0.0`. From e8dfbaca76616a32cabba30ec343cd4fcb28bda9 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 1 Nov 2020 10:31:08 -0800 Subject: [PATCH 5/5] Rephrase -0.0 docs --- library/std/src/primitive_docs.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index b48718df31c4e..64b22b64f4bf1 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -807,10 +807,10 @@ mod prim_tuple {} /// /// Additionally, `f32` can represent some special values: /// -/// - `-0`: this value exists due to how floats are encoded. -0 == 0 is true, but for other -/// operations they are not equal and the difference can be useful to certain algorithms. -/// For example, operations on negative numbers that underflow to 0 will usually generate -0 -/// instead of +0. +/// - -0.0: IEEE 754 floating point numbers have a bit that indicates their sign, so -0.0 is a +/// possible value. For comparison `-0.0 == +0.0` is true but floating point operations can +/// carry the sign bit through arithmetic operations. This means `-1.0 * 0.0` produces -0.0 and +/// a negative number rounded to a value smaller than a float can represent also produces -0.0. /// - [∞](#associatedconstant.INFINITY) and /// [−∞](#associatedconstant.NEG_INFINITY): these result from calculations /// like `1.0 / 0.0`.