Skip to content

Commit

Permalink
Enable LARGEST_POWER_OF_TEN from expression to show failures
Browse files Browse the repository at this point in the history
More generic work, tests passing

flt2dec work

Figured out the power of 10 magic numbers

Fix off by one

Update library/core/src/num/dec2flt/number.rs
  • Loading branch information
tgross35 committed Jul 23, 2024
1 parent b0561b5 commit 7c3f9c1
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 109 deletions.
213 changes: 128 additions & 85 deletions library/core/src/num/dec2flt/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,50 @@

use crate::fmt::{Debug, LowerExp};
use crate::num::FpCategory;
use crate::ops::{Add, Div, Mul, Neg};
use crate::ops::{self, Add, Div, Mul, Neg};

use core::f64;

pub trait CastInto<T: Copy>: Copy {
fn cast(self) -> T;
}

pub trait Integer:
Sized
+ Clone
+ Copy
+ Debug
+ ops::Shr<u32, Output = Self>
+ ops::Shl<u32, Output = Self>
+ ops::BitAnd<Output = Self>
+ ops::BitOr<Output = Self>
+ PartialEq
+ CastInto<i16>
{
const ZERO: Self;
const ONE: Self;
}

macro_rules! int {
($($ty:ty),+) => {
$(
impl CastInto<i16> for $ty {
fn cast(self) -> i16 {
self as i16
}
}


impl Integer for $ty {
const ZERO: Self = 0;
const ONE: Self = 1;
}
)+
}
}

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.
Expand All @@ -26,6 +66,9 @@ pub trait RawFloat:
+ Copy
+ Debug
{
/// The unsigned integer with the same size as the float
type Int: Integer + Into<u64>;

/* general constants */

const INFINITY: Self;
Expand All @@ -39,6 +82,9 @@ pub trait RawFloat:
/// Mantissa digits including the hidden bit (provided by core)
const MANTISSA_BITS: u32;

const EXPONENT_MASK: Self::Int;
const MANTISSA_MASK: Self::Int;

/// The number of bits in the significand, *excluding* the hidden bit.
const MANTISSA_EXPLICIT_BITS: u32 = Self::MANTISSA_BITS - 1;

Expand Down Expand Up @@ -91,13 +137,14 @@ pub trait RawFloat:
/// This is the max exponent in binary converted to the max exponent in decimal. Allows fast
/// pathing anything larger than `10^LARGEST_POWER_OF_TEN`, which will round to infinity.
// const LARGEST_POWER_OF_TEN: i32;
const LARGEST_POWER_OF_TEN: i32 = (Self::EXPONENT_BIAS as f64 / f64::consts::LOG2_10) as i32;
const LARGEST_POWER_OF_TEN: i32 =
((Self::EXPONENT_BIAS as f64 + 1.0) / f64::consts::LOG2_10) as i32;

/// Smallest decimal exponent for a non-zero value. This allows for fast pathing anything
/// smaller than `10^SMALLEST_POWER_OF_TEN`.
const SMALLEST_POWER_OF_TEN: i32;
// const SMALLEST_POWER_OF_TEN: i32 =
// -(((Self::EXPONENT_BIAS + Self::MANTISSA_BITS) as f64) / f64::consts::LOG2_10) as i32 - 2;
// / smaller than `10^SMALLEST_POWER_OF_TEN`.
// const SMALLEST_POWER_OF_TEN: i32;
const SMALLEST_POWER_OF_TEN: i32 =
-(((Self::EXPONENT_BIAS + Self::MANTISSA_BITS + 64) as f64) / f64::consts::LOG2_10) as i32;

/// Maximum exponent that can be represented for a disguised-fast path case.
/// This is `MAX_EXPONENT_FAST_PATH + ⌊(MANTISSA_EXPLICIT_BITS+1)/log2(10)⌋`
Expand All @@ -122,72 +169,83 @@ pub trait RawFloat:
/// Returns the category that this number falls into.
fn classify(self) -> FpCategory;

/// Transmute to the integer representation
fn to_bits(self) -> Self::Int;

/// Returns the mantissa, exponent and sign as integers.
fn integer_decode(self) -> (u64, i16, i8);
fn integer_decode(self) -> (u64, i16, i8) {
let bits = self.to_bits();
let sign: i8 = if bits >> (Self::BITS - 1) == Self::Int::ZERO { 1 } else { -1 };
let mut exponent: i16 =
((bits & Self::EXPONENT_MASK) >> Self::MANTISSA_EXPLICIT_BITS).cast();
let mantissa = if exponent == 0 {
(bits & Self::MANTISSA_MASK) << 1
} else {
(bits & Self::MANTISSA_MASK) | (Self::Int::ONE << Self::MANTISSA_EXPLICIT_BITS)
};
// Exponent bias + mantissa shift
exponent -= (Self::EXPONENT_BIAS + Self::MANTISSA_EXPLICIT_BITS) as i16;
(mantissa.into(), exponent, sign)
}
}

