diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 6a458436726cf..87ce27b0d86de 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -1,6 +1,6 @@ use crate::fmt::{Debug, Display, Formatter, LowerExp, Result, UpperExp}; use crate::mem::MaybeUninit; -use crate::num::{flt2dec, fmt as numfmt}; +use crate::num::imp::{flt2dec, fmt as numfmt}; #[doc(hidden)] trait GeneralFormat: PartialOrd { diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index e20109c3cc9a8..05d8e0d84f057 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -6,7 +6,7 @@ use crate::cell::{Cell, Ref, RefCell, RefMut, SyncUnsafeCell, UnsafeCell}; use crate::char::EscapeDebugExtArgs; use crate::hint::assert_unchecked; use crate::marker::{PhantomData, PointeeSized}; -use crate::num::fmt as numfmt; +use crate::num::imp::fmt as numfmt; use crate::ops::Deref; use crate::ptr::NonNull; use crate::{iter, mem, result, str}; diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 253a7b7587e49..d3d6495e75a2a 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -2,7 +2,7 @@ use crate::fmt::NumBuffer; use crate::mem::MaybeUninit; -use crate::num::fmt as numfmt; +use crate::num::imp::fmt as numfmt; use crate::{fmt, str}; /// Formatting of integers with a non-decimal radix. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 463f07da91b28..cb9c7d78aae2c 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -14,7 +14,7 @@ use crate::convert::FloatToInt; use crate::num::FpCategory; #[cfg(not(test))] -use crate::num::libm; +use crate::num::imp::libm; use crate::panic::const_assert; use crate::{intrinsics, mem}; diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index be908cb3894b7..3de8e29df2b82 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1633,7 +1633,7 @@ impl f32 { #[unstable(feature = "core_float_math", issue = "137578")] pub mod math { use crate::intrinsics; - use crate::num::libm; + use crate::num::imp::libm; /// Experimental version of `floor` in `core`. See [`f32::floor`] for details. /// diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 73b20a50ff8ee..8704430e84405 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1631,7 +1631,7 @@ impl f64 { /// They will be stabilized as inherent methods._ pub mod math { use crate::intrinsics; - use crate::num::libm; + use crate::num::imp::libm; /// Experimental version of `floor` in `core`. See [`f64::floor`] for details. /// diff --git a/library/core/src/num/float_parse.rs b/library/core/src/num/float_parse.rs new file mode 100644 index 0000000000000..d8846a0cc0a8e --- /dev/null +++ b/library/core/src/num/float_parse.rs @@ -0,0 +1,133 @@ +//! User-facing API for float parsing. + +use crate::error::Error; +use crate::fmt; +use crate::num::imp::dec2flt; +use crate::str::FromStr; + +macro_rules! from_str_float_impl { + ($t:ty) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl FromStr for $t { + type Err = ParseFloatError; + + /// Converts a string in base 10 to a float. + /// Accepts an optional decimal exponent. + /// + /// This function accepts strings such as + /// + /// * '3.14' + /// * '-3.14' + /// * '2.5E10', or equivalently, '2.5e10' + /// * '2.5E-10' + /// * '5.' + /// * '.5', or, equivalently, '0.5' + /// * '7' + /// * '007' + /// * 'inf', '-inf', '+infinity', 'NaN' + /// + /// Note that alphabetical characters are not case-sensitive. + /// + /// Leading and trailing whitespace represent an error. + /// + /// # Grammar + /// + /// All strings that adhere to the following [EBNF] grammar when + /// lowercased will result in an [`Ok`] being returned: + /// + /// ```txt + /// Float ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number ) + /// Number ::= ( Digit+ | + /// Digit+ '.' Digit* | + /// Digit* '.' Digit+ ) Exp? + /// Exp ::= 'e' Sign? Digit+ + /// Sign ::= [+-] + /// Digit ::= [0-9] + /// ``` + /// + /// [EBNF]: https://www.w3.org/TR/REC-xml/#sec-notation + /// + /// # Arguments + /// + /// * src - A string + /// + /// # Return value + /// + /// `Err(ParseFloatError)` if the string did not represent a valid + /// number. Otherwise, `Ok(n)` where `n` is the closest + /// representable floating-point number to the number represented + /// by `src` (following the same rules for rounding as for the + /// results of primitive operations). + // We add the `#[inline(never)]` attribute, since its content will + // be filled with that of `dec2flt`, which has #[inline(always)]. + // Since `dec2flt` is generic, a normal inline attribute on this function + // with `dec2flt` having no attributes results in heavily repeated + // generation of `dec2flt`, despite the fact only a maximum of 2 + // possible instances can ever exist. Adding #[inline(never)] avoids this. + #[inline(never)] + fn from_str(src: &str) -> Result { + dec2flt::dec2flt(src) + } + } + }; +} + +#[cfg(target_has_reliable_f16)] +from_str_float_impl!(f16); +from_str_float_impl!(f32); +from_str_float_impl!(f64); + +// FIXME(f16): A fallback is used when the backend+target does not support f16 well, in order +// to avoid ICEs. + +#[cfg(not(target_has_reliable_f16))] +#[expect(ineffective_unstable_trait_impl, reason = "stable trait on unstable type")] +#[unstable(feature = "f16", issue = "116909")] +impl FromStr for f16 { + type Err = ParseFloatError; + + #[inline] + fn from_str(_src: &str) -> Result { + unimplemented!("requires target_has_reliable_f16") + } +} + +/// An error which can be returned when parsing a float. +/// +/// This error is used as the error type for the [`FromStr`] implementation +/// for [`f32`] and [`f64`]. +/// +/// # Example +/// +/// ``` +/// use std::str::FromStr; +/// +/// if let Err(e) = f64::from_str("a.12") { +/// println!("Failed conversion to f64: {e}"); +/// } +/// ``` +#[derive(Debug, Clone, PartialEq, Eq)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ParseFloatError { + pub(super) kind: FloatErrorKind, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(super) enum FloatErrorKind { + Empty, + Invalid, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseFloatError {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseFloatError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.kind { + FloatErrorKind::Empty => "cannot parse float from empty string", + FloatErrorKind::Invalid => "invalid float literal", + } + .fmt(f) + } +} diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/imp/bignum.rs similarity index 98% rename from library/core/src/num/bignum.rs rename to library/core/src/num/imp/bignum.rs index 95b49a38ded06..9e930ed15a234 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/imp/bignum.rs @@ -251,7 +251,7 @@ macro_rules! define_bignum { /// Multiplies itself by `5^e` and returns its own mutable reference. pub fn mul_pow5(&mut self, mut e: usize) -> &mut $name { - use crate::num::bignum::SMALL_POW5; + use crate::num::imp::bignum::SMALL_POW5; // There are exactly n trailing zeros on 2^n, and the only relevant digit sizes // are consecutive powers of two, so this is well suited index for the table. @@ -281,7 +281,7 @@ macro_rules! define_bignum { pub fn mul_digits<'a>(&'a mut self, other: &[$ty]) -> &'a mut $name { // the internal routine. works best when aa.len() <= bb.len(). fn mul_inner(ret: &mut [$ty; $n], aa: &[$ty], bb: &[$ty]) -> usize { - use crate::num::bignum::FullOps; + use crate::num::imp::bignum::FullOps; let mut retsz = 0; for (i, &a) in aa.iter().enumerate() { @@ -320,7 +320,7 @@ macro_rules! define_bignum { /// Divides itself by a digit-sized `other` and returns its own /// mutable reference *and* the remainder. pub fn div_rem_small(&mut self, other: $ty) -> (&mut $name, $ty) { - use crate::num::bignum::FullOps; + use crate::num::imp::bignum::FullOps; assert!(other > 0); diff --git a/library/core/src/num/dec2flt/common.rs b/library/core/src/num/imp/dec2flt/common.rs similarity index 100% rename from library/core/src/num/dec2flt/common.rs rename to library/core/src/num/imp/dec2flt/common.rs diff --git a/library/core/src/num/dec2flt/decimal.rs b/library/core/src/num/imp/dec2flt/decimal.rs similarity index 93% rename from library/core/src/num/dec2flt/decimal.rs rename to library/core/src/num/imp/dec2flt/decimal.rs index db7176c124318..c9b0cc531b386 100644 --- a/library/core/src/num/dec2flt/decimal.rs +++ b/library/core/src/num/imp/dec2flt/decimal.rs @@ -1,7 +1,9 @@ //! Representation of a float as the significant digits and exponent. -use crate::num::dec2flt::float::RawFloat; -use crate::num::dec2flt::fpu::set_precision; +use dec2flt::Lemire; +use dec2flt::fpu::set_precision; + +use crate::num::imp::dec2flt; const INT_POW10: [u64; 16] = [ 1, @@ -34,7 +36,7 @@ pub struct Decimal { impl Decimal { /// Detect if the float can be accurately reconstructed from native floats. #[inline] - fn can_use_fast_path(&self) -> bool { + fn can_use_fast_path(&self) -> bool { F::MIN_EXPONENT_FAST_PATH <= self.exponent && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH && self.mantissa <= F::MAX_MANTISSA_FAST_PATH @@ -51,7 +53,7 @@ impl Decimal { /// /// There is an exception: disguised fast-path cases, where we can shift /// powers-of-10 from the exponent to the significant digits. - pub fn try_fast_path(&self) -> Option { + pub fn try_fast_path(&self) -> Option { // Here we need to work around . // The fast path crucially depends on arithmetic being rounded to the correct number of bits // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision diff --git a/library/core/src/num/dec2flt/decimal_seq.rs b/library/core/src/num/imp/dec2flt/decimal_seq.rs similarity index 99% rename from library/core/src/num/dec2flt/decimal_seq.rs rename to library/core/src/num/imp/dec2flt/decimal_seq.rs index de22280c001c9..0c73cdaa03a0f 100644 --- a/library/core/src/num/dec2flt/decimal_seq.rs +++ b/library/core/src/num/imp/dec2flt/decimal_seq.rs @@ -9,7 +9,9 @@ //! algorithm can be found in "ParseNumberF64 by Simple Decimal Conversion", //! available online: . -use crate::num::dec2flt::common::{ByteSlice, is_8digits}; +use dec2flt::common::{ByteSlice, is_8digits}; + +use crate::num::imp::dec2flt; /// A decimal floating-point number, represented as a sequence of decimal digits. #[derive(Clone, Debug, PartialEq)] diff --git a/library/core/src/num/dec2flt/fpu.rs b/library/core/src/num/imp/dec2flt/fpu.rs similarity index 100% rename from library/core/src/num/dec2flt/fpu.rs rename to library/core/src/num/imp/dec2flt/fpu.rs diff --git a/library/core/src/num/dec2flt/lemire.rs b/library/core/src/num/imp/dec2flt/lemire.rs similarity index 96% rename from library/core/src/num/dec2flt/lemire.rs rename to library/core/src/num/imp/dec2flt/lemire.rs index f84929a03c172..f89d16c843477 100644 --- a/library/core/src/num/dec2flt/lemire.rs +++ b/library/core/src/num/imp/dec2flt/lemire.rs @@ -1,10 +1,9 @@ //! Implementation of the Eisel-Lemire algorithm. -use crate::num::dec2flt::common::BiasedFp; -use crate::num::dec2flt::float::RawFloat; -use crate::num::dec2flt::table::{ - LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE, -}; +use dec2flt::common::BiasedFp; +use dec2flt::table::{LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE}; + +use crate::num::imp::{Float, dec2flt}; /// Compute w * 10^q using an extended-precision float representation. /// @@ -24,7 +23,7 @@ use crate::num::dec2flt::table::{ /// at a Gigabyte per Second" in section 5, "Fast Algorithm", and /// section 6, "Exact Numbers And Ties", available online: /// . -pub fn compute_float(q: i64, mut w: u64) -> BiasedFp { +pub fn compute_float(q: i64, mut w: u64) -> BiasedFp { let fp_zero = BiasedFp::zero_pow2(0); let fp_inf = BiasedFp::zero_pow2(F::INFINITE_POWER); let fp_error = BiasedFp::zero_pow2(-1); diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/imp/dec2flt/mod.rs similarity index 61% rename from library/core/src/num/dec2flt/mod.rs rename to library/core/src/num/imp/dec2flt/mod.rs index 66e30e1c5f7f1..76b8d416ee0f1 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/imp/dec2flt/mod.rs @@ -87,148 +87,103 @@ issue = "none" )] -use self::common::BiasedFp; -use self::float::RawFloat; -use self::lemire::compute_float; -use self::parse::{parse_inf_nan, parse_number}; -use self::slow::parse_long_mantissa; -use crate::error::Error; -use crate::fmt; -use crate::str::FromStr; +use common::BiasedFp; +use lemire::compute_float; +use parse::{parse_inf_nan, parse_number}; +use slow::parse_long_mantissa; + +use crate::f64; +use crate::num::ParseFloatError; +use crate::num::float_parse::FloatErrorKind; +use crate::num::imp::FloatExt; mod common; pub mod decimal; pub mod decimal_seq; mod fpu; -mod slow; -mod table; -// float is used in flt2dec, and all are used in unit tests. -pub mod float; pub mod lemire; pub mod parse; +mod slow; +mod table; -macro_rules! from_str_float_impl { - ($t:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl FromStr for $t { - type Err = ParseFloatError; - - /// Converts a string in base 10 to a float. - /// Accepts an optional decimal exponent. - /// - /// This function accepts strings such as - /// - /// * '3.14' - /// * '-3.14' - /// * '2.5E10', or equivalently, '2.5e10' - /// * '2.5E-10' - /// * '5.' - /// * '.5', or, equivalently, '0.5' - /// * '7' - /// * '007' - /// * 'inf', '-inf', '+infinity', 'NaN' - /// - /// Note that alphabetical characters are not case-sensitive. - /// - /// Leading and trailing whitespace represent an error. - /// - /// # Grammar - /// - /// All strings that adhere to the following [EBNF] grammar when - /// lowercased will result in an [`Ok`] being returned: - /// - /// ```txt - /// Float ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number ) - /// Number ::= ( Digit+ | - /// Digit+ '.' Digit* | - /// Digit* '.' Digit+ ) Exp? - /// Exp ::= 'e' Sign? Digit+ - /// Sign ::= [+-] - /// Digit ::= [0-9] - /// ``` - /// - /// [EBNF]: https://www.w3.org/TR/REC-xml/#sec-notation - /// - /// # Arguments - /// - /// * src - A string - /// - /// # Return value - /// - /// `Err(ParseFloatError)` if the string did not represent a valid - /// number. Otherwise, `Ok(n)` where `n` is the closest - /// representable floating-point number to the number represented - /// by `src` (following the same rules for rounding as for the - /// results of primitive operations). - // We add the `#[inline(never)]` attribute, since its content will - // be filled with that of `dec2flt`, which has #[inline(always)]. - // Since `dec2flt` is generic, a normal inline attribute on this function - // with `dec2flt` having no attributes results in heavily repeated - // generation of `dec2flt`, despite the fact only a maximum of 2 - // possible instances can ever exist. Adding #[inline(never)] avoids this. - #[inline(never)] - fn from_str(src: &str) -> Result { - dec2flt(src) - } - } +/// Extension to `Float` that are necessary for parsing using the Lemire method. +/// +/// See the parent module's doc comment for why this is necessary. +/// +/// Not intended for use outside of the `dec2flt` module. +#[doc(hidden)] +pub trait Lemire: FloatExt { + /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋` + // assuming FLT_EVAL_METHOD = 0 + const MAX_EXPONENT_FAST_PATH: i64 = { + let log2_5 = f64::consts::LOG2_10 - 1.0; + (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64 }; -} -#[cfg(target_has_reliable_f16)] -from_str_float_impl!(f16); -from_str_float_impl!(f32); -from_str_float_impl!(f64); + /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋` + const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH; + + /// Maximum exponent that can be represented for a disguised-fast path case. + /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋` + const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = + Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64; + + /// Maximum mantissa for the fast-path (`1 << 53` for f64). + const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS; + + /// Gets a small power-of-ten for fast-path multiplication. + fn pow10_fast_path(exponent: usize) -> Self; -// FIXME(f16): A fallback is used when the backend+target does not support f16 well, in order -// to avoid ICEs. + /// Converts integer into float through an as cast. + /// This is only called in the fast-path algorithm, and therefore + /// will not lose precision, since the value will always have + /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH. + fn from_u64(v: u64) -> Self; +} -#[cfg(not(target_has_reliable_f16))] -impl FromStr for f16 { - type Err = ParseFloatError; +#[cfg(target_has_reliable_f16)] +impl Lemire for f16 { + fn pow10_fast_path(exponent: usize) -> Self { + #[allow(clippy::use_self)] + const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.]; + TABLE[exponent & 7] + } #[inline] - fn from_str(_src: &str) -> Result { - unimplemented!("requires target_has_reliable_f16") + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ } } -/// An error which can be returned when parsing a float. -/// -/// This error is used as the error type for the [`FromStr`] implementation -/// for [`f32`] and [`f64`]. -/// -/// # Example -/// -/// ``` -/// use std::str::FromStr; -/// -/// if let Err(e) = f64::from_str("a.12") { -/// println!("Failed conversion to f64: {e}"); -/// } -/// ``` -#[derive(Debug, Clone, PartialEq, Eq)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct ParseFloatError { - kind: FloatErrorKind, -} +impl Lemire for f32 { + fn pow10_fast_path(exponent: usize) -> Self { + #[allow(clippy::use_self)] + const TABLE: [f32; 16] = + [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.]; + TABLE[exponent & 15] + } -#[derive(Debug, Clone, PartialEq, Eq)] -enum FloatErrorKind { - Empty, - Invalid, + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ + } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseFloatError {} +impl Lemire for f64 { + fn pow10_fast_path(exponent: usize) -> Self { + const TABLE: [f64; 32] = [ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, + 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0., + ]; + TABLE[exponent & 31] + } -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseFloatError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.kind { - FloatErrorKind::Empty => "cannot parse float from empty string", - FloatErrorKind::Invalid => "invalid float literal", - } - .fmt(f) + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ } } @@ -245,7 +200,7 @@ pub fn pfe_invalid() -> ParseFloatError { } /// Converts a `BiasedFp` to the closest machine float type. -fn biased_fp_to_float(x: BiasedFp) -> F { +fn biased_fp_to_float(x: BiasedFp) -> F { let mut word = x.m; word |= (x.p_biased as u64) << F::SIG_BITS; F::from_u64_bits(word) @@ -253,7 +208,7 @@ fn biased_fp_to_float(x: BiasedFp) -> F { /// Converts a decimal string into a floating point number. #[inline(always)] // Will be inlined into a function with `#[inline(never)]`, see above -pub fn dec2flt(s: &str) -> Result { +pub fn dec2flt(s: &str) -> Result { let mut s = s.as_bytes(); let Some(&c) = s.first() else { return Err(pfe_empty()) }; let negative = c == b'-'; diff --git a/library/core/src/num/dec2flt/parse.rs b/library/core/src/num/imp/dec2flt/parse.rs similarity index 96% rename from library/core/src/num/dec2flt/parse.rs rename to library/core/src/num/imp/dec2flt/parse.rs index e38fedc58bec0..ee55eadbc7b9e 100644 --- a/library/core/src/num/dec2flt/parse.rs +++ b/library/core/src/num/imp/dec2flt/parse.rs @@ -1,8 +1,9 @@ //! Functions to parse floating-point numbers. -use crate::num::dec2flt::common::{ByteSlice, is_8digits}; -use crate::num::dec2flt::decimal::Decimal; -use crate::num::dec2flt::float::RawFloat; +use dec2flt::common::{ByteSlice, is_8digits}; +use dec2flt::decimal::Decimal; + +use crate::num::imp::{Float, dec2flt}; const MIN_19DIGIT_INT: u64 = 100_0000_0000_0000_0000; @@ -195,7 +196,7 @@ pub fn parse_number(s: &[u8]) -> Option { } /// Try to parse a special, non-finite float. -pub(crate) fn parse_inf_nan(s: &[u8], negative: bool) -> Option { +pub(crate) fn parse_inf_nan(s: &[u8], negative: bool) -> Option { // Since a valid string has at most the length 8, we can load // all relevant characters into a u64 and work from there. // This also generates much better code. diff --git a/library/core/src/num/dec2flt/slow.rs b/library/core/src/num/imp/dec2flt/slow.rs similarity index 94% rename from library/core/src/num/dec2flt/slow.rs rename to library/core/src/num/imp/dec2flt/slow.rs index 3baed42652393..f1b2525cf38e6 100644 --- a/library/core/src/num/dec2flt/slow.rs +++ b/library/core/src/num/imp/dec2flt/slow.rs @@ -1,8 +1,9 @@ //! Slow, fallback algorithm for cases the Eisel-Lemire algorithm cannot round. -use crate::num::dec2flt::common::BiasedFp; -use crate::num::dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq}; -use crate::num::dec2flt::float::RawFloat; +use dec2flt::common::BiasedFp; +use dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq}; + +use crate::num::imp::{Float, dec2flt}; /// Parse the significant digits and biased, binary exponent of a float. /// @@ -23,7 +24,7 @@ use crate::num::dec2flt::float::RawFloat; /// /// The algorithms described here are based on "Processing Long Numbers Quickly", /// available here: . -pub(crate) fn parse_long_mantissa(s: &[u8]) -> BiasedFp { +pub(crate) fn parse_long_mantissa(s: &[u8]) -> BiasedFp { const MAX_SHIFT: usize = 60; const NUM_POWERS: usize = 19; const POWERS: [u8; 19] = diff --git a/library/core/src/num/dec2flt/table.rs b/library/core/src/num/imp/dec2flt/table.rs similarity index 100% rename from library/core/src/num/dec2flt/table.rs rename to library/core/src/num/imp/dec2flt/table.rs diff --git a/library/core/src/num/diy_float.rs b/library/core/src/num/imp/diy_float.rs similarity index 100% rename from library/core/src/num/diy_float.rs rename to library/core/src/num/imp/diy_float.rs diff --git a/library/core/src/num/flt2dec/decoder.rs b/library/core/src/num/imp/flt2dec/decoder.rs similarity index 97% rename from library/core/src/num/flt2dec/decoder.rs rename to library/core/src/num/imp/flt2dec/decoder.rs index bd6e2cdbafec8..5ccc91f4c9faf 100644 --- a/library/core/src/num/flt2dec/decoder.rs +++ b/library/core/src/num/imp/flt2dec/decoder.rs @@ -1,7 +1,7 @@ //! Decodes a floating-point value into individual parts and error ranges. use crate::num::FpCategory; -use crate::num::dec2flt::float::RawFloat; +use crate::num::imp::FloatExt; /// Decoded unsigned finite value, such that: /// @@ -40,7 +40,7 @@ pub enum FullDecoded { } /// A floating point type which can be `decode`d. -pub trait DecodableFloat: RawFloat + Copy { +pub trait DecodableFloat: FloatExt + Copy { /// The minimum positive normalized value. fn min_pos_norm_value() -> Self; } diff --git a/library/core/src/num/flt2dec/estimator.rs b/library/core/src/num/imp/flt2dec/estimator.rs similarity index 100% rename from library/core/src/num/flt2dec/estimator.rs rename to library/core/src/num/imp/flt2dec/estimator.rs diff --git a/library/core/src/num/flt2dec/mod.rs b/library/core/src/num/imp/flt2dec/mod.rs similarity index 100% rename from library/core/src/num/flt2dec/mod.rs rename to library/core/src/num/imp/flt2dec/mod.rs diff --git a/library/core/src/num/flt2dec/strategy/dragon.rs b/library/core/src/num/imp/flt2dec/strategy/dragon.rs similarity index 98% rename from library/core/src/num/flt2dec/strategy/dragon.rs rename to library/core/src/num/imp/flt2dec/strategy/dragon.rs index dd73e4b4846d5..de19ca6bb664d 100644 --- a/library/core/src/num/flt2dec/strategy/dragon.rs +++ b/library/core/src/num/imp/flt2dec/strategy/dragon.rs @@ -4,11 +4,13 @@ //! [^1]: Burger, R. G. and Dybvig, R. K. 1996. Printing floating-point numbers //! quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116. +use flt2dec::estimator::estimate_scaling_factor; +use flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; + use crate::cmp::Ordering; use crate::mem::MaybeUninit; -use crate::num::bignum::{Big32x40 as Big, Digit32 as Digit}; -use crate::num::flt2dec::estimator::estimate_scaling_factor; -use crate::num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; +use crate::num::imp::bignum::{Big32x40 as Big, Digit32 as Digit}; +use crate::num::imp::flt2dec; static POW10: [Digit; 10] = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000]; diff --git a/library/core/src/num/flt2dec/strategy/grisu.rs b/library/core/src/num/imp/flt2dec/strategy/grisu.rs similarity index 99% rename from library/core/src/num/flt2dec/strategy/grisu.rs rename to library/core/src/num/imp/flt2dec/strategy/grisu.rs index d3bbb0934e0ff..f7ee465829340 100644 --- a/library/core/src/num/flt2dec/strategy/grisu.rs +++ b/library/core/src/num/imp/flt2dec/strategy/grisu.rs @@ -5,9 +5,11 @@ //! [^1]: Florian Loitsch. 2010. Printing floating-point numbers quickly and //! accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243. +use flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; + use crate::mem::MaybeUninit; -use crate::num::diy_float::Fp; -use crate::num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; +use crate::num::imp::diy_float::Fp; +use crate::num::imp::flt2dec; // see the comments in `format_shortest_opt` for the rationale. #[doc(hidden)] @@ -455,7 +457,7 @@ pub fn format_shortest<'a>( d: &Decoded, buf: &'a mut [MaybeUninit], ) -> (/*digits*/ &'a [u8], /*exp*/ i16) { - use crate::num::flt2dec::strategy::dragon::format_shortest as fallback; + use flt2dec::strategy::dragon::format_shortest as fallback; // SAFETY: The borrow checker is not smart enough to let us use `buf` // in the second branch, so we launder the lifetime here. But we only re-use // `buf` if `format_shortest_opt` returned `None` so this is okay. @@ -765,7 +767,7 @@ pub fn format_exact<'a>( buf: &'a mut [MaybeUninit], limit: i16, ) -> (/*digits*/ &'a [u8], /*exp*/ i16) { - use crate::num::flt2dec::strategy::dragon::format_exact as fallback; + use flt2dec::strategy::dragon::format_exact as fallback; // SAFETY: The borrow checker is not smart enough to let us use `buf` // in the second branch, so we launder the lifetime here. But we only re-use // `buf` if `format_exact_opt` returned `None` so this is okay. diff --git a/library/core/src/num/fmt.rs b/library/core/src/num/imp/fmt.rs similarity index 100% rename from library/core/src/num/fmt.rs rename to library/core/src/num/imp/fmt.rs diff --git a/library/core/src/num/int_bits.rs b/library/core/src/num/imp/int_bits.rs similarity index 97% rename from library/core/src/num/int_bits.rs rename to library/core/src/num/imp/int_bits.rs index 7e54591922358..2bc95e66e7ef6 100644 --- a/library/core/src/num/int_bits.rs +++ b/library/core/src/num/imp/int_bits.rs @@ -64,7 +64,7 @@ macro_rules! uint_impl { ($U:ident) => { - pub(super) mod $U { + pub(in crate::num) mod $U { const STAGES: usize = $U::BITS.ilog2() as usize; #[inline] const fn prepare(sparse: $U) -> [$U; STAGES] { @@ -100,7 +100,7 @@ macro_rules! uint_impl { } #[inline(always)] - pub(in super::super) const fn extract_impl(mut x: $U, sparse: $U) -> $U { + pub(in crate::num) const fn extract_impl(mut x: $U, sparse: $U) -> $U { let masks = prepare(sparse); x &= sparse; let mut stage = 0; @@ -131,7 +131,7 @@ macro_rules! uint_impl { x } #[inline(always)] - pub(in super::super) const fn deposit_impl(mut x: $U, sparse: $U) -> $U { + pub(in crate::num) const fn deposit_impl(mut x: $U, sparse: $U) -> $U { let masks = prepare(sparse); let mut stage = STAGES; while stage > 0 { diff --git a/library/core/src/num/int_log10.rs b/library/core/src/num/imp/int_log10.rs similarity index 94% rename from library/core/src/num/int_log10.rs rename to library/core/src/num/imp/int_log10.rs index af8e1f90968d6..1da029c6a21c4 100644 --- a/library/core/src/num/int_log10.rs +++ b/library/core/src/num/imp/int_log10.rs @@ -96,7 +96,7 @@ const fn u128_impl(mut val: u128) -> u32 { macro_rules! define_unsigned_ilog10 { ($($ty:ident => $impl_fn:ident,)*) => {$( #[inline] - pub(super) const fn $ty(val: NonZero<$ty>) -> u32 { + pub(in crate::num) const fn $ty(val: NonZero<$ty>) -> u32 { let result = $impl_fn(val.get()); // SAFETY: Integer logarithm is monotonic non-decreasing, so the computed `result` cannot @@ -117,7 +117,7 @@ define_unsigned_ilog10! { } #[inline] -pub(super) const fn usize(val: NonZero) -> u32 { +pub(in crate::num) const fn usize(val: NonZero) -> u32 { #[cfg(target_pointer_width = "16")] let impl_fn = u16; @@ -136,7 +136,7 @@ macro_rules! define_signed_ilog10 { ($($ty:ident => $impl_fn:ident,)*) => {$( // 0 < val <= $ty::MAX #[inline] - pub(super) const fn $ty(val: $ty) -> Option { + pub(in crate::num) const fn $ty(val: $ty) -> Option { if val > 0 { let result = $impl_fn(val.cast_unsigned()); @@ -166,6 +166,6 @@ define_signed_ilog10! { /// on every single primitive type. #[cold] #[track_caller] -pub(super) const fn panic_for_nonpositive_argument() -> ! { +pub(in crate::num) const fn panic_for_nonpositive_argument() -> ! { panic!("argument of integer logarithm must be positive") } diff --git a/library/core/src/num/int_sqrt.rs b/library/core/src/num/imp/int_sqrt.rs similarity index 97% rename from library/core/src/num/int_sqrt.rs rename to library/core/src/num/imp/int_sqrt.rs index c7a322c08c139..152841793d56e 100644 --- a/library/core/src/num/int_sqrt.rs +++ b/library/core/src/num/imp/int_sqrt.rs @@ -37,7 +37,7 @@ const U8_ISQRT_WITH_REMAINDER: [(u8, u8); 256] = { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] -pub(super) const fn u8(n: u8) -> u8 { +pub(in crate::num) const fn u8(n: u8) -> u8 { U8_ISQRT_WITH_REMAINDER[n as usize].0 } @@ -58,7 +58,7 @@ macro_rules! signed_fn { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub(super) const unsafe fn $SignedT(n: $SignedT) -> $SignedT { + pub(in crate::num) const unsafe fn $SignedT(n: $SignedT) -> $SignedT { debug_assert!(n >= 0, "Negative input inside `isqrt`."); $UnsignedT(n as $UnsignedT) as $SignedT } @@ -83,7 +83,7 @@ macro_rules! unsigned_fn { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub(super) const fn $UnsignedT(mut n: $UnsignedT) -> $UnsignedT { + pub(in crate::num) const fn $UnsignedT(mut n: $UnsignedT) -> $UnsignedT { if n <= <$HalfBitsT>::MAX as $UnsignedT { $HalfBitsT(n as $HalfBitsT) as $UnsignedT } else { @@ -311,6 +311,6 @@ unsigned_fn!(u128, u64, u128_stages); /// on every single primitive type. #[cold] #[track_caller] -pub(super) const fn panic_for_negative_argument() -> ! { +pub(in crate::num) const fn panic_for_negative_argument() -> ! { panic!("argument of integer square root cannot be negative") } diff --git a/library/core/src/num/libm.rs b/library/core/src/num/imp/libm.rs similarity index 100% rename from library/core/src/num/libm.rs rename to library/core/src/num/imp/libm.rs diff --git a/library/core/src/num/imp/mod.rs b/library/core/src/num/imp/mod.rs new file mode 100644 index 0000000000000..6fccfd1c238ed --- /dev/null +++ b/library/core/src/num/imp/mod.rs @@ -0,0 +1,21 @@ +//! Numeric routines, separate from API. + +// These modules are public only for testing. +#[cfg(not(no_fp_fmt_parse))] +pub mod bignum; +#[cfg(not(no_fp_fmt_parse))] +pub mod dec2flt; +#[cfg(not(no_fp_fmt_parse))] +pub mod diy_float; +#[cfg(not(no_fp_fmt_parse))] +pub mod flt2dec; +pub mod fmt; + +pub(crate) mod int_bits; +pub(crate) mod int_log10; +pub(crate) mod int_sqrt; +pub(crate) mod libm; +pub(crate) mod overflow_panic; +mod traits; + +pub use traits::{Float, FloatExt, Int}; diff --git a/library/core/src/num/overflow_panic.rs b/library/core/src/num/imp/overflow_panic.rs similarity index 68% rename from library/core/src/num/overflow_panic.rs rename to library/core/src/num/imp/overflow_panic.rs index e30573dd3f392..a9b91daba954b 100644 --- a/library/core/src/num/overflow_panic.rs +++ b/library/core/src/num/imp/overflow_panic.rs @@ -4,48 +4,48 @@ #[cold] #[track_caller] -pub(super) const fn add() -> ! { +pub(in crate::num) const fn add() -> ! { panic!("attempt to add with overflow") } #[cold] #[track_caller] -pub(super) const fn sub() -> ! { +pub(in crate::num) const fn sub() -> ! { panic!("attempt to subtract with overflow") } #[cold] #[track_caller] -pub(super) const fn mul() -> ! { +pub(in crate::num) const fn mul() -> ! { panic!("attempt to multiply with overflow") } #[cold] #[track_caller] -pub(super) const fn div() -> ! { +pub(in crate::num) const fn div() -> ! { panic!("attempt to divide with overflow") } #[cold] #[track_caller] -pub(super) const fn rem() -> ! { +pub(in crate::num) const fn rem() -> ! { panic!("attempt to calculate the remainder with overflow") } #[cold] #[track_caller] -pub(super) const fn neg() -> ! { +pub(in crate::num) const fn neg() -> ! { panic!("attempt to negate with overflow") } #[cold] #[track_caller] -pub(super) const fn shr() -> ! { +pub(in crate::num) const fn shr() -> ! { panic!("attempt to shift right with overflow") } #[cold] #[track_caller] -pub(super) const fn shl() -> ! { +pub(in crate::num) const fn shl() -> ! { panic!("attempt to shift left with overflow") } diff --git a/library/core/src/num/dec2flt/float.rs b/library/core/src/num/imp/traits.rs similarity index 72% rename from library/core/src/num/dec2flt/float.rs rename to library/core/src/num/imp/traits.rs index 21aabdc8addb4..7b84f7a4a5aa2 100644 --- a/library/core/src/num/dec2flt/float.rs +++ b/library/core/src/num/imp/traits.rs @@ -1,10 +1,14 @@ -//! Helper trait for generic float types. +//! Numeric traits used for internal implementations. -use core::f64; +#![doc(hidden)] +#![unstable( + feature = "num_internals", + reason = "internal routines only exposed for testing", + issue = "none" +)] -use crate::fmt::{Debug, LowerExp}; use crate::num::FpCategory; -use crate::ops::{self, Add, Div, Mul, Neg}; +use crate::{f64, fmt, ops}; /// Lossy `as` casting between two types. pub trait CastInto: Copy { @@ -12,11 +16,11 @@ pub trait CastInto: Copy { } /// Collection of traits that allow us to be generic over integer size. -pub trait Integer: +pub trait Int: Sized + Clone + Copy - + Debug + + fmt::Debug + ops::Shr + ops::Shl + ops::BitAnd @@ -37,7 +41,7 @@ macro_rules! int { } } - impl Integer for $ty { + impl Int for $ty { const ZERO: Self = 0; const ONE: Self = 1; } @@ -48,27 +52,22 @@ macro_rules! int { int!(u16, u32, u64); /// A helper trait to avoid duplicating basically all the conversion code for IEEE floats. -/// -/// 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. #[doc(hidden)] -pub trait RawFloat: +pub trait Float: Sized - + Div - + Neg - + Mul - + Add - + LowerExp + + ops::Div + + ops::Neg + + ops::Mul + + ops::Add + + fmt::Debug + PartialEq + PartialOrd + Default + Clone + Copy - + Debug { /// The unsigned integer with the same size as the float - type Int: Integer + Into; + type Int: Int + Into; /* general constants */ @@ -128,8 +127,6 @@ pub trait RawFloat: const MIN_EXPONENT_ROUND_TO_EVEN: i32; const MAX_EXPONENT_ROUND_TO_EVEN: i32; - /* limits related to Fast pathing */ - /// Largest decimal exponent for a non-infinite value. /// /// This is the max exponent in binary converted to the max exponent in decimal. Allows fast @@ -151,41 +148,19 @@ pub trait RawFloat: /// compile time since intermediates exceed the range of an `f64`. const SMALLEST_POWER_OF_TEN: i32; - /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋` - // assuming FLT_EVAL_METHOD = 0 - const MAX_EXPONENT_FAST_PATH: i64 = { - let log2_5 = f64::consts::LOG2_10 - 1.0; - (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64 - }; - - /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋` - const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH; - - /// Maximum exponent that can be represented for a disguised-fast path case. - /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋` - const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = - Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64; - - /// Maximum mantissa for the fast-path (`1 << 53` for f64). - const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS; - - /// Converts integer into float through an as cast. - /// This is only called in the fast-path algorithm, and therefore - /// will not lose precision, since the value will always have - /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH. - fn from_u64(v: u64) -> Self; - - /// Performs a raw transmutation from an integer. - fn from_u64_bits(v: u64) -> Self; - - /// Gets a small power-of-ten for fast-path multiplication. - fn pow10_fast_path(exponent: usize) -> Self; - /// Returns the category that this number falls into. fn classify(self) -> FpCategory; /// Transmute to the integer representation fn to_bits(self) -> Self::Int; +} + +/// Items that ideally would be on `Float`, but don't apply to all float types because they +/// rely on the mantissa fitting into a `u64` (which isn't true for `f128`). +#[doc(hidden)] +pub trait FloatExt: Float { + /// Performs a raw transmutation from an integer. + fn from_u64_bits(v: u64) -> Self; /// Returns the mantissa, exponent and sign as integers. /// @@ -219,7 +194,7 @@ const fn pow2_to_pow10(a: i64) -> i64 { } #[cfg(target_has_reliable_f16)] -impl RawFloat for f16 { +impl Float for f16 { type Int = u16; const INFINITY: Self = Self::INFINITY; @@ -236,23 +211,6 @@ impl RawFloat for f16 { const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 5; const SMALLEST_POWER_OF_TEN: i32 = -27; - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ - } - - #[inline] - fn from_u64_bits(v: u64) -> Self { - Self::from_bits((v & 0xFFFF) as u16) - } - - fn pow10_fast_path(exponent: usize) -> Self { - #[allow(clippy::use_self)] - const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.]; - TABLE[exponent & 7] - } - fn to_bits(self) -> Self::Int { self.to_bits() } @@ -262,7 +220,15 @@ impl RawFloat for f16 { } } -impl RawFloat for f32 { +#[cfg(target_has_reliable_f16)] +impl FloatExt for f16 { + #[inline] + fn from_u64_bits(v: u64) -> Self { + Self::from_bits((v & 0xFFFF) as u16) + } +} + +impl Float for f32 { type Int = u32; const INFINITY: Self = f32::INFINITY; @@ -279,24 +245,6 @@ impl RawFloat for f32 { const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10; const SMALLEST_POWER_OF_TEN: i32 = -65; - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ - } - - #[inline] - fn from_u64_bits(v: u64) -> Self { - f32::from_bits((v & 0xFFFFFFFF) as u32) - } - - fn pow10_fast_path(exponent: usize) -> Self { - #[allow(clippy::use_self)] - const TABLE: [f32; 16] = - [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.]; - TABLE[exponent & 15] - } - fn to_bits(self) -> Self::Int { self.to_bits() } @@ -306,7 +254,14 @@ impl RawFloat for f32 { } } -impl RawFloat for f64 { +impl FloatExt for f32 { + #[inline] + fn from_u64_bits(v: u64) -> Self { + f32::from_bits((v & 0xFFFFFFFF) as u32) + } +} + +impl Float for f64 { type Int = u64; const INFINITY: Self = Self::INFINITY; @@ -323,25 +278,6 @@ impl RawFloat for f64 { const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23; const SMALLEST_POWER_OF_TEN: i32 = -342; - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ - } - - #[inline] - fn from_u64_bits(v: u64) -> Self { - f64::from_bits(v) - } - - fn pow10_fast_path(exponent: usize) -> Self { - const TABLE: [f64; 32] = [ - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, - 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0., - ]; - TABLE[exponent & 31] - } - fn to_bits(self) -> Self::Int { self.to_bits() } @@ -350,3 +286,10 @@ impl RawFloat for f64 { self.classify() } } + +impl FloatExt for f64 { + #[inline] + fn from_u64_bits(v: u64) -> Self { + f64::from_bits(v) + } +} diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index b21865a9ae546..34517818938d2 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -553,7 +553,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); - if b { overflow_panic::add() } else { a } + if b { imp::overflow_panic::add() } else { a } } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow @@ -643,7 +643,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_add_unsigned(self, rhs: $UnsignedT) -> Self { let (a, b) = self.overflowing_add_unsigned(rhs); - if b { overflow_panic::add() } else { a } + if b { imp::overflow_panic::add() } else { a } } /// Checked integer subtraction. Computes `self - rhs`, returning `None` if @@ -693,7 +693,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); - if b { overflow_panic::sub() } else { a } + if b { imp::overflow_panic::sub() } else { a } } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow @@ -783,7 +783,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_sub_unsigned(self, rhs: $UnsignedT) -> Self { let (a, b) = self.overflowing_sub_unsigned(rhs); - if b { overflow_panic::sub() } else { a } + if b { imp::overflow_panic::sub() } else { a } } /// Checked integer multiplication. Computes `self * rhs`, returning `None` if @@ -833,7 +833,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); - if b { overflow_panic::mul() } else { a } + if b { imp::overflow_panic::mul() } else { a } } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow @@ -940,7 +940,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_div(self, rhs: Self) -> Self { let (a, b) = self.overflowing_div(rhs); - if b { overflow_panic::div() } else { a } + if b { imp::overflow_panic::div() } else { a } } /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, @@ -1007,7 +1007,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_div_euclid(self, rhs: Self) -> Self { let (a, b) = self.overflowing_div_euclid(rhs); - if b { overflow_panic::div() } else { a } + if b { imp::overflow_panic::div() } else { a } } /// Checked integer division without remainder. Computes `self / rhs`, @@ -1179,7 +1179,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_rem(self, rhs: Self) -> Self { let (a, b) = self.overflowing_rem(rhs); - if b { overflow_panic::rem() } else { a } + if b { imp::overflow_panic::rem() } else { a } } /// Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` @@ -1245,7 +1245,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_rem_euclid(self, rhs: Self) -> Self { let (a, b) = self.overflowing_rem_euclid(rhs); - if b { overflow_panic::rem() } else { a } + if b { imp::overflow_panic::rem() } else { a } } /// Checked negation. Computes `-self`, returning `None` if `self == MIN`. @@ -1323,7 +1323,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_neg(self) -> Self { let (a, b) = self.overflowing_neg(); - if b { overflow_panic::neg() } else { a } + if b { imp::overflow_panic::neg() } else { a } } /// Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger @@ -1379,7 +1379,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_shl(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shl(rhs); - if b { overflow_panic::shl() } else { a } + if b { imp::overflow_panic::shl() } else { a } } /// Unchecked shift left. Computes `self << rhs`, assuming that @@ -1558,7 +1558,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_shr(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shr(rhs); - if b { overflow_panic::shr() } else { a } + if b { imp::overflow_panic::shr() } else { a } } /// Unchecked shift right. Computes `self >> rhs`, assuming that @@ -1847,7 +1847,7 @@ macro_rules! int_impl { } else { // SAFETY: Input is nonnegative in this `else` branch. let result = unsafe { - crate::num::int_sqrt::$ActualT(self as $ActualT) as $SelfT + imp::int_sqrt::$ActualT(self as $ActualT) as $SelfT }; // Inform the optimizer what the range of outputs is. If @@ -1864,7 +1864,7 @@ macro_rules! int_impl { unsafe { // SAFETY: `<$ActualT>::MAX` is nonnegative. const MAX_RESULT: $SelfT = unsafe { - crate::num::int_sqrt::$ActualT(<$ActualT>::MAX) as $SelfT + imp::int_sqrt::$ActualT(<$ActualT>::MAX) as $SelfT }; crate::hint::assert_unchecked(result >= 0); @@ -3134,7 +3134,7 @@ macro_rules! int_impl { pub const fn isqrt(self) -> Self { match self.checked_isqrt() { Some(sqrt) => sqrt, - None => crate::num::int_sqrt::panic_for_negative_argument(), + None => imp::int_sqrt::panic_for_negative_argument(), } } @@ -3440,7 +3440,7 @@ macro_rules! int_impl { if let Some(log) = self.checked_ilog(base) { log } else { - int_log10::panic_for_nonpositive_argument() + imp::int_log10::panic_for_nonpositive_argument() } } @@ -3465,7 +3465,7 @@ macro_rules! int_impl { if let Some(log) = self.checked_ilog2() { log } else { - int_log10::panic_for_nonpositive_argument() + imp::int_log10::panic_for_nonpositive_argument() } } @@ -3490,7 +3490,7 @@ macro_rules! int_impl { if let Some(log) = self.checked_ilog10() { log } else { - int_log10::panic_for_nonpositive_argument() + imp::int_log10::panic_for_nonpositive_argument() } } @@ -3562,7 +3562,7 @@ macro_rules! int_impl { without modifying the original"] #[inline] pub const fn checked_ilog10(self) -> Option { - int_log10::$ActualT(self as $ActualT) + imp::int_log10::$ActualT(self as $ActualT) } /// Computes the absolute value of `self`. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 558426c94e5dc..0f2397d47d872 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -27,16 +27,14 @@ macro_rules! sign_dependent_expr { }; } -// All these modules are technically private and only exposed for coretests: -#[cfg(not(no_fp_fmt_parse))] -pub mod bignum; -#[cfg(not(no_fp_fmt_parse))] -pub mod dec2flt; -#[cfg(not(no_fp_fmt_parse))] -pub mod diy_float; -#[cfg(not(no_fp_fmt_parse))] -pub mod flt2dec; -pub mod fmt; +// These modules are public only for testing. +#[doc(hidden)] +#[unstable( + feature = "num_internals", + reason = "internal routines only exposed for testing", + issue = "none" +)] +pub mod imp; #[macro_use] mod int_macros; // import int_impl! @@ -44,12 +42,9 @@ mod int_macros; // import int_impl! mod uint_macros; // import uint_impl! mod error; -mod int_bits; -mod int_log10; -mod int_sqrt; -pub(crate) mod libm; +#[cfg(not(no_fp_fmt_parse))] +mod float_parse; mod nonzero; -mod overflow_panic; mod saturating; mod wrapping; @@ -57,15 +52,15 @@ mod wrapping; #[doc(hidden)] pub mod niche_types; -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg(not(no_fp_fmt_parse))] -pub use dec2flt::ParseFloatError; #[stable(feature = "int_error_matching", since = "1.55.0")] pub use error::IntErrorKind; #[stable(feature = "rust1", since = "1.0.0")] pub use error::ParseIntError; #[stable(feature = "try_from", since = "1.34.0")] pub use error::TryFromIntError; +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(no_fp_fmt_parse))] +pub use float_parse::ParseFloatError; #[stable(feature = "generic_nonzero", since = "1.79.0")] pub use nonzero::NonZero; #[unstable( diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 7876fced1c986..de3013e7114c7 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -5,6 +5,7 @@ use crate::clone::{TrivialClone, UseCloned}; use crate::cmp::Ordering; use crate::hash::{Hash, Hasher}; use crate::marker::{Destruct, Freeze, StructuralPartialEq}; +use crate::num::imp; use crate::ops::{BitOr, BitOrAssign, Div, DivAssign, Neg, Rem, RemAssign}; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::str::FromStr; @@ -1817,7 +1818,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { without modifying the original"] #[inline] pub const fn ilog10(self) -> u32 { - super::int_log10::$Int(self) + imp::int_log10::$Int(self) } /// Calculates the midpoint (average) between `self` and `rhs`. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 5c263ea845cc2..29c877fe5e555 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -515,7 +515,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn extract_bits(self, mask: Self) -> Self { - crate::num::int_bits::$ActualT::extract_impl(self as $ActualT, mask as $ActualT) as $SelfT + imp::int_bits::$ActualT::extract_impl(self as $ActualT, mask as $ActualT) as $SelfT } /// Returns an integer with the least significant bits of `self` @@ -532,7 +532,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn deposit_bits(self, mask: Self) -> Self { - crate::num::int_bits::$ActualT::deposit_impl(self as $ActualT, mask as $ActualT) as $SelfT + imp::int_bits::$ActualT::deposit_impl(self as $ActualT, mask as $ActualT) as $SelfT } /// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit, @@ -743,7 +743,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); - if b { overflow_panic::add() } else { a } + if b { imp::overflow_panic::add() } else { a } } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow @@ -838,7 +838,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_add_signed(self, rhs: $SignedT) -> Self { let (a, b) = self.overflowing_add_signed(rhs); - if b { overflow_panic::add() } else { a } + if b { imp::overflow_panic::add() } else { a } } /// Checked integer subtraction. Computes `self - rhs`, returning @@ -897,7 +897,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); - if b { overflow_panic::sub() } else { a } + if b { imp::overflow_panic::sub() } else { a } } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow @@ -1022,7 +1022,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_sub_signed(self, rhs: $SignedT) -> Self { let (a, b) = self.overflowing_sub_signed(rhs); - if b { overflow_panic::sub() } else { a } + if b { imp::overflow_panic::sub() } else { a } } #[doc = concat!( @@ -1131,7 +1131,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); - if b { overflow_panic::mul() } else { a } + if b { imp::overflow_panic::mul() } else { a } } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow @@ -1556,7 +1556,7 @@ macro_rules! uint_impl { if let Some(log) = self.checked_ilog(base) { log } else { - int_log10::panic_for_nonpositive_argument() + imp::int_log10::panic_for_nonpositive_argument() } } @@ -1581,7 +1581,7 @@ macro_rules! uint_impl { if let Some(log) = self.checked_ilog2() { log } else { - int_log10::panic_for_nonpositive_argument() + imp::int_log10::panic_for_nonpositive_argument() } } @@ -1606,7 +1606,7 @@ macro_rules! uint_impl { if let Some(log) = self.checked_ilog10() { log } else { - int_log10::panic_for_nonpositive_argument() + imp::int_log10::panic_for_nonpositive_argument() } } @@ -1768,7 +1768,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_neg(self) -> Self { let (a, b) = self.overflowing_neg(); - if b { overflow_panic::neg() } else { a } + if b { imp::overflow_panic::neg() } else { a } } /// Checked shift left. Computes `self << rhs`, returning `None` @@ -1824,7 +1824,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_shl(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shl(rhs); - if b { overflow_panic::shl() } else { a } + if b { imp::overflow_panic::shl() } else { a } } /// Unchecked shift left. Computes `self << rhs`, assuming that @@ -2009,7 +2009,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_shr(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shr(rhs); - if b { overflow_panic::shr() } else { a } + if b { imp::overflow_panic::shr() } else { a } } /// Unchecked shift right. Computes `self >> rhs`, assuming that @@ -3481,7 +3481,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn isqrt(self) -> Self { - let result = crate::num::int_sqrt::$ActualT(self as $ActualT) as $SelfT; + let result = imp::int_sqrt::$ActualT(self as $ActualT) as $SelfT; // Inform the optimizer what the range of outputs is. If testing // `core` crashes with no panic message and a `num::int_sqrt::u*` @@ -3494,7 +3494,7 @@ macro_rules! uint_impl { // integers is bounded by `[0, <$ActualT>::MAX]`, sqrt(n) will be // bounded by `[sqrt(0), sqrt(<$ActualT>::MAX)]`. unsafe { - const MAX_RESULT: $SelfT = crate::num::int_sqrt::$ActualT(<$ActualT>::MAX) as $SelfT; + const MAX_RESULT: $SelfT = imp::int_sqrt::$ActualT(<$ActualT>::MAX) as $SelfT; crate::hint::assert_unchecked(result <= MAX_RESULT); } diff --git a/library/coretests/benches/num/flt2dec/mod.rs b/library/coretests/benches/num/flt2dec/mod.rs index 428d0bbbbfbfa..0cd94ec5e1cfe 100644 --- a/library/coretests/benches/num/flt2dec/mod.rs +++ b/library/coretests/benches/num/flt2dec/mod.rs @@ -3,7 +3,7 @@ mod strategy { mod grisu; } -use core::num::flt2dec::{DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, decode}; +use core::num::imp::flt2dec::{DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, decode}; use std::io::Write; use test::{Bencher, black_box}; diff --git a/library/coretests/benches/num/flt2dec/strategy/dragon.rs b/library/coretests/benches/num/flt2dec/strategy/dragon.rs index 4526697140365..d98b3df9b2f35 100644 --- a/library/coretests/benches/num/flt2dec/strategy/dragon.rs +++ b/library/coretests/benches/num/flt2dec/strategy/dragon.rs @@ -1,4 +1,4 @@ -use core::num::flt2dec::strategy::dragon::*; +use core::num::imp::flt2dec::strategy::dragon::*; use std::mem::MaybeUninit; use super::super::*; diff --git a/library/coretests/benches/num/flt2dec/strategy/grisu.rs b/library/coretests/benches/num/flt2dec/strategy/grisu.rs index d20f9b02f7e74..5f73fdebf5e77 100644 --- a/library/coretests/benches/num/flt2dec/strategy/grisu.rs +++ b/library/coretests/benches/num/flt2dec/strategy/grisu.rs @@ -1,4 +1,4 @@ -use core::num::flt2dec::strategy::grisu::*; +use core::num::imp::flt2dec::strategy::grisu::*; use std::mem::MaybeUninit; use super::super::*; diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 5923328655524..a75ad12b6f294 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -92,6 +92,7 @@ #![feature(next_index)] #![feature(non_exhaustive_omitted_patterns_lint)] #![feature(nonzero_from_str_radix)] +#![feature(num_internals)] #![feature(numfmt)] #![feature(one_sided_range)] #![feature(option_reduce)] diff --git a/library/coretests/tests/num/bignum.rs b/library/coretests/tests/num/bignum.rs index 6dfa496e018bf..2b4c30cc261cb 100644 --- a/library/coretests/tests/num/bignum.rs +++ b/library/coretests/tests/num/bignum.rs @@ -1,5 +1,5 @@ -use core::num::bignum::Big32x40; -use core::num::bignum::tests::Big8x3 as Big; +use core::num::imp::bignum::Big32x40; +use core::num::imp::bignum::tests::Big8x3 as Big; #[test] #[should_panic] diff --git a/library/coretests/tests/num/dec2flt/decimal.rs b/library/coretests/tests/num/dec2flt/decimal.rs index f5ecc604a99a1..8611310850be7 100644 --- a/library/coretests/tests/num/dec2flt/decimal.rs +++ b/library/coretests/tests/num/dec2flt/decimal.rs @@ -1,4 +1,4 @@ -use core::num::dec2flt::decimal::Decimal; +use core::num::imp::dec2flt::decimal::Decimal; type FPath = ((i64, u64, bool, bool), Option); diff --git a/library/coretests/tests/num/dec2flt/decimal_seq.rs b/library/coretests/tests/num/dec2flt/decimal_seq.rs index f46ba7c465a6e..f2fee3a0d8e85 100644 --- a/library/coretests/tests/num/dec2flt/decimal_seq.rs +++ b/library/coretests/tests/num/dec2flt/decimal_seq.rs @@ -1,4 +1,4 @@ -use core::num::dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq}; +use core::num::imp::dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq}; #[test] fn test_trim() { diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs index 734cb7e4f7dbd..0713c5c651fb3 100644 --- a/library/coretests/tests/num/dec2flt/float.rs +++ b/library/coretests/tests/num/dec2flt/float.rs @@ -1,4 +1,5 @@ -use core::num::dec2flt::float::RawFloat; +use core::num::imp::dec2flt::Lemire; +use core::num::imp::{Float, FloatExt}; use crate::num::{ldexp_f32, ldexp_f64}; @@ -56,57 +57,60 @@ fn test_f64_integer_decode() { #[test] #[cfg(target_has_reliable_f16)] fn test_f16_consts() { - assert_eq!(::INFINITY, f16::INFINITY); - assert_eq!(::NEG_INFINITY, -f16::INFINITY); - assert_eq!(::NAN.to_bits(), f16::NAN.to_bits()); - assert_eq!(::NEG_NAN.to_bits(), (-f16::NAN).to_bits()); - assert_eq!(::SIG_BITS, 10); - assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -22); - assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 5); - assert_eq!(::MIN_EXPONENT_FAST_PATH, -4); - assert_eq!(::MAX_EXPONENT_FAST_PATH, 4); - assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 7); - assert_eq!(::EXP_MIN, -14); - assert_eq!(::EXP_SAT, 0x1f); - assert_eq!(::SMALLEST_POWER_OF_TEN, -27); - assert_eq!(::LARGEST_POWER_OF_TEN, 4); - assert_eq!(::MAX_MANTISSA_FAST_PATH, 2048); + assert_eq!(::INFINITY, f16::INFINITY); + assert_eq!(::NEG_INFINITY, -f16::INFINITY); + assert_eq!(::NAN.to_bits(), f16::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f16::NAN).to_bits()); + assert_eq!(::SIG_BITS, 10); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -22); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 5); + assert_eq!(::EXP_MIN, -14); + assert_eq!(::EXP_SAT, 0x1f); + assert_eq!(::SMALLEST_POWER_OF_TEN, -27); + assert_eq!(::LARGEST_POWER_OF_TEN, 4); + + assert_eq!(::MIN_EXPONENT_FAST_PATH, -4); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 4); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 7); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 2048); } #[test] fn test_f32_consts() { - assert_eq!(::INFINITY, f32::INFINITY); - assert_eq!(::NEG_INFINITY, -f32::INFINITY); - assert_eq!(::NAN.to_bits(), f32::NAN.to_bits()); - assert_eq!(::NEG_NAN.to_bits(), (-f32::NAN).to_bits()); - assert_eq!(::SIG_BITS, 23); - assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -17); - assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 10); - assert_eq!(::MIN_EXPONENT_FAST_PATH, -10); - assert_eq!(::MAX_EXPONENT_FAST_PATH, 10); - assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 17); - assert_eq!(::EXP_MIN, -126); - assert_eq!(::EXP_SAT, 0xff); - assert_eq!(::SMALLEST_POWER_OF_TEN, -65); - assert_eq!(::LARGEST_POWER_OF_TEN, 38); - assert_eq!(::MAX_MANTISSA_FAST_PATH, 16777216); + assert_eq!(::INFINITY, f32::INFINITY); + assert_eq!(::NEG_INFINITY, -f32::INFINITY); + assert_eq!(::NAN.to_bits(), f32::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f32::NAN).to_bits()); + assert_eq!(::SIG_BITS, 23); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -17); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 10); + assert_eq!(::EXP_MIN, -126); + assert_eq!(::EXP_SAT, 0xff); + assert_eq!(::SMALLEST_POWER_OF_TEN, -65); + assert_eq!(::LARGEST_POWER_OF_TEN, 38); + + assert_eq!(::MIN_EXPONENT_FAST_PATH, -10); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 10); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 17); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 16777216); } #[test] fn test_f64_consts() { - assert_eq!(::INFINITY, f64::INFINITY); - assert_eq!(::NEG_INFINITY, -f64::INFINITY); - assert_eq!(::NAN.to_bits(), f64::NAN.to_bits()); - assert_eq!(::NEG_NAN.to_bits(), (-f64::NAN).to_bits()); - assert_eq!(::SIG_BITS, 52); - assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -4); - assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 23); - assert_eq!(::MIN_EXPONENT_FAST_PATH, -22); - assert_eq!(::MAX_EXPONENT_FAST_PATH, 22); - assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 37); - assert_eq!(::EXP_MIN, -1022); - assert_eq!(::EXP_SAT, 0x7ff); - assert_eq!(::SMALLEST_POWER_OF_TEN, -342); - assert_eq!(::LARGEST_POWER_OF_TEN, 308); - assert_eq!(::MAX_MANTISSA_FAST_PATH, 9007199254740992); + assert_eq!(::INFINITY, f64::INFINITY); + assert_eq!(::NEG_INFINITY, -f64::INFINITY); + assert_eq!(::NAN.to_bits(), f64::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f64::NAN).to_bits()); + assert_eq!(::SIG_BITS, 52); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -4); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 23); + assert_eq!(::EXP_MIN, -1022); + assert_eq!(::EXP_SAT, 0x7ff); + assert_eq!(::SMALLEST_POWER_OF_TEN, -342); + assert_eq!(::LARGEST_POWER_OF_TEN, 308); + + assert_eq!(::MIN_EXPONENT_FAST_PATH, -22); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 22); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 37); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 9007199254740992); } diff --git a/library/coretests/tests/num/dec2flt/lemire.rs b/library/coretests/tests/num/dec2flt/lemire.rs index ba359a0495fef..e5a7ae346f425 100644 --- a/library/coretests/tests/num/dec2flt/lemire.rs +++ b/library/coretests/tests/num/dec2flt/lemire.rs @@ -1,5 +1,6 @@ -use core::num::dec2flt::float::RawFloat; -use core::num::dec2flt::lemire::compute_float; +use core::num::imp::{Float, dec2flt}; + +use dec2flt::lemire::compute_float; #[cfg(target_has_reliable_f16)] fn compute_float16(q: i64, w: u64) -> (i32, u64) { diff --git a/library/coretests/tests/num/dec2flt/parse.rs b/library/coretests/tests/num/dec2flt/parse.rs index 65f1289d531b3..a63cdb3873762 100644 --- a/library/coretests/tests/num/dec2flt/parse.rs +++ b/library/coretests/tests/num/dec2flt/parse.rs @@ -1,6 +1,8 @@ -use core::num::dec2flt::decimal::Decimal; -use core::num::dec2flt::parse::parse_number; -use core::num::dec2flt::{dec2flt, pfe_invalid}; +use core::num::imp::dec2flt; + +use dec2flt::decimal::Decimal; +use dec2flt::parse::parse_number; +use dec2flt::{dec2flt, pfe_invalid}; fn new_dec(e: i64, m: u64) -> Decimal { Decimal { exponent: e, mantissa: m, negative: false, many_digits: false } diff --git a/library/coretests/tests/num/flt2dec/estimator.rs b/library/coretests/tests/num/flt2dec/estimator.rs index f53282611f686..1e24048fa515a 100644 --- a/library/coretests/tests/num/flt2dec/estimator.rs +++ b/library/coretests/tests/num/flt2dec/estimator.rs @@ -1,4 +1,4 @@ -use core::num::flt2dec::estimator::*; +use core::num::imp::flt2dec::estimator::*; use crate::num::ldexp_f64; diff --git a/library/coretests/tests/num/flt2dec/mod.rs b/library/coretests/tests/num/flt2dec/mod.rs index be1bc6ac460ba..4888d9d1de06a 100644 --- a/library/coretests/tests/num/flt2dec/mod.rs +++ b/library/coretests/tests/num/flt2dec/mod.rs @@ -1,11 +1,13 @@ -use core::num::flt2dec::{ +use core::num::imp::flt2dec::{ DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, Sign, decode, round_up, to_exact_exp_str, to_exact_fixed_str, to_shortest_exp_str, to_shortest_str, }; -use core::num::fmt::{Formatted, Part}; +use core::num::imp::fmt::{Formatted, Part}; use std::mem::MaybeUninit; use std::{fmt, str}; +use Sign::{Minus, MinusPlus}; + use crate::num::{ldexp_f32, ldexp_f64}; mod estimator; @@ -562,8 +564,6 @@ pub fn to_shortest_str_test(mut f_: F) where F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { - use core::num::flt2dec::Sign::*; - fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String where T: DecodableFloat, @@ -672,8 +672,6 @@ pub fn to_shortest_exp_str_test(mut f_: F) where F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { - use core::num::flt2dec::Sign::*; - fn to_string(f: &mut F, v: T, sign: Sign, exp_bounds: (i16, i16), upper: bool) -> String where T: DecodableFloat, @@ -789,8 +787,6 @@ pub fn to_exact_exp_str_test(mut f_: F) where F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { - use core::num::flt2dec::Sign::*; - fn to_string(f: &mut F, v: T, sign: Sign, ndigits: usize, upper: bool) -> String where T: DecodableFloat, @@ -1065,8 +1061,6 @@ pub fn to_exact_fixed_str_test(mut f_: F) where F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { - use core::num::flt2dec::Sign::*; - fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String where T: DecodableFloat, diff --git a/library/coretests/tests/num/flt2dec/random.rs b/library/coretests/tests/num/flt2dec/random.rs index 7386139aaced5..e47aa6d37a804 100644 --- a/library/coretests/tests/num/flt2dec/random.rs +++ b/library/coretests/tests/num/flt2dec/random.rs @@ -1,10 +1,11 @@ #![cfg(not(target_arch = "wasm32"))] -use core::num::flt2dec::strategy::grisu::{format_exact_opt, format_shortest_opt}; -use core::num::flt2dec::{DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, decode}; +use core::num::imp::flt2dec; use std::mem::MaybeUninit; use std::str; +use flt2dec::strategy::grisu::{format_exact_opt, format_shortest_opt}; +use flt2dec::{DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, decode}; use rand::distr::{Distribution, Uniform}; pub fn decode_finite(v: T) -> Decoded { @@ -159,7 +160,7 @@ where #[test] fn shortest_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + use flt2dec::strategy::dragon::format_shortest as fallback; // Miri is too slow let n = if cfg!(miri) { 10 } else { 10_000 }; @@ -174,7 +175,7 @@ fn shortest_random_equivalence_test() { #[cfg(target_has_reliable_f16)] fn shortest_f16_exhaustive_equivalence_test() { // see the f32 version - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + use flt2dec::strategy::dragon::format_shortest as fallback; f16_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); } @@ -188,7 +189,7 @@ fn shortest_f32_exhaustive_equivalence_test() { // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print: // `done, ignored=17643158 passed=2121451881 failed=0`. - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + use flt2dec::strategy::dragon::format_shortest as fallback; f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); } @@ -197,14 +198,14 @@ fn shortest_f32_exhaustive_equivalence_test() { fn shortest_f64_hard_random_equivalence_test() { // this again probably has to use appropriate rustc flags. - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + use flt2dec::strategy::dragon::format_shortest as fallback; f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 100_000_000); } #[test] #[cfg(target_has_reliable_f16)] fn exact_f16_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_exact as fallback; + use flt2dec::strategy::dragon::format_exact as fallback; // Miri is too slow let n = if cfg!(miri) { 3 } else { 1_000 }; @@ -220,7 +221,7 @@ fn exact_f16_random_equivalence_test() { #[test] fn exact_f32_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_exact as fallback; + use flt2dec::strategy::dragon::format_exact as fallback; // Miri is too slow let n = if cfg!(miri) { 3 } else { 1_000 }; @@ -236,7 +237,7 @@ fn exact_f32_random_equivalence_test() { #[test] fn exact_f64_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_exact as fallback; + use flt2dec::strategy::dragon::format_exact as fallback; // Miri is too slow let n = if cfg!(miri) { 2 } else { 1_000 }; diff --git a/library/coretests/tests/num/flt2dec/strategy/dragon.rs b/library/coretests/tests/num/flt2dec/strategy/dragon.rs index 43bb6024f9cee..886f50064a503 100644 --- a/library/coretests/tests/num/flt2dec/strategy/dragon.rs +++ b/library/coretests/tests/num/flt2dec/strategy/dragon.rs @@ -1,5 +1,5 @@ -use core::num::bignum::Big32x40 as Big; -use core::num::flt2dec::strategy::dragon::*; +use core::num::imp::bignum::Big32x40 as Big; +use core::num::imp::flt2dec::strategy::dragon::*; use super::super::*; diff --git a/library/coretests/tests/num/flt2dec/strategy/grisu.rs b/library/coretests/tests/num/flt2dec/strategy/grisu.rs index 117191e0c8fdb..8350480333380 100644 --- a/library/coretests/tests/num/flt2dec/strategy/grisu.rs +++ b/library/coretests/tests/num/flt2dec/strategy/grisu.rs @@ -1,4 +1,4 @@ -use core::num::flt2dec::strategy::grisu::*; +use core::num::imp::flt2dec::strategy::grisu::*; use super::super::*; diff --git a/tests/codegen-llvm/overflow-checks.rs b/tests/codegen-llvm/overflow-checks.rs index 3a48e6b76243b..a9d5b2d2ec074 100644 --- a/tests/codegen-llvm/overflow-checks.rs +++ b/tests/codegen-llvm/overflow-checks.rs @@ -21,7 +21,7 @@ pub unsafe fn add(a: u8, b: u8) -> u8 { // CHECK: i8 noundef{{( zeroext)?}} %a, i8 noundef{{( zeroext)?}} %b // CHECK: add i8 %b, %a // DEBUG: icmp ult i8 [[zero:[^,]+]], %a - // DEBUG: call core::num::overflow_panic::add + // DEBUG: call core::num::imp::overflow_panic::add // DEBUG: unreachable // NOCHECKS-NOT: unreachable // NOCHECKS: ret i8 %0 diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff index 88c77832a4e18..95b170750ce81 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff @@ -11,18 +11,18 @@ let mut _7: isize; let mut _9: &mut std::fmt::Formatter<'_>; let mut _10: &T; - let mut _11: core::num::flt2dec::Sign; + let mut _11: core::num::imp::flt2dec::Sign; let mut _12: u32; let mut _13: u32; let mut _14: usize; let mut _15: bool; let mut _16: &mut std::fmt::Formatter<'_>; let mut _17: &T; - let mut _18: core::num::flt2dec::Sign; + let mut _18: core::num::imp::flt2dec::Sign; let mut _19: bool; scope 1 { debug force_sign => _4; - let _5: core::num::flt2dec::Sign; + let _5: core::num::imp::flt2dec::Sign; scope 2 { debug sign => _5; scope 3 { @@ -56,14 +56,14 @@ } bb1: { -- _5 = core::num::flt2dec::Sign::MinusPlus; -+ _5 = const core::num::flt2dec::Sign::MinusPlus; +- _5 = core::num::imp::flt2dec::Sign::MinusPlus; ++ _5 = const core::num::imp::flt2dec::Sign::MinusPlus; goto -> bb3; } bb2: { -- _5 = core::num::flt2dec::Sign::Minus; -+ _5 = const core::num::flt2dec::Sign::Minus; +- _5 = core::num::imp::flt2dec::Sign::Minus; ++ _5 = const core::num::imp::flt2dec::Sign::Minus; goto -> bb3; } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff index 8a6e7fd35ccd2..42fb16d022916 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff @@ -11,18 +11,18 @@ let mut _7: isize; let mut _9: &mut std::fmt::Formatter<'_>; let mut _10: &T; - let mut _11: core::num::flt2dec::Sign; + let mut _11: core::num::imp::flt2dec::Sign; let mut _12: u32; let mut _13: u32; let mut _14: usize; let mut _15: bool; let mut _16: &mut std::fmt::Formatter<'_>; let mut _17: &T; - let mut _18: core::num::flt2dec::Sign; + let mut _18: core::num::imp::flt2dec::Sign; let mut _19: bool; scope 1 { debug force_sign => _4; - let _5: core::num::flt2dec::Sign; + let _5: core::num::imp::flt2dec::Sign; scope 2 { debug sign => _5; scope 3 { @@ -56,14 +56,14 @@ } bb1: { -- _5 = core::num::flt2dec::Sign::MinusPlus; -+ _5 = const core::num::flt2dec::Sign::MinusPlus; +- _5 = core::num::imp::flt2dec::Sign::MinusPlus; ++ _5 = const core::num::imp::flt2dec::Sign::MinusPlus; goto -> bb3; } bb2: { -- _5 = core::num::flt2dec::Sign::Minus; -+ _5 = const core::num::flt2dec::Sign::Minus; +- _5 = core::num::imp::flt2dec::Sign::Minus; ++ _5 = const core::num::imp::flt2dec::Sign::Minus; goto -> bb3; } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff index ce10f4bb247a8..55cc28bafc9fe 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff @@ -11,18 +11,18 @@ let mut _7: isize; let mut _9: &mut std::fmt::Formatter<'_>; let mut _10: &T; - let mut _11: core::num::flt2dec::Sign; + let mut _11: core::num::imp::flt2dec::Sign; let mut _12: u32; let mut _13: u32; let mut _14: usize; let mut _15: bool; let mut _16: &mut std::fmt::Formatter<'_>; let mut _17: &T; - let mut _18: core::num::flt2dec::Sign; + let mut _18: core::num::imp::flt2dec::Sign; let mut _19: bool; scope 1 { debug force_sign => _4; - let _5: core::num::flt2dec::Sign; + let _5: core::num::imp::flt2dec::Sign; scope 2 { debug sign => _5; scope 3 { @@ -56,14 +56,14 @@ } bb1: { -- _5 = core::num::flt2dec::Sign::MinusPlus; -+ _5 = const core::num::flt2dec::Sign::MinusPlus; +- _5 = core::num::imp::flt2dec::Sign::MinusPlus; ++ _5 = const core::num::imp::flt2dec::Sign::MinusPlus; goto -> bb3; } bb2: { -- _5 = core::num::flt2dec::Sign::Minus; -+ _5 = const core::num::flt2dec::Sign::Minus; +- _5 = core::num::imp::flt2dec::Sign::Minus; ++ _5 = const core::num::imp::flt2dec::Sign::Minus; goto -> bb3; } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff index b19f2438d0225..c93c6b5a27795 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff @@ -11,18 +11,18 @@ let mut _7: isize; let mut _9: &mut std::fmt::Formatter<'_>; let mut _10: &T; - let mut _11: core::num::flt2dec::Sign; + let mut _11: core::num::imp::flt2dec::Sign; let mut _12: u32; let mut _13: u32; let mut _14: usize; let mut _15: bool; let mut _16: &mut std::fmt::Formatter<'_>; let mut _17: &T; - let mut _18: core::num::flt2dec::Sign; + let mut _18: core::num::imp::flt2dec::Sign; let mut _19: bool; scope 1 { debug force_sign => _4; - let _5: core::num::flt2dec::Sign; + let _5: core::num::imp::flt2dec::Sign; scope 2 { debug sign => _5; scope 3 { @@ -56,14 +56,14 @@ } bb1: { -- _5 = core::num::flt2dec::Sign::MinusPlus; -+ _5 = const core::num::flt2dec::Sign::MinusPlus; +- _5 = core::num::imp::flt2dec::Sign::MinusPlus; ++ _5 = const core::num::imp::flt2dec::Sign::MinusPlus; goto -> bb3; } bb2: { -- _5 = core::num::flt2dec::Sign::Minus; -+ _5 = const core::num::flt2dec::Sign::Minus; +- _5 = core::num::imp::flt2dec::Sign::Minus; ++ _5 = const core::num::imp::flt2dec::Sign::Minus; goto -> bb3; } diff --git a/tests/mir-opt/funky_arms.rs b/tests/mir-opt/funky_arms.rs index 403a22ebed320..8018f26997e46 100644 --- a/tests/mir-opt/funky_arms.rs +++ b/tests/mir-opt/funky_arms.rs @@ -3,10 +3,11 @@ // EMIT_MIR_FOR_EACH_BIT_WIDTH #![feature(flt2dec)] +#![feature(num_internals)] extern crate core; -use core::num::flt2dec; +use core::num::imp::flt2dec; use std::fmt::{Formatter, Result}; // EMIT_MIR funky_arms.float_to_exponential_common.GVN.diff diff --git a/triagebot.toml b/triagebot.toml index 2a98b1d43b99e..95ca37f4bc922 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1076,7 +1076,7 @@ gets adapted for the changes, if necessary. """ cc = ["@rust-lang/miri", "@RalfJung", "@oli-obk", "@lcnr"] -[mentions."library/core/src/num/{dec2flt,flt2dec}"] +[mentions."library/core/src/num/imp/{dec2flt,flt2dec}"] message = "Some changes occurred in float parsing" cc = ["@tgross35"]