Skip to content

Commit d3005eb

Browse files
committed
Everything working with some magic constants removed
1 parent 49649bf commit d3005eb

File tree

8 files changed

+284
-98
lines changed

8 files changed

+284
-98
lines changed

library/core/src/fmt/float.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ macro_rules! impl_general_format {
2121
}
2222
}
2323

24+
#[cfg(not(bootstrap))]
25+
impl_general_format! { f16 }
2426
impl_general_format! { f32 f64 }
2527

2628
// Don't inline this so callers don't use the stack space this function
@@ -228,17 +230,11 @@ macro_rules! floating {
228230
};
229231
}
230232

233+
#[cfg(not(bootstrap))]
234+
floating! { f16 }
231235
floating! { f32 }
232236
floating! { f64 }
233237

234-
#[stable(feature = "rust1", since = "1.0.0")]
235-
impl Debug for f16 {
236-
#[inline]
237-
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
238-
write!(f, "{:#06x}", self.to_bits())
239-
}
240-
}
241-
242238
#[stable(feature = "rust1", since = "1.0.0")]
243239
impl Debug for f128 {
244240
#[inline]

library/core/src/num/dec2flt/float.rs

Lines changed: 147 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ use crate::fmt::{Debug, LowerExp};
44
use crate::num::FpCategory;
55
use crate::ops::{Add, Div, Mul, Neg};
66

7-
/// A helper trait to avoid duplicating basically all the conversion code for `f32` and `f64`.
7+
use core::f64;
8+
9+
/// A helper trait to avoid duplicating basically all the conversion code for IEEE floats.
810
///
911
/// See the parent module's doc comment for why this is necessary.
1012
///
11-
/// Should **never ever** be implemented for other types or be used outside the dec2flt module.
13+
/// Should **never ever** be implemented for other types or be used outside the `dec2flt` module.
1214
#[doc(hidden)]
1315
pub trait RawFloat:
1416
Sized
@@ -24,62 +26,86 @@ pub trait RawFloat:
2426
+ Copy
2527
+ Debug
2628
{
29+
/* general constants */
30+
2731
const INFINITY: Self;
2832
const NEG_INFINITY: Self;
2933
const NAN: Self;
3034
const NEG_NAN: Self;
3135

36+
/// Bit width of the float
37+
const BITS: u32;
38+
39+
/// Mantissa digits including the hidden bit (provided by core)
40+
const MANTISSA_BITS: u32;
41+
3242
/// The number of bits in the significand, *excluding* the hidden bit.
33-
const MANTISSA_EXPLICIT_BITS: usize;
34-
35-
// Round-to-even only happens for negative values of q
36-
// when q ≥ −4 in the 64-bit case and when q ≥ −17 in
37-
// the 32-bitcase.
38-
//
39-
// When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we
40-
// have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have
41-
// 5^q ≤ 2m+1 ≤ 2^25 or q ≤ 10.
42-
//
43-
// When q < 0, we have w ≥ (2m+1)×5^−q. We must have that w < 2^64
44-
// so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case)
45-
// or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64
46-
// (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11
47-
// or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bitcase).
48-
//
49-
// Thus we have that we only need to round ties to even when
50-
// we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10]
51-
// (in the 32-bit case). In both cases,the power of five(5^|q|)
52-
// fits in a 64-bit word.
43+
const MANTISSA_EXPLICIT_BITS: u32 = Self::MANTISSA_BITS - 1;
44+
45+
/// Bits for the exponent
46+
const EXPONENT_BITS: u32 = Self::BITS - Self::MANTISSA_EXPLICIT_BITS - 1;
47+
48+
/// Maximum exponent for a fast path case, or `⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋`
49+
// assuming FLT_EVAL_METHOD = 0
50+
const MAX_EXPONENT_FAST_PATH: i64 =
51+
((Self::MANTISSA_BITS as f64) / (f64::consts::LOG2_10 - 1.0)) as i64;
52+
53+
/// Minimum exponent for a fast path case, or `-⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋`
54+
const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH;
55+
56+
/// Round-to-even only happens for negative values of q
57+
/// when q ≥ −4 in the 64-bit case and when q ≥ −17 in
58+
/// the 32-bitcase.
59+
///
60+
/// When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we
61+
/// have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have
62+
/// 5^q ≤ 2m+1 ≤ 2^25 or q ≤ 10.
63+
///
64+
/// When q < 0, we have w ≥ (2m+1)×5^−q. We must have that w < 2^64
65+
/// so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case)
66+
/// or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64
67+
/// (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11
68+
/// or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bitcase).
69+
///
70+
/// Thus we have that we only need to round ties to even when
71+
/// we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10]
72+
/// (in the 32-bit case). In both cases,the power of five(5^|q|)
73+
/// fits in a 64-bit word.
5374
const MIN_EXPONENT_ROUND_TO_EVEN: i32;
5475
const MAX_EXPONENT_ROUND_TO_EVEN: i32;
5576

56-
// Minimum exponent that for a fast path case, or `-⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋`
57-
const MIN_EXPONENT_FAST_PATH: i64;
77+
/// Minimum exponent value `-(1 << (EXP_BITS - 1)) + 1`.
78+
const MINIMUM_EXPONENT: i32 = -(1 << (Self::EXPONENT_BITS - 1)) + 1;
5879

59-
// Maximum exponent that for a fast path case, or `⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋`
60-
const MAX_EXPONENT_FAST_PATH: i64;
80+
/// Maximum exponent without overflowing to infinity
81+
const MAXIMUM_EXPONENT: u32 = (1 << Self::EXPONENT_BITS) - 1;
6182

62-
// Maximum exponent that can be represented for a disguised-fast path case.
63-
// This is `MAX_EXPONENT_FAST_PATH + ⌊(MANTISSA_EXPLICIT_BITS+1)/log2(10)⌋`
64-
const MAX_EXPONENT_DISGUISED_FAST_PATH: i64;
83+
/// The exponent bias value
84+
const EXPONENT_BIAS: u32 = Self::MAXIMUM_EXPONENT >> 1;
6585

66-
// Minimum exponent value `-(1 << (EXP_BITS - 1)) + 1`.
67-
const MINIMUM_EXPONENT: i32;
86+
/// Largest exponent value `(1 << EXP_BITS) - 1`.
87+
const INFINITE_POWER: i32 = (1 << Self::EXPONENT_BITS) - 1;
6888

69-
// Largest exponent value `(1 << EXP_BITS) - 1`.
70-
const INFINITE_POWER: i32;
89+
/// Largest decimal exponent for a non-infinite value.
90+
///
91+
/// This is the max exponent in binary converted to the max exponent in decimal. Allows fast
92+
/// pathing anything larger than `10^LARGEST_POWER_OF_TEN`, which will round to infinity.
93+
// const LARGEST_POWER_OF_TEN: i32;
94+
const LARGEST_POWER_OF_TEN: i32 = (Self::EXPONENT_BIAS as f64 / f64::consts::LOG2_10) as i32;
7195

72-
// Index (in bits) of the sign.
73-
const SIGN_INDEX: usize;
74-
75-
// Smallest decimal exponent for a non-zero value.
96+
/// Smallest decimal exponent for a non-zero value. This allows for fast pathing anything
97+
/// smaller than `10^SMALLEST_POWER_OF_TEN`.
7698
const SMALLEST_POWER_OF_TEN: i32;
99+
// const SMALLEST_POWER_OF_TEN: i32 =
100+
// -(((Self::EXPONENT_BIAS + Self::MANTISSA_BITS) as f64) / f64::consts::LOG2_10) as i32 - 2;
77101

78-
// Largest decimal exponent for a non-infinite value.
79-
const LARGEST_POWER_OF_TEN: i32;
102+
/// Maximum exponent that can be represented for a disguised-fast path case.
103+
/// This is `MAX_EXPONENT_FAST_PATH + ⌊(MANTISSA_EXPLICIT_BITS+1)/log2(10)⌋`
104+
const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 =
105+
Self::MAX_EXPONENT_FAST_PATH + (Self::MANTISSA_BITS as f64 / f64::consts::LOG2_10) as i64;
80106

81-
// Maximum mantissa for the fast-path (`1 << 53` for f64).
82-
const MAX_MANTISSA_FAST_PATH: u64 = 2_u64 << Self::MANTISSA_EXPLICIT_BITS;
107+
/// Maximum mantissa for the fast-path (`1 << 53` for f64).
108+
const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::MANTISSA_BITS;
83109

84110
/// Convert integer into float through an as cast.
85111
/// This is only called in the fast-path algorithm, and therefore
@@ -100,23 +126,80 @@ pub trait RawFloat:
100126
fn integer_decode(self) -> (u64, i16, i8);
101127
}
102128

129+
// #[cfg(not(bootstrap))]
130+
// impl RawFloat for f16 {
131+
// const INFINITY: Self = Self::INFINITY;
132+
// const NEG_INFINITY: Self = Self::NEG_INFINITY;
133+
// const NAN: Self = Self::NAN;
134+
// const NEG_NAN: Self = -Self::NAN;
135+
136+
// const BITS: u32 = 16;
137+
// const MANTISSA_DIGITS: u32 = Self::MANTISSA_DIGITS;
138+
139+
// const MIN_EXPONENT_FAST_PATH: i64 = -4; // assuming FLT_EVAL_METHOD = 0
140+
// const MAX_EXPONENT_FAST_PATH: i64 = 4;
141+
142+
// const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17;
143+
// const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
144+
// const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 17;
145+
// const SMALLEST_POWER_OF_TEN: i32 = -65;
146+
// const LARGEST_POWER_OF_TEN: i32 = Self::MAX_10_EXP;
147+
148+
// #[inline]
149+
// fn from_u64(v: u64) -> Self {
150+
// debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
151+
// v as _
152+
// }
153+
154+
// #[inline]
155+
// fn from_u64_bits(v: u64) -> Self {
156+
// Self::from_bits((v & 0xFFFF) as u16)
157+
// }
158+
159+
// fn pow10_fast_path(exponent: usize) -> Self {
160+
// #[allow(clippy::use_self)]
161+
// const TABLE: [f32; 16] =
162+
// [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.];
163+
// TABLE[exponent & 15]
164+
// }
165+
166+
// /// Returns the mantissa, exponent and sign as integers.
167+
// fn integer_decode(self) -> (u64, i16, i8) {
168+
// let bits = self.to_bits();
169+
// let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
170+
// let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
171+
// let mantissa =
172+
// if exponent == 0 { (bits & 0x7fffff) << 1 } else { (bits & 0x7fffff) | 0x800000 };
173+
// // Exponent bias + mantissa shift
174+
// exponent -= 127 + 23;
175+
// (mantissa as u64, exponent, sign)
176+
// }
177+
178+
// fn classify(self) -> FpCategory {
179+
// self.classify()
180+
// }
181+
// }
182+
103183
impl RawFloat for f32 {
104184
const INFINITY: Self = f32::INFINITY;
105185
const NEG_INFINITY: Self = f32::NEG_INFINITY;
106186
const NAN: Self = f32::NAN;
107187
const NEG_NAN: Self = -f32::NAN;
108188

109-
const MANTISSA_EXPLICIT_BITS: usize = 23;
189+
const BITS: u32 = 32;
190+
const MANTISSA_BITS: u32 = Self::MANTISSA_DIGITS;
191+
192+
// const MANTISSA_EXPLICIT_BITS: u32 = 23;
110193
const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17;
111194
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
112-
const MIN_EXPONENT_FAST_PATH: i64 = -10; // assuming FLT_EVAL_METHOD = 0
113-
const MAX_EXPONENT_FAST_PATH: i64 = 10;
114-
const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 17;
115-
const MINIMUM_EXPONENT: i32 = -127;
116-
const INFINITE_POWER: i32 = 0xFF;
117-
const SIGN_INDEX: usize = 31;
195+
// const MIN_EXPONENT_FAST_PATH: i64 = -10; // assuming FLT_EVAL_METHOD = 0
196+
// const MAX_EXPONENT_FAST_PATH: i64 = 10;
197+
// const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 17;
198+
// const MINIMUM_EXPONENT: i32 = -127;
199+
// const INFINITE_POWER: i32 = 0xFF;
200+
// const SIGN_INDEX: u32 = 31;
118201
const SMALLEST_POWER_OF_TEN: i32 = -65;
119-
const LARGEST_POWER_OF_TEN: i32 = 38;
202+
// const LARGEST_POWER_OF_TEN: i32 = 38;
120203

121204
#[inline]
122205
fn from_u64(v: u64) -> Self {
@@ -154,22 +237,25 @@ impl RawFloat for f32 {
154237
}
155238

156239
impl RawFloat for f64 {
157-
const INFINITY: Self = f64::INFINITY;
158-
const NEG_INFINITY: Self = f64::NEG_INFINITY;
159-
const NAN: Self = f64::NAN;
160-
const NEG_NAN: Self = -f64::NAN;
240+
const INFINITY: Self = Self::INFINITY;
241+
const NEG_INFINITY: Self = Self::NEG_INFINITY;
242+
const NAN: Self = Self::NAN;
243+
const NEG_NAN: Self = -Self::NAN;
244+
245+
const BITS: u32 = 64;
246+
const MANTISSA_BITS: u32 = Self::MANTISSA_DIGITS;
161247

162-
const MANTISSA_EXPLICIT_BITS: usize = 52;
248+
// const MANTISSA_EXPLICIT_BITS: u32 = 52;
163249
const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -4;
164250
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23;
165-
const MIN_EXPONENT_FAST_PATH: i64 = -22; // assuming FLT_EVAL_METHOD = 0
166-
const MAX_EXPONENT_FAST_PATH: i64 = 22;
167-
const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 37;
168-
const MINIMUM_EXPONENT: i32 = -1023;
169-
const INFINITE_POWER: i32 = 0x7FF;
170-
const SIGN_INDEX: usize = 63;
251+
// const MIN_EXPONENT_FAST_PATH: i64 = -22; // assuming FLT_EVAL_METHOD = 0
252+
// const MAX_EXPONENT_FAST_PATH: i64 = 22;
253+
// const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 37;
254+
// const MINIMUM_EXPONENT: i32 = -1023;
255+
// const INFINITE_POWER: i32 = 0x7FF;
256+
// const SIGN_INDEX: u32 = 63;
171257
const SMALLEST_POWER_OF_TEN: i32 = -342;
172-
const LARGEST_POWER_OF_TEN: i32 = 308;
258+
// const LARGEST_POWER_OF_TEN: i32 = 308;
173259

174260
#[inline]
175261
fn from_u64(v: u64) -> Self {

library/core/src/num/dec2flt/lemire.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub fn compute_float<F: RawFloat>(q: i64, mut w: u64) -> BiasedFp {
3838
// Normalize our significant digits, so the most-significant bit is set.
3939
let lz = w.leading_zeros();
4040
w <<= lz;
41-
let (lo, hi) = compute_product_approx(q, w, F::MANTISSA_EXPLICIT_BITS + 3);
41+
let (lo, hi) = compute_product_approx(q, w, F::MANTISSA_EXPLICIT_BITS as usize + 3);
4242
if lo == 0xFFFF_FFFF_FFFF_FFFF {
4343
// If we have failed to approximate w x 5^-q with our 128-bit value.
4444
// Since the addition of 1 could lead to an overflow which could then

library/core/src/num/dec2flt/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@
6767
//! "such that the exponent +/- the number of decimal digits fits into a 64 bit integer".
6868
//! Larger exponents are accepted, but we don't do arithmetic with them, they are immediately
6969
//! turned into {positive,negative} {zero,infinity}.
70+
//!
71+
//! # Notation
72+
//!
73+
//! This module uses the same notation as the Lemire paper:
74+
//!
75+
//! - `m`: binary mantissa; always nonnegative
76+
//! - `p`: binary exponent; a signed integer
77+
//! - `w`: decimal significand; always nonnegative
78+
//! - `q`: decimal exponent; a signed integer
79+
//!
80+
//! This gives `m * 2^p` for the binary floating-point number, with `w * 10^q` as the decimal
81+
//! equivalent.
7082
7183
#![doc(hidden)]
7284
#![unstable(

library/core/src/num/dec2flt/number.rs

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,15 @@ pub struct Number {
3434
impl Number {
3535
/// Detect if the float can be accurately reconstructed from native floats.
3636
#[inline]
37-
fn is_fast_path<F: RawFloat>(&self) -> bool {
37+
fn can_use_fast_path<F: RawFloat>(&self) -> bool {
3838
F::MIN_EXPONENT_FAST_PATH <= self.exponent
3939
&& self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH
4040
&& self.mantissa <= F::MAX_MANTISSA_FAST_PATH
4141
&& !self.many_digits
4242
}
4343

44-
/// The fast path algorithm using machine-sized integers and floats.
44+
/// The fast path algorithm to turn into an exact float representation, using machine-sized
45+
/// integers and floats.
4546
///
4647
/// This is extracted into a separate function so that it can be attempted before constructing
4748
/// a Decimal. This only works if both the mantissa and the exponent
@@ -59,30 +60,32 @@ impl Number {
5960
// require setting it by changing the global state (like the control word of the x87 FPU).
6061
let _cw = set_precision::<F>();
6162

62-
if self.is_fast_path::<F>() {
63-
let mut value = if self.exponent <= F::MAX_EXPONENT_FAST_PATH {
64-
// normal fast path
65-
let value = F::from_u64(self.mantissa);
66-
if self.exponent < 0 {
67-
value / F::pow10_fast_path((-self.exponent) as _)
68-
} else {
69-
value * F::pow10_fast_path(self.exponent as _)
70-
}
63+
if !self.can_use_fast_path::<F>() {
64+
return None;
65+
}
66+
67+
let mut value = if self.exponent <= F::MAX_EXPONENT_FAST_PATH {
68+
// normal fast path
69+
let value = F::from_u64(self.mantissa);
70+
if self.exponent < 0 {
71+
value / F::pow10_fast_path((-self.exponent) as _)
7172
} else {
72-
// disguised fast path
73-
let shift = self.exponent - F::MAX_EXPONENT_FAST_PATH;
74-
let mantissa = self.mantissa.checked_mul(INT_POW10[shift as usize])?;
75-
if mantissa > F::MAX_MANTISSA_FAST_PATH {
76-
return None;
77-
}
78-
F::from_u64(mantissa) * F::pow10_fast_path(F::MAX_EXPONENT_FAST_PATH as _)
79-
};
80-
if self.negative {
81-
value = -value;
73+
value * F::pow10_fast_path(self.exponent as _)
8274
}
83-
Some(value)
8475
} else {
85-
None
76+
// disguised fast path
77+
let shift = self.exponent - F::MAX_EXPONENT_FAST_PATH;
78+
let mantissa = self.mantissa.checked_mul(INT_POW10[shift as usize])?;
79+
if mantissa > F::MAX_MANTISSA_FAST_PATH {
80+
return None;
81+
}
82+
F::from_u64(mantissa) * F::pow10_fast_path(F::MAX_EXPONENT_FAST_PATH as _)
83+
};
84+
85+
if self.negative {
86+
value = -value;
8687
}
88+
89+
Some(value)
8790
}
8891
}

0 commit comments

Comments
 (0)