// #[cfg(not(bootstrap))]
// impl RawFloat for f16 {
// const INFINITY: Self = Self::INFINITY;
// const NEG_INFINITY: Self = Self::NEG_INFINITY;
// const NAN: Self = Self::NAN;
// const NEG_NAN: Self = -Self::NAN;

// const BITS: u32 = 16;
// const MANTISSA_DIGITS: u32 = Self::MANTISSA_DIGITS;

// const MIN_EXPONENT_FAST_PATH: i64 = -4; // assuming FLT_EVAL_METHOD = 0
// const MAX_EXPONENT_FAST_PATH: i64 = 4;

// const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17;
// const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
// const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 17;
// const SMALLEST_POWER_OF_TEN: i32 = -65;
// const LARGEST_POWER_OF_TEN: i32 = Self::MAX_10_EXP;

// #[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: [f32; 16] =
// [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.];
// TABLE[exponent & 15]
// }

// /// Returns the mantissa, exponent and sign as integers.
// fn integer_decode(self) -> (u64, i16, i8) {
// let bits = self.to_bits();
// let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
// let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
// let mantissa =
// if exponent == 0 { (bits & 0x7fffff) << 1 } else { (bits & 0x7fffff) | 0x800000 };
// // Exponent bias + mantissa shift
// exponent -= 127 + 23;
// (mantissa as u64, exponent, sign)
// }

// fn classify(self) -> FpCategory {
// self.classify()
// }
// }
#[cfg(not(bootstrap))]
impl RawFloat for f16 {
type Int = u16;

const INFINITY: Self = Self::INFINITY;
const NEG_INFINITY: Self = Self::NEG_INFINITY;
const NAN: Self = Self::NAN;
const NEG_NAN: Self = -Self::NAN;

const BITS: u32 = 16;
const MANTISSA_BITS: u32 = Self::MANTISSA_DIGITS;
const EXPONENT_MASK: Self::Int = Self::EXP_MASK;
const MANTISSA_MASK: Self::Int = Self::MAN_MASK;

const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17;
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
// const SMALLEST_POWER_OF_TEN: i32 = -27;
// const LARGEST_POWER_OF_TEN: i32 = Self::MAX_10_EXP;

#[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 & 0xFF) 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 & 15]
}

fn to_bits(self) -> Self::Int {
self.to_bits()
}

fn classify(self) -> FpCategory {
todo!()
}
}

