mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #151905 - tgross35:dec2flt-traits, r=Mark-Simulacrum
Split the `dec2flt::RawFloat` trait for easier reuse `RawFloat` is an internal trait with quite a few useful float properties. It currently resides in the `dec2flt` module but is also used in parsing, and would be nice to reuse other places. Unfortunately it cannot be implemented on `f128` because of limitations with how the parsing API is implemented (mantissa must fit into a u64). To make the trait easier to work with, split it into the following: * `Float`: Anything that is reasonably applicable to all floating point types. * `FloatExt`: Items that should be part of `Float` but don't work for all float types. This will eventually be merged back into `Float` once it can be implemented on f128. * `Lemire`: Items that are specific to the Lemire dec2flt algorithm. These traits are then moved to places that make sense. Builds on top of https://github.com/rust-lang/rust/pull/151900
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
//! Representation of a float as the significant digits and exponent.
|
||||
|
||||
use dec2flt::float::RawFloat;
|
||||
use dec2flt::Lemire;
|
||||
use dec2flt::fpu::set_precision;
|
||||
|
||||
use crate::num::imp::dec2flt;
|
||||
@@ -36,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<F: RawFloat>(&self) -> bool {
|
||||
fn can_use_fast_path<F: Lemire>(&self) -> bool {
|
||||
F::MIN_EXPONENT_FAST_PATH <= self.exponent
|
||||
&& self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH
|
||||
&& self.mantissa <= F::MAX_MANTISSA_FAST_PATH
|
||||
@@ -53,7 +53,7 @@ fn can_use_fast_path<F: RawFloat>(&self) -> bool {
|
||||
///
|
||||
/// 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<F: RawFloat>(&self) -> Option<F> {
|
||||
pub fn try_fast_path<F: Lemire>(&self) -> Option<F> {
|
||||
// Here we need to work around <https://github.com/rust-lang/rust/issues/114479>.
|
||||
// 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
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
//! Implementation of the Eisel-Lemire algorithm.
|
||||
|
||||
use dec2flt::common::BiasedFp;
|
||||
use dec2flt::float::RawFloat;
|
||||
use dec2flt::table::{LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE};
|
||||
|
||||
use crate::num::imp::dec2flt;
|
||||
use crate::num::imp::{Float, dec2flt};
|
||||
|
||||
/// Compute w * 10^q using an extended-precision float representation.
|
||||
///
|
||||
@@ -24,7 +23,7 @@
|
||||
/// at a Gigabyte per Second" in section 5, "Fast Algorithm", and
|
||||
/// section 6, "Exact Numbers And Ties", available online:
|
||||
/// <https://arxiv.org/abs/2101.11408.pdf>.
|
||||
pub fn compute_float<F: RawFloat>(q: i64, mut w: u64) -> BiasedFp {
|
||||
pub fn compute_float<F: 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);
|
||||
|
||||
@@ -88,24 +88,104 @@
|
||||
)]
|
||||
|
||||
use common::BiasedFp;
|
||||
use float::RawFloat;
|
||||
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;
|
||||
|
||||
/// 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
|
||||
};
|
||||
|
||||
/// 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;
|
||||
|
||||
/// 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(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_u64(v: u64) -> Self {
|
||||
debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
|
||||
v as _
|
||||
}
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_u64(v: u64) -> Self {
|
||||
debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
|
||||
v as _
|
||||
}
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_u64(v: u64) -> Self {
|
||||
debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
|
||||
v as _
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn pfe_empty() -> ParseFloatError {
|
||||
@@ -120,7 +200,7 @@ pub fn pfe_invalid() -> ParseFloatError {
|
||||
}
|
||||
|
||||
/// Converts a `BiasedFp` to the closest machine float type.
|
||||
fn biased_fp_to_float<F: RawFloat>(x: BiasedFp) -> F {
|
||||
fn biased_fp_to_float<F: FloatExt>(x: BiasedFp) -> F {
|
||||
let mut word = x.m;
|
||||
word |= (x.p_biased as u64) << F::SIG_BITS;
|
||||
F::from_u64_bits(word)
|
||||
@@ -128,7 +208,7 @@ fn biased_fp_to_float<F: RawFloat>(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<F: RawFloat>(s: &str) -> Result<F, ParseFloatError> {
|
||||
pub fn dec2flt<F: Lemire>(s: &str) -> Result<F, ParseFloatError> {
|
||||
let mut s = s.as_bytes();
|
||||
let Some(&c) = s.first() else { return Err(pfe_empty()) };
|
||||
let negative = c == b'-';
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
use dec2flt::common::{ByteSlice, is_8digits};
|
||||
use dec2flt::decimal::Decimal;
|
||||
use dec2flt::float::RawFloat;
|
||||
|
||||
use crate::num::imp::dec2flt;
|
||||
use crate::num::imp::{Float, dec2flt};
|
||||
|
||||
const MIN_19DIGIT_INT: u64 = 100_0000_0000_0000_0000;
|
||||
|
||||
@@ -197,7 +196,7 @@ pub fn parse_number(s: &[u8]) -> Option<Decimal> {
|
||||
}
|
||||
|
||||
/// Try to parse a special, non-finite float.
|
||||
pub(crate) fn parse_inf_nan<F: RawFloat>(s: &[u8], negative: bool) -> Option<F> {
|
||||
pub(crate) fn parse_inf_nan<F: Float>(s: &[u8], negative: bool) -> Option<F> {
|
||||
// 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.
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
use dec2flt::common::BiasedFp;
|
||||
use dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq};
|
||||
use dec2flt::float::RawFloat;
|
||||
|
||||
use crate::num::imp::dec2flt;
|
||||
use crate::num::imp::{Float, dec2flt};
|
||||
|
||||
/// Parse the significant digits and biased, binary exponent of a float.
|
||||
///
|
||||
@@ -25,7 +24,7 @@
|
||||
///
|
||||
/// The algorithms described here are based on "Processing Long Numbers Quickly",
|
||||
/// available here: <https://arxiv.org/pdf/2101.11408.pdf#section.11>.
|
||||
pub(crate) fn parse_long_mantissa<F: RawFloat>(s: &[u8]) -> BiasedFp {
|
||||
pub(crate) fn parse_long_mantissa<F: Float>(s: &[u8]) -> BiasedFp {
|
||||
const MAX_SHIFT: usize = 60;
|
||||
const NUM_POWERS: usize = 19;
|
||||
const POWERS: [u8; 19] =
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Decodes a floating-point value into individual parts and error ranges.
|
||||
|
||||
use crate::num::FpCategory;
|
||||
use crate::num::imp::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;
|
||||
}
|
||||
|
||||
@@ -16,3 +16,6 @@
|
||||
pub(crate) mod int_sqrt;
|
||||
pub(crate) mod libm;
|
||||
pub(crate) mod overflow_panic;
|
||||
mod traits;
|
||||
|
||||
pub use traits::{Float, FloatExt, Int};
|
||||
|
||||
@@ -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<T: Copy>: Copy {
|
||||
@@ -12,11 +16,11 @@ pub trait CastInto<T: Copy>: 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<u32, Output = Self>
|
||||
+ ops::Shl<u32, Output = Self>
|
||||
+ ops::BitAnd<Output = Self>
|
||||
@@ -37,7 +41,7 @@ fn cast(self) -> i16 {
|
||||
}
|
||||
}
|
||||
|
||||
impl Integer for $ty {
|
||||
impl Int for $ty {
|
||||
const ZERO: Self = 0;
|
||||
const ONE: Self = 1;
|
||||
}
|
||||
@@ -48,27 +52,22 @@ impl Integer for $ty {
|
||||
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<Output = Self>
|
||||
+ Neg<Output = Self>
|
||||
+ Mul<Output = Self>
|
||||
+ Add<Output = Self>
|
||||
+ LowerExp
|
||||
+ ops::Div<Output = Self>
|
||||
+ ops::Neg<Output = Self>
|
||||
+ ops::Mul<Output = Self>
|
||||
+ ops::Add<Output = Self>
|
||||
+ fmt::Debug
|
||||
+ PartialEq
|
||||
+ PartialOrd
|
||||
+ Default
|
||||
+ Clone
|
||||
+ Copy
|
||||
+ Debug
|
||||
{
|
||||
/// The unsigned integer with the same size as the float
|
||||
type Int: Integer + Into<u64>;
|
||||
type Int: Int + Into<u64>;
|
||||
|
||||
/* 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 @@ fn classify(self) -> FpCategory {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn classify(self) -> FpCategory {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn classify(self) -> FpCategory {
|
||||
self.classify()
|
||||
}
|
||||
}
|
||||
|
||||
impl FloatExt for f64 {
|
||||
#[inline]
|
||||
fn from_u64_bits(v: u64) -> Self {
|
||||
f64::from_bits(v)
|
||||
}
|
||||
}
|
||||
@@ -88,6 +88,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(panic_internals)]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use core::num::imp::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!(<f16 as RawFloat>::INFINITY, f16::INFINITY);
|
||||
assert_eq!(<f16 as RawFloat>::NEG_INFINITY, -f16::INFINITY);
|
||||
assert_eq!(<f16 as RawFloat>::NAN.to_bits(), f16::NAN.to_bits());
|
||||
assert_eq!(<f16 as RawFloat>::NEG_NAN.to_bits(), (-f16::NAN).to_bits());
|
||||
assert_eq!(<f16 as RawFloat>::SIG_BITS, 10);
|
||||
assert_eq!(<f16 as RawFloat>::MIN_EXPONENT_ROUND_TO_EVEN, -22);
|
||||
assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_ROUND_TO_EVEN, 5);
|
||||
assert_eq!(<f16 as RawFloat>::MIN_EXPONENT_FAST_PATH, -4);
|
||||
assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_FAST_PATH, 4);
|
||||
assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_DISGUISED_FAST_PATH, 7);
|
||||
assert_eq!(<f16 as RawFloat>::EXP_MIN, -14);
|
||||
assert_eq!(<f16 as RawFloat>::EXP_SAT, 0x1f);
|
||||
assert_eq!(<f16 as RawFloat>::SMALLEST_POWER_OF_TEN, -27);
|
||||
assert_eq!(<f16 as RawFloat>::LARGEST_POWER_OF_TEN, 4);
|
||||
assert_eq!(<f16 as RawFloat>::MAX_MANTISSA_FAST_PATH, 2048);
|
||||
assert_eq!(<f16 as Float>::INFINITY, f16::INFINITY);
|
||||
assert_eq!(<f16 as Float>::NEG_INFINITY, -f16::INFINITY);
|
||||
assert_eq!(<f16 as Float>::NAN.to_bits(), f16::NAN.to_bits());
|
||||
assert_eq!(<f16 as Float>::NEG_NAN.to_bits(), (-f16::NAN).to_bits());
|
||||
assert_eq!(<f16 as Float>::SIG_BITS, 10);
|
||||
assert_eq!(<f16 as Float>::MIN_EXPONENT_ROUND_TO_EVEN, -22);
|
||||
assert_eq!(<f16 as Float>::MAX_EXPONENT_ROUND_TO_EVEN, 5);
|
||||
assert_eq!(<f16 as Float>::EXP_MIN, -14);
|
||||
assert_eq!(<f16 as Float>::EXP_SAT, 0x1f);
|
||||
assert_eq!(<f16 as Float>::SMALLEST_POWER_OF_TEN, -27);
|
||||
assert_eq!(<f16 as Float>::LARGEST_POWER_OF_TEN, 4);
|
||||
|
||||
assert_eq!(<f16 as Lemire>::MIN_EXPONENT_FAST_PATH, -4);
|
||||
assert_eq!(<f16 as Lemire>::MAX_EXPONENT_FAST_PATH, 4);
|
||||
assert_eq!(<f16 as Lemire>::MAX_EXPONENT_DISGUISED_FAST_PATH, 7);
|
||||
assert_eq!(<f16 as Lemire>::MAX_MANTISSA_FAST_PATH, 2048);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32_consts() {
|
||||
assert_eq!(<f32 as RawFloat>::INFINITY, f32::INFINITY);
|
||||
assert_eq!(<f32 as RawFloat>::NEG_INFINITY, -f32::INFINITY);
|
||||
assert_eq!(<f32 as RawFloat>::NAN.to_bits(), f32::NAN.to_bits());
|
||||
assert_eq!(<f32 as RawFloat>::NEG_NAN.to_bits(), (-f32::NAN).to_bits());
|
||||
assert_eq!(<f32 as RawFloat>::SIG_BITS, 23);
|
||||
assert_eq!(<f32 as RawFloat>::MIN_EXPONENT_ROUND_TO_EVEN, -17);
|
||||
assert_eq!(<f32 as RawFloat>::MAX_EXPONENT_ROUND_TO_EVEN, 10);
|
||||
assert_eq!(<f32 as RawFloat>::MIN_EXPONENT_FAST_PATH, -10);
|
||||
assert_eq!(<f32 as RawFloat>::MAX_EXPONENT_FAST_PATH, 10);
|
||||
assert_eq!(<f32 as RawFloat>::MAX_EXPONENT_DISGUISED_FAST_PATH, 17);
|
||||
assert_eq!(<f32 as RawFloat>::EXP_MIN, -126);
|
||||
assert_eq!(<f32 as RawFloat>::EXP_SAT, 0xff);
|
||||
assert_eq!(<f32 as RawFloat>::SMALLEST_POWER_OF_TEN, -65);
|
||||
assert_eq!(<f32 as RawFloat>::LARGEST_POWER_OF_TEN, 38);
|
||||
assert_eq!(<f32 as RawFloat>::MAX_MANTISSA_FAST_PATH, 16777216);
|
||||
assert_eq!(<f32 as Float>::INFINITY, f32::INFINITY);
|
||||
assert_eq!(<f32 as Float>::NEG_INFINITY, -f32::INFINITY);
|
||||
assert_eq!(<f32 as Float>::NAN.to_bits(), f32::NAN.to_bits());
|
||||
assert_eq!(<f32 as Float>::NEG_NAN.to_bits(), (-f32::NAN).to_bits());
|
||||
assert_eq!(<f32 as Float>::SIG_BITS, 23);
|
||||
assert_eq!(<f32 as Float>::MIN_EXPONENT_ROUND_TO_EVEN, -17);
|
||||
assert_eq!(<f32 as Float>::MAX_EXPONENT_ROUND_TO_EVEN, 10);
|
||||
assert_eq!(<f32 as Float>::EXP_MIN, -126);
|
||||
assert_eq!(<f32 as Float>::EXP_SAT, 0xff);
|
||||
assert_eq!(<f32 as Float>::SMALLEST_POWER_OF_TEN, -65);
|
||||
assert_eq!(<f32 as Float>::LARGEST_POWER_OF_TEN, 38);
|
||||
|
||||
assert_eq!(<f32 as Lemire>::MIN_EXPONENT_FAST_PATH, -10);
|
||||
assert_eq!(<f32 as Lemire>::MAX_EXPONENT_FAST_PATH, 10);
|
||||
assert_eq!(<f32 as Lemire>::MAX_EXPONENT_DISGUISED_FAST_PATH, 17);
|
||||
assert_eq!(<f32 as Lemire>::MAX_MANTISSA_FAST_PATH, 16777216);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64_consts() {
|
||||
assert_eq!(<f64 as RawFloat>::INFINITY, f64::INFINITY);
|
||||
assert_eq!(<f64 as RawFloat>::NEG_INFINITY, -f64::INFINITY);
|
||||
assert_eq!(<f64 as RawFloat>::NAN.to_bits(), f64::NAN.to_bits());
|
||||
assert_eq!(<f64 as RawFloat>::NEG_NAN.to_bits(), (-f64::NAN).to_bits());
|
||||
assert_eq!(<f64 as RawFloat>::SIG_BITS, 52);
|
||||
assert_eq!(<f64 as RawFloat>::MIN_EXPONENT_ROUND_TO_EVEN, -4);
|
||||
assert_eq!(<f64 as RawFloat>::MAX_EXPONENT_ROUND_TO_EVEN, 23);
|
||||
assert_eq!(<f64 as RawFloat>::MIN_EXPONENT_FAST_PATH, -22);
|
||||
assert_eq!(<f64 as RawFloat>::MAX_EXPONENT_FAST_PATH, 22);
|
||||
assert_eq!(<f64 as RawFloat>::MAX_EXPONENT_DISGUISED_FAST_PATH, 37);
|
||||
assert_eq!(<f64 as RawFloat>::EXP_MIN, -1022);
|
||||
assert_eq!(<f64 as RawFloat>::EXP_SAT, 0x7ff);
|
||||
assert_eq!(<f64 as RawFloat>::SMALLEST_POWER_OF_TEN, -342);
|
||||
assert_eq!(<f64 as RawFloat>::LARGEST_POWER_OF_TEN, 308);
|
||||
assert_eq!(<f64 as RawFloat>::MAX_MANTISSA_FAST_PATH, 9007199254740992);
|
||||
assert_eq!(<f64 as Float>::INFINITY, f64::INFINITY);
|
||||
assert_eq!(<f64 as Float>::NEG_INFINITY, -f64::INFINITY);
|
||||
assert_eq!(<f64 as Float>::NAN.to_bits(), f64::NAN.to_bits());
|
||||
assert_eq!(<f64 as Float>::NEG_NAN.to_bits(), (-f64::NAN).to_bits());
|
||||
assert_eq!(<f64 as Float>::SIG_BITS, 52);
|
||||
assert_eq!(<f64 as Float>::MIN_EXPONENT_ROUND_TO_EVEN, -4);
|
||||
assert_eq!(<f64 as Float>::MAX_EXPONENT_ROUND_TO_EVEN, 23);
|
||||
assert_eq!(<f64 as Float>::EXP_MIN, -1022);
|
||||
assert_eq!(<f64 as Float>::EXP_SAT, 0x7ff);
|
||||
assert_eq!(<f64 as Float>::SMALLEST_POWER_OF_TEN, -342);
|
||||
assert_eq!(<f64 as Float>::LARGEST_POWER_OF_TEN, 308);
|
||||
|
||||
assert_eq!(<f64 as Lemire>::MIN_EXPONENT_FAST_PATH, -22);
|
||||
assert_eq!(<f64 as Lemire>::MAX_EXPONENT_FAST_PATH, 22);
|
||||
assert_eq!(<f64 as Lemire>::MAX_EXPONENT_DISGUISED_FAST_PATH, 37);
|
||||
assert_eq!(<f64 as Lemire>::MAX_MANTISSA_FAST_PATH, 9007199254740992);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use core::num::imp::dec2flt;
|
||||
use core::num::imp::{Float, dec2flt};
|
||||
|
||||
use dec2flt::float::RawFloat;
|
||||
use dec2flt::lemire::compute_float;
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
|
||||
Reference in New Issue
Block a user