From b825477154e32e8538e00e1e230dadf93bc7e6df Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 21 May 2018 10:45:11 +0200 Subject: [PATCH] Remove the unstable Float trait Following up to #49896 and #50629. Fixes #32110. E0689 is weird. --- src/libcore/num/dec2flt/rawfp.rs | 33 ++- src/libcore/num/f32.rs | 222 ++++++----------- src/libcore/num/f64.rs | 228 ++++++------------ src/libcore/num/mod.rs | 55 ----- src/libcore/tests/num/mod.rs | 77 +++--- src/librustc_typeck/diagnostics.rs | 12 +- .../macro-backtrace-invalid-internals.rs | 4 +- .../macro-backtrace-invalid-internals.stderr | 16 +- .../method-on-ambiguous-numeric-type.rs | 8 +- .../method-on-ambiguous-numeric-type.stderr | 14 +- 10 files changed, 232 insertions(+), 437 deletions(-) diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 77180233a2389..456d0e956d42a 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -33,7 +33,7 @@ use ops::{Add, Mul, Div, Neg}; use fmt::{Debug, LowerExp}; use num::diy_float::Fp; use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan}; -use num::Float; +use num::FpCategory; use num::dec2flt::num::{self, Big}; use num::dec2flt::table; @@ -54,24 +54,29 @@ impl Unpacked { /// See the parent module's doc comment for why this is necessary. /// /// Should **never ever** be implemented for other types or be used outside the dec2flt module. -/// Inherits from `Float` because there is some overlap, but all the reused methods are trivial. pub trait RawFloat - : Float - + Copy + : Copy + Debug + LowerExp + Mul + Div + Neg -where - Self: Float::RawBits> { const INFINITY: Self; const NAN: Self; const ZERO: Self; - /// Same as `Float::Bits` with extra traits. - type RawBits: Add + From + TryFrom; + /// Type used by `to_bits` and `from_bits`. + type Bits: Add + From + TryFrom; + + /// Raw transmutation to integer. + fn to_bits(self) -> Self::Bits; + + /// Raw transmutation from integer. + fn from_bits(v: Self::Bits) -> Self; + + /// Returns the category that this number falls into. + fn classify(self) -> FpCategory; /// Returns the mantissa, exponent and sign as integers. fn integer_decode(self) -> (u64, i16, i8); @@ -153,7 +158,7 @@ macro_rules! other_constants { } impl RawFloat for f32 { - type RawBits = u32; + type Bits = u32; const SIG_BITS: u8 = 24; const EXP_BITS: u8 = 8; @@ -192,11 +197,15 @@ impl RawFloat for f32 { fn short_fast_pow10(e: usize) -> Self { table::F32_SHORT_POWERS[e] } + + fn classify(self) -> FpCategory { self.classify() } + fn to_bits(self) -> Self::Bits { self.to_bits() } + fn from_bits(v: Self::Bits) -> Self { Self::from_bits(v) } } impl RawFloat for f64 { - type RawBits = u64; + type Bits = u64; const SIG_BITS: u8 = 53; const EXP_BITS: u8 = 11; @@ -235,6 +244,10 @@ impl RawFloat for f64 { fn short_fast_pow10(e: usize) -> Self { table::F64_SHORT_POWERS[e] } + + fn classify(self) -> FpCategory { self.classify() } + fn to_bits(self) -> Self::Bits { self.to_bits() } + fn from_bits(v: Self::Bits) -> Self { Self::from_bits(v) } } /// Convert an Fp to the closest machine float type. diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 718dd42a61535..e5dbc65cd99bb 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -18,9 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use mem; -use num::Float; use num::FpCategory; -use num::FpCategory as Fp; /// The radix or base of the internal representation of `f32`. #[stable(feature = "rust1", since = "1.0.0")] @@ -149,136 +147,9 @@ pub mod consts { pub const LN_10: f32 = 2.30258509299404568401799145468436421_f32; } -#[unstable(feature = "core_float", - reason = "stable interface is via `impl f{32,64}` in later crates", - issue = "32110")] -impl Float for f32 { - type Bits = u32; - - /// Returns `true` if the number is NaN. - #[inline] - fn is_nan(self) -> bool { - self != self - } - - /// Returns `true` if the number is infinite. - #[inline] - fn is_infinite(self) -> bool { - self == INFINITY || self == NEG_INFINITY - } - - /// Returns `true` if the number is neither infinite or NaN. - #[inline] - fn is_finite(self) -> bool { - !(self.is_nan() || self.is_infinite()) - } - - /// Returns `true` if the number is neither zero, infinite, subnormal or NaN. - #[inline] - fn is_normal(self) -> bool { - self.classify() == Fp::Normal - } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - fn classify(self) -> Fp { - const EXP_MASK: u32 = 0x7f800000; - const MAN_MASK: u32 = 0x007fffff; - - let bits = self.to_bits(); - match (bits & MAN_MASK, bits & EXP_MASK) { - (0, 0) => Fp::Zero, - (_, 0) => Fp::Subnormal, - (0, EXP_MASK) => Fp::Infinite, - (_, EXP_MASK) => Fp::Nan, - _ => Fp::Normal, - } - } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - #[inline] - fn is_sign_positive(self) -> bool { - !self.is_sign_negative() - } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - #[inline] - fn is_sign_negative(self) -> bool { - // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus - // applies to zeros and NaNs as well. - self.to_bits() & 0x8000_0000 != 0 - } - - /// Returns the reciprocal (multiplicative inverse) of the number. - #[inline] - fn recip(self) -> f32 { - 1.0 / self - } - - /// Converts to degrees, assuming the number is in radians. - #[inline] - fn to_degrees(self) -> f32 { - // Use a constant for better precision. - const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; - self * PIS_IN_180 - } - - /// Converts to radians, assuming the number is in degrees. - #[inline] - fn to_radians(self) -> f32 { - let value: f32 = consts::PI; - self * (value / 180.0f32) - } - - /// Returns the maximum of the two numbers. - #[inline] - fn max(self, other: f32) -> f32 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self.is_nan() || self < other { other } else { self }) * 1.0 - } - - /// Returns the minimum of the two numbers. - #[inline] - fn min(self, other: f32) -> f32 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if other.is_nan() || self < other { self } else { other }) * 1.0 - } - - /// Raw transmutation to `u32`. - #[inline] - fn to_bits(self) -> u32 { - unsafe { mem::transmute(self) } - } - - /// Raw transmutation from `u32`. - #[inline] - fn from_bits(v: u32) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { mem::transmute(v) } - } -} - -// FIXME: remove (inline) this macro and the Float trait -// when updating to a bootstrap compiler that has the new lang items. -#[unstable(feature = "core_float", issue = "32110")] -macro_rules! f32_core_methods { () => { +#[lang = "f32"] +#[cfg(not(test))] +impl f32 { /// Returns `true` if this value is `NaN` and false otherwise. /// /// ``` @@ -292,7 +163,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_nan(self) -> bool { Float::is_nan(self) } + pub fn is_nan(self) -> bool { + self != self + } /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. @@ -313,7 +186,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + pub fn is_infinite(self) -> bool { + self == INFINITY || self == NEG_INFINITY + } /// Returns `true` if this number is neither infinite nor `NaN`. /// @@ -333,7 +208,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_finite(self) -> bool { Float::is_finite(self) } + pub fn is_finite(self) -> bool { + !(self.is_nan() || self.is_infinite()) + } /// Returns `true` if the number is neither zero, infinite, /// [subnormal][subnormal], or `NaN`. @@ -358,7 +235,9 @@ macro_rules! f32_core_methods { () => { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_normal(self) -> bool { Float::is_normal(self) } + pub fn is_normal(self) -> bool { + self.classify() == FpCategory::Normal + } /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific @@ -375,8 +254,19 @@ macro_rules! f32_core_methods { () => { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { Float::classify(self) } + pub fn classify(self) -> FpCategory { + const EXP_MASK: u32 = 0x7f800000; + const MAN_MASK: u32 = 0x007fffff; + + let bits = self.to_bits(); + match (bits & MAN_MASK, bits & EXP_MASK) { + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + (0, EXP_MASK) => FpCategory::Infinite, + (_, EXP_MASK) => FpCategory::Nan, + _ => FpCategory::Normal, + } + } /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. @@ -390,7 +280,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + pub fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with /// negative sign bit and negative infinity. @@ -404,7 +296,11 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + pub fn is_sign_negative(self) -> bool { + // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus + // applies to zeros and NaNs as well. + self.to_bits() & 0x8000_0000 != 0 + } /// Takes the reciprocal (inverse) of a number, `1/x`. /// @@ -418,7 +314,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn recip(self) -> f32 { Float::recip(self) } + pub fn recip(self) -> f32 { + 1.0 / self + } /// Converts radians to degrees. /// @@ -433,7 +331,11 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] #[inline] - pub fn to_degrees(self) -> f32 { Float::to_degrees(self) } + pub fn to_degrees(self) -> f32 { + // Use a constant for better precision. + const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; + self * PIS_IN_180 + } /// Converts degrees to radians. /// @@ -448,7 +350,10 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] #[inline] - pub fn to_radians(self) -> f32 { Float::to_radians(self) } + pub fn to_radians(self) -> f32 { + let value: f32 = consts::PI; + self * (value / 180.0f32) + } /// Returns the maximum of the two numbers. /// @@ -463,7 +368,15 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f32) -> f32 { - Float::max(self, other) + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if self.is_nan() || self < other { other } else { self }) * 1.0 } /// Returns the minimum of the two numbers. @@ -479,7 +392,15 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f32) -> f32 { - Float::min(self, other) + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if other.is_nan() || self < other { self } else { other }) * 1.0 } /// Raw transmutation to `u32`. @@ -502,7 +423,7 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u32 { - Float::to_bits(self) + unsafe { mem::transmute(self) } } /// Raw transmutation from `u32`. @@ -546,12 +467,7 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u32) -> Self { - Float::from_bits(v) + // It turns out the safety issues with sNaN were overblown! Hooray! + unsafe { mem::transmute(v) } } -}} - -#[lang = "f32"] -#[cfg(not(test))] -impl f32 { - f32_core_methods!(); } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index f128c55c78afa..eb769c4ad5a3b 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -18,9 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use mem; -use num::Float; use num::FpCategory; -use num::FpCategory as Fp; /// The radix or base of the internal representation of `f64`. #[stable(feature = "rust1", since = "1.0.0")] @@ -149,135 +147,9 @@ pub mod consts { pub const LN_10: f64 = 2.30258509299404568401799145468436421_f64; } -#[unstable(feature = "core_float", - reason = "stable interface is via `impl f{32,64}` in later crates", - issue = "32110")] -impl Float for f64 { - type Bits = u64; - - /// Returns `true` if the number is NaN. - #[inline] - fn is_nan(self) -> bool { - self != self - } - - /// Returns `true` if the number is infinite. - #[inline] - fn is_infinite(self) -> bool { - self == INFINITY || self == NEG_INFINITY - } - - /// Returns `true` if the number is neither infinite or NaN. - #[inline] - fn is_finite(self) -> bool { - !(self.is_nan() || self.is_infinite()) - } - - /// Returns `true` if the number is neither zero, infinite, subnormal or NaN. - #[inline] - fn is_normal(self) -> bool { - self.classify() == Fp::Normal - } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - fn classify(self) -> Fp { - const EXP_MASK: u64 = 0x7ff0000000000000; - const MAN_MASK: u64 = 0x000fffffffffffff; - - let bits = self.to_bits(); - match (bits & MAN_MASK, bits & EXP_MASK) { - (0, 0) => Fp::Zero, - (_, 0) => Fp::Subnormal, - (0, EXP_MASK) => Fp::Infinite, - (_, EXP_MASK) => Fp::Nan, - _ => Fp::Normal, - } - } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - #[inline] - fn is_sign_positive(self) -> bool { - !self.is_sign_negative() - } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - #[inline] - fn is_sign_negative(self) -> bool { - self.to_bits() & 0x8000_0000_0000_0000 != 0 - } - - /// Returns the reciprocal (multiplicative inverse) of the number. - #[inline] - fn recip(self) -> f64 { - 1.0 / self - } - - /// Converts to degrees, assuming the number is in radians. - #[inline] - fn to_degrees(self) -> f64 { - // The division here is correctly rounded with respect to the true - // value of 180/π. (This differs from f32, where a constant must be - // used to ensure a correctly rounded result.) - self * (180.0f64 / consts::PI) - } - - /// Converts to radians, assuming the number is in degrees. - #[inline] - fn to_radians(self) -> f64 { - let value: f64 = consts::PI; - self * (value / 180.0) - } - - /// Returns the maximum of the two numbers. - #[inline] - fn max(self, other: f64) -> f64 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self.is_nan() || self < other { other } else { self }) * 1.0 - } - - /// Returns the minimum of the two numbers. - #[inline] - fn min(self, other: f64) -> f64 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if other.is_nan() || self < other { self } else { other }) * 1.0 - } - - /// Raw transmutation to `u64`. - #[inline] - fn to_bits(self) -> u64 { - unsafe { mem::transmute(self) } - } - - /// Raw transmutation from `u64`. - #[inline] - fn from_bits(v: u64) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { mem::transmute(v) } - } -} - -// FIXME: remove (inline) this macro and the Float trait -// when updating to a bootstrap compiler that has the new lang items. -#[unstable(feature = "core_float", issue = "32110")] -macro_rules! f64_core_methods { () => { +#[lang = "f64"] +#[cfg(not(test))] +impl f64 { /// Returns `true` if this value is `NaN` and false otherwise. /// /// ``` @@ -291,7 +163,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_nan(self) -> bool { Float::is_nan(self) } + pub fn is_nan(self) -> bool { + self != self + } /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. @@ -312,7 +186,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + pub fn is_infinite(self) -> bool { + self == INFINITY || self == NEG_INFINITY + } /// Returns `true` if this number is neither infinite nor `NaN`. /// @@ -332,7 +208,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_finite(self) -> bool { Float::is_finite(self) } + pub fn is_finite(self) -> bool { + !(self.is_nan() || self.is_infinite()) + } /// Returns `true` if the number is neither zero, infinite, /// [subnormal][subnormal], or `NaN`. @@ -357,7 +235,9 @@ macro_rules! f64_core_methods { () => { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_normal(self) -> bool { Float::is_normal(self) } + pub fn is_normal(self) -> bool { + self.classify() == FpCategory::Normal + } /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific @@ -374,8 +254,19 @@ macro_rules! f64_core_methods { () => { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { Float::classify(self) } + pub fn classify(self) -> FpCategory { + const EXP_MASK: u64 = 0x7ff0000000000000; + const MAN_MASK: u64 = 0x000fffffffffffff; + + let bits = self.to_bits(); + match (bits & MAN_MASK, bits & EXP_MASK) { + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + (0, EXP_MASK) => FpCategory::Infinite, + (_, EXP_MASK) => FpCategory::Nan, + _ => FpCategory::Normal, + } + } /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. @@ -389,13 +280,17 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + pub fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] #[inline] #[doc(hidden)] - pub fn is_positive(self) -> bool { Float::is_sign_positive(self) } + pub fn is_positive(self) -> bool { + self.is_sign_positive() + } /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with /// negative sign bit and negative infinity. @@ -409,13 +304,17 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + pub fn is_sign_negative(self) -> bool { + self.to_bits() & 0x8000_0000_0000_0000 != 0 + } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] #[inline] #[doc(hidden)] - pub fn is_negative(self) -> bool { Float::is_sign_negative(self) } + pub fn is_negative(self) -> bool { + self.is_sign_negative() + } /// Takes the reciprocal (inverse) of a number, `1/x`. /// @@ -427,7 +326,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn recip(self) -> f64 { Float::recip(self) } + pub fn recip(self) -> f64 { + 1.0 / self + } /// Converts radians to degrees. /// @@ -442,7 +343,12 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn to_degrees(self) -> f64 { Float::to_degrees(self) } + pub fn to_degrees(self) -> f64 { + // The division here is correctly rounded with respect to the true + // value of 180/π. (This differs from f32, where a constant must be + // used to ensure a correctly rounded result.) + self * (180.0f64 / consts::PI) + } /// Converts degrees to radians. /// @@ -457,7 +363,10 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn to_radians(self) -> f64 { Float::to_radians(self) } + pub fn to_radians(self) -> f64 { + let value: f64 = consts::PI; + self * (value / 180.0) + } /// Returns the maximum of the two numbers. /// @@ -472,7 +381,15 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f64) -> f64 { - Float::max(self, other) + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if self.is_nan() || self < other { other } else { self }) * 1.0 } /// Returns the minimum of the two numbers. @@ -488,7 +405,15 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f64) -> f64 { - Float::min(self, other) + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if other.is_nan() || self < other { self } else { other }) * 1.0 } /// Raw transmutation to `u64`. @@ -511,7 +436,7 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u64 { - Float::to_bits(self) + unsafe { mem::transmute(self) } } /// Raw transmutation from `u64`. @@ -555,12 +480,7 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u64) -> Self { - Float::from_bits(v) + // It turns out the safety issues with sNaN were overblown! Hooray! + unsafe { mem::transmute(v) } } -}} - -#[lang = "f64"] -#[cfg(not(test))] -impl f64 { - f64_core_methods!(); } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 58d45b107f169..232ecb8fbae18 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4080,61 +4080,6 @@ pub enum FpCategory { Normal, } -// Technically private and only exposed for coretests: -#[doc(hidden)] -#[unstable(feature = "float_internals", - reason = "internal routines only exposed for testing", - issue = "0")] -pub trait Float: Sized { - /// Type used by `to_bits` and `from_bits`. - type Bits; - - /// Returns `true` if this value is NaN and false otherwise. - fn is_nan(self) -> bool; - - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - fn is_infinite(self) -> bool; - - /// Returns `true` if this number is neither infinite nor NaN. - fn is_finite(self) -> bool; - - /// Returns `true` if this number is neither zero, infinite, denormal, or NaN. - fn is_normal(self) -> bool; - - /// Returns the category that this number falls into. - fn classify(self) -> FpCategory; - - /// Returns `true` if `self` is positive, including `+0.0` and - /// `Float::infinity()`. - fn is_sign_positive(self) -> bool; - - /// Returns `true` if `self` is negative, including `-0.0` and - /// `Float::neg_infinity()`. - fn is_sign_negative(self) -> bool; - - /// Take the reciprocal (inverse) of a number, `1/x`. - fn recip(self) -> Self; - - /// Convert radians to degrees. - fn to_degrees(self) -> Self; - - /// Convert degrees to radians. - fn to_radians(self) -> Self; - - /// Returns the maximum of the two numbers. - fn max(self, other: Self) -> Self; - - /// Returns the minimum of the two numbers. - fn min(self, other: Self) -> Self; - - /// Raw transmutation to integer. - fn to_bits(self) -> Self::Bits; - - /// Raw transmutation from integer. - fn from_bits(v: Self::Bits) -> Self; -} - macro_rules! from_str_radix_int_impl { ($($t:ty)*) => {$( #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index c7edb55b378c3..f3439890fce50 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -508,51 +508,50 @@ assume_usize_width! { macro_rules! test_float { ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => { mod $modname { - use core::num::Float; // FIXME(nagisa): these tests should test for sign of -0.0 #[test] fn min() { - assert_eq!(0.0.min(0.0), 0.0); - assert_eq!((-0.0).min(-0.0), -0.0); - assert_eq!(9.0.min(9.0), 9.0); - assert_eq!((-9.0).min(0.0), -9.0); - assert_eq!(0.0.min(9.0), 0.0); - assert_eq!((-0.0).min(-9.0), -9.0); - assert_eq!($inf.min(9.0), 9.0); - assert_eq!(9.0.min($inf), 9.0); - assert_eq!($inf.min(-9.0), -9.0); - assert_eq!((-9.0).min($inf), -9.0); - assert_eq!($neginf.min(9.0), $neginf); - assert_eq!(9.0.min($neginf), $neginf); - assert_eq!($neginf.min(-9.0), $neginf); - assert_eq!((-9.0).min($neginf), $neginf); - assert_eq!($nan.min(9.0), 9.0); - assert_eq!($nan.min(-9.0), -9.0); - assert_eq!(9.0.min($nan), 9.0); - assert_eq!((-9.0).min($nan), -9.0); - assert!($nan.min($nan).is_nan()); + assert_eq!((0.0 as $fty).min(0.0), 0.0); + assert_eq!((-0.0 as $fty).min(-0.0), -0.0); + assert_eq!((9.0 as $fty).min(9.0), 9.0); + assert_eq!((-9.0 as $fty).min(0.0), -9.0); + assert_eq!((0.0 as $fty).min(9.0), 0.0); + assert_eq!((-0.0 as $fty).min(-9.0), -9.0); + assert_eq!(($inf as $fty).min(9.0), 9.0); + assert_eq!((9.0 as $fty).min($inf), 9.0); + assert_eq!(($inf as $fty).min(-9.0), -9.0); + assert_eq!((-9.0 as $fty).min($inf), -9.0); + assert_eq!(($neginf as $fty).min(9.0), $neginf); + assert_eq!((9.0 as $fty).min($neginf), $neginf); + assert_eq!(($neginf as $fty).min(-9.0), $neginf); + assert_eq!((-9.0 as $fty).min($neginf), $neginf); + assert_eq!(($nan as $fty).min(9.0), 9.0); + assert_eq!(($nan as $fty).min(-9.0), -9.0); + assert_eq!((9.0 as $fty).min($nan), 9.0); + assert_eq!((-9.0 as $fty).min($nan), -9.0); + assert!(($nan as $fty).min($nan).is_nan()); } #[test] fn max() { - assert_eq!(0.0.max(0.0), 0.0); - assert_eq!((-0.0).max(-0.0), -0.0); - assert_eq!(9.0.max(9.0), 9.0); - assert_eq!((-9.0).max(0.0), 0.0); - assert_eq!(0.0.max(9.0), 9.0); - assert_eq!((-0.0).max(-9.0), -0.0); - assert_eq!($inf.max(9.0), $inf); - assert_eq!(9.0.max($inf), $inf); - assert_eq!($inf.max(-9.0), $inf); - assert_eq!((-9.0).max($inf), $inf); - assert_eq!($neginf.max(9.0), 9.0); - assert_eq!(9.0.max($neginf), 9.0); - assert_eq!($neginf.max(-9.0), -9.0); - assert_eq!((-9.0).max($neginf), -9.0); - assert_eq!($nan.max(9.0), 9.0); - assert_eq!($nan.max(-9.0), -9.0); - assert_eq!(9.0.max($nan), 9.0); - assert_eq!((-9.0).max($nan), -9.0); - assert!($nan.max($nan).is_nan()); + assert_eq!((0.0 as $fty).max(0.0), 0.0); + assert_eq!((-0.0 as $fty).max(-0.0), -0.0); + assert_eq!((9.0 as $fty).max(9.0), 9.0); + assert_eq!((-9.0 as $fty).max(0.0), 0.0); + assert_eq!((0.0 as $fty).max(9.0), 9.0); + assert_eq!((-0.0 as $fty).max(-9.0), -0.0); + assert_eq!(($inf as $fty).max(9.0), $inf); + assert_eq!((9.0 as $fty).max($inf), $inf); + assert_eq!(($inf as $fty).max(-9.0), $inf); + assert_eq!((-9.0 as $fty).max($inf), $inf); + assert_eq!(($neginf as $fty).max(9.0), 9.0); + assert_eq!((9.0 as $fty).max($neginf), 9.0); + assert_eq!(($neginf as $fty).max(-9.0), -9.0); + assert_eq!((-9.0 as $fty).max($neginf), -9.0); + assert_eq!(($nan as $fty).max(9.0), 9.0); + assert_eq!(($nan as $fty).max(-9.0), -9.0); + assert_eq!((9.0 as $fty).max($nan), 9.0); + assert_eq!((-9.0 as $fty).max($nan), -9.0); + assert!(($nan as $fty).max($nan).is_nan()); } } } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 7a572bbbffd91..e6a66cd613e9c 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4552,23 +4552,25 @@ but the type of the numeric value or binding could not be identified. The error happens on numeric literals: ```compile_fail,E0689 -2.0.recip(); +2.0.neg(); ``` and on numeric bindings without an identified concrete type: ```compile_fail,E0689 let x = 2.0; -x.recip(); // same error as above +x.neg(); // same error as above ``` Because of this, you must give the numeric literal or binding a type: ``` -let _ = 2.0_f32.recip(); +use std::ops::Neg; + +let _ = 2.0_f32.neg(); let x: f32 = 2.0; -let _ = x.recip(); -let _ = (2.0 as f32).recip(); +let _ = x.neg(); +let _ = (2.0 as f32).neg(); ``` "##, diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.rs b/src/test/ui/macros/macro-backtrace-invalid-internals.rs index 090ff817eb0f2..0bc2dd5a601bd 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.rs +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.rs @@ -48,13 +48,13 @@ macro_rules! fake_anon_field_expr { macro_rules! real_method_stmt { () => { - 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` + 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` } } macro_rules! real_method_expr { () => { - 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` + 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` } } diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr index 284960d2f6e15..ec8eee6573989 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -25,17 +25,17 @@ LL | (1).0 //~ ERROR doesn't have fields LL | fake_anon_field_stmt!(); | ------------------------ in this macro invocation -error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:51:15 | -LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` - | ^^^^^ +LL | 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` + | ^^^ ... LL | real_method_stmt!(); | -------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` +LL | 2.0_f32.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` | ^^^^^^^ error[E0599]: no method named `fake` found for type `{integer}` in the current scope @@ -65,17 +65,17 @@ LL | (1).0 //~ ERROR doesn't have fields LL | let _ = fake_anon_field_expr!(); | ----------------------- in this macro invocation -error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:57:15 | -LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` - | ^^^^^ +LL | 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` + | ^^^ ... LL | let _ = real_method_expr!(); | ------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` +LL | 2.0_f32.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` | ^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs index 2e452f9671f38..9bf74c3875fed 100644 --- a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs +++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs @@ -9,10 +9,10 @@ // except according to those terms. fn main() { - let x = 2.0.recip(); - //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}` + let x = 2.0.neg(); + //~^ ERROR can't call method `neg` on ambiguous numeric type `{float}` let y = 2.0; - let x = y.recip(); - //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}` + let x = y.neg(); + //~^ ERROR can't call method `neg` on ambiguous numeric type `{float}` println!("{:?}", x); } diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr index 477b4c3821d51..68c8be7dff8c9 100644 --- a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr +++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr @@ -1,18 +1,18 @@ -error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` --> $DIR/method-on-ambiguous-numeric-type.rs:12:17 | -LL | let x = 2.0.recip(); - | ^^^^^ +LL | let x = 2.0.neg(); + | ^^^ help: you must specify a concrete type for this numeric value, like `f32` | -LL | let x = 2.0_f32.recip(); +LL | let x = 2.0_f32.neg(); | ^^^^^^^ -error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` --> $DIR/method-on-ambiguous-numeric-type.rs:15:15 | -LL | let x = y.recip(); - | ^^^^^ +LL | let x = y.neg(); + | ^^^ help: you must specify a type for this binding, like `f32` | LL | let y: f32 = 2.0;