impl RawFloat for f32 {
type Int = u32;

const INFINITY: Self = f32::INFINITY;
const NEG_INFINITY: Self = f32::NEG_INFINITY;
const NAN: Self = f32::NAN;
const NEG_NAN: Self = -f32::NAN;

const BITS: u32 = 32;
const MANTISSA_BITS: u32 = Self::MANTISSA_DIGITS;
const EXPONENT_MASK: Self::Int = Self::EXP_MASK;
const MANTISSA_MASK: Self::Int = Self::MAN_MASK;

// const MANTISSA_EXPLICIT_BITS: u32 = 23;
const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17;
Expand All @@ -198,7 +256,7 @@ impl RawFloat for f32 {
// const MINIMUM_EXPONENT: i32 = -127;
// const INFINITE_POWER: i32 = 0xFF;
// const SIGN_INDEX: u32 = 31;
const SMALLEST_POWER_OF_TEN: i32 = -65;
// const SMALLEST_POWER_OF_TEN: i32 = -65;
// const LARGEST_POWER_OF_TEN: i32 = 38;

#[inline]
Expand All @@ -219,16 +277,8 @@ impl RawFloat for f32 {
TABLE[exponent & 15]
}

/// Returns the mantissa, exponent and sign as integers.
fn integer_decode(self) -> (u64, i16, i8) {
let bits = self.to_bits();
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
let mantissa =
if exponent == 0 { (bits & 0x7fffff) << 1 } else { (bits & 0x7fffff) | 0x800000 };
// Exponent bias + mantissa shift
exponent -= 127 + 23;
(mantissa as u64, exponent, sign)
fn to_bits(self) -> Self::Int {
self.to_bits()
}

fn classify(self) -> FpCategory {
Expand All @@ -237,13 +287,17 @@ impl RawFloat for f32 {
}

impl RawFloat for f64 {
type Int = u64;

const INFINITY: Self = Self::INFINITY;
const NEG_INFINITY: Self = Self::NEG_INFINITY;
const NAN: Self = Self::NAN;
const NEG_NAN: Self = -Self::NAN;

const BITS: u32 = 64;
const MANTISSA_BITS: u32 = Self::MANTISSA_DIGITS;
const EXPONENT_MASK: Self::Int = Self::EXP_MASK;
const MANTISSA_MASK: Self::Int = Self::MAN_MASK;

// const MANTISSA_EXPLICIT_BITS: u32 = 52;
const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -4;
Expand All @@ -254,7 +308,7 @@ impl RawFloat for f64 {
// const MINIMUM_EXPONENT: i32 = -1023;
// const INFINITE_POWER: i32 = 0x7FF;
// const SIGN_INDEX: u32 = 63;
const SMALLEST_POWER_OF_TEN: i32 = -342;
// const SMALLEST_POWER_OF_TEN: i32 = -342;
// const LARGEST_POWER_OF_TEN: i32 = 308;

#[inline]
Expand All @@ -276,19 +330,8 @@ impl RawFloat for f64 {
TABLE[exponent & 31]
}

/// Returns the mantissa, exponent and sign as integers.
fn integer_decode(self) -> (u64, i16, i8) {
let bits = self.to_bits();
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
let mantissa = if exponent == 0 {
(bits & 0xfffffffffffff) << 1
} else {
(bits & 0xfffffffffffff) | 0x10000000000000
};
// Exponent bias + mantissa shift
exponent -= 1023 + 52;
(mantissa, exponent, sign)
fn to_bits(self) -> Self::Int {
self.to_bits()
}

fn classify(self) -> FpCategory {
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/num/dec2flt/lemire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ pub fn compute_float<F: RawFloat>(q: i64, mut w: u64) -> BiasedFp {
if lo <= 1
&& q >= F::MIN_EXPONENT_ROUND_TO_EVEN as i64
&& q <= F::MAX_EXPONENT_ROUND_TO_EVEN as i64
&& mantissa & 3 == 1
&& mantissa & 0b11 == 1
&& (mantissa << (upperbit + 64 - F::MANTISSA_EXPLICIT_BITS as i32 - 3)) == hi
{
// Zero the lowest bit, so we don't round up.
Expand Down
6 changes: 1 addition & 5 deletions library/core/src/num/dec2flt/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ impl Number {
F::from_u64(mantissa) * F::pow10_fast_path(F::MAX_EXPONENT_FAST_PATH as _)
};

if self.negative {
value = -value;
}

Some(value)
if self.negative { Some(-value) } else { Some(value) }
}
}
3 changes: 2 additions & 1 deletion library/core/src/num/f16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,10 @@ impl f16 {
pub(crate) const SIGN_MASK: u16 = 0x8000;

/// Exponent mask
#[cfg(not(bootstrap))]
pub(crate) const EXP_MASK: u16 = 0x7c00;

/// Mantissa mask
#[cfg(not(bootstrap))]
pub(crate) const MAN_MASK: u16 = 0x03ff;

/// Minimum representable positive value (min subnormal)
Expand Down
6 changes: 3 additions & 3 deletions library/core/src/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,13 +491,13 @@ impl f32 {
pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32;

/// Sign bit
const SIGN_MASK: u32 = 0x8000_0000;
pub(crate) const SIGN_MASK: u32 = 0x8000_0000;

/// Exponent mask
const EXP_MASK: u32 = 0x7f80_0000;
pub(crate) const EXP_MASK: u32 = 0x7f80_0000;

/// Mantissa mask
const MAN_MASK: u32 = 0x007f_ffff;
pub(crate) const MAN_MASK: u32 = 0x007f_ffff;

/// Minimum representable positive value (min subnormal)
const TINY_BITS: u32 = 0x1;
Expand Down
6 changes: 3 additions & 3 deletions library/core/src/num/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,13 +490,13 @@ impl f64 {
pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64;

/// Sign bit
const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
pub(crate) const SIGN_MASK: u64 = 0x8000_0000_0000_0000;

/// Exponent mask
const EXP_MASK: u64 = 0x7ff0_0000_0000_0000;
pub(crate) const EXP_MASK: u64 = 0x7ff0_0000_0000_0000;

/// Mantissa mask
const MAN_MASK: u64 = 0x000f_ffff_ffff_ffff;
pub(crate) const MAN_MASK: u64 = 0x000f_ffff_ffff_ffff;

/// Minimum representable positive value (min subnormal)
const TINY_BITS: u64 = 0x1;
Expand Down
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#![feature(duration_constructors)]
#![feature(exact_size_is_empty)]
#![feature(extern_types)]
#![feature(f16)]
#![feature(freeze)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
Expand Down
Loading

0 comments on commit 7c3f9c1

Please sign in to comment.