Skip to content

Commit

Permalink
Merge pull request #656 from tgross35/public-test-deps
Browse files Browse the repository at this point in the history
  • Loading branch information
Amanieu authored Aug 6, 2024
2 parents 2216530 + 2e2a925 commit 6736513
Show file tree
Hide file tree
Showing 8 changed files with 752 additions and 759 deletions.
190 changes: 5 additions & 185 deletions src/float/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
use core::ops;

use crate::int::{DInt, Int, MinInt};

pub mod add;
pub mod cmp;
pub mod conv;
Expand All @@ -10,187 +6,11 @@ pub mod extend;
pub mod mul;
pub mod pow;
pub mod sub;
pub(crate) mod traits;
pub mod trunc;

/// Wrapper to extract the integer type half of the float's size
pub(crate) type HalfRep<F> = <<F as Float>::Int as DInt>::H;

public_test_dep! {
/// Trait for some basic operations on floats
#[allow(dead_code)]
pub(crate) trait Float:
Copy
+ core::fmt::Debug
+ PartialEq
+ PartialOrd
+ ops::AddAssign
+ ops::MulAssign
+ ops::Add<Output = Self>
+ ops::Sub<Output = Self>
+ ops::Div<Output = Self>
+ ops::Rem<Output = Self>
{
/// A uint of the same width as the float
type Int: Int;

/// A int of the same width as the float
type SignedInt: Int;

/// An int capable of containing the exponent bits plus a sign bit. This is signed.
type ExpInt: Int;

const ZERO: Self;
const ONE: Self;

/// The bitwidth of the float type
const BITS: u32;

/// The bitwidth of the significand
const SIGNIFICAND_BITS: u32;

/// The bitwidth of the exponent
const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1;

/// The maximum value of the exponent
const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1;

/// The exponent bias value
const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1;

/// A mask for the sign bit
const SIGN_MASK: Self::Int;

/// A mask for the significand
const SIGNIFICAND_MASK: Self::Int;

/// The implicit bit of the float format
const IMPLICIT_BIT: Self::Int;

/// A mask for the exponent
const EXPONENT_MASK: Self::Int;

/// Returns `self` transmuted to `Self::Int`
fn repr(self) -> Self::Int;

/// Returns `self` transmuted to `Self::SignedInt`
fn signed_repr(self) -> Self::SignedInt;

/// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
/// represented in multiple different ways. This method returns `true` if two NaNs are
/// compared.
fn eq_repr(self, rhs: Self) -> bool;

/// Returns true if the sign is negative
fn is_sign_negative(self) -> bool;

/// Returns the exponent with bias
fn exp(self) -> Self::ExpInt;

/// Returns the significand with no implicit bit (or the "fractional" part)
fn frac(self) -> Self::Int;

/// Returns the significand with implicit bit
fn imp_frac(self) -> Self::Int;

/// Returns a `Self::Int` transmuted back to `Self`
fn from_repr(a: Self::Int) -> Self;

/// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position.
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self;

/// Returns (normalized exponent, normalized significand)
fn normalize(significand: Self::Int) -> (i32, Self::Int);

/// Returns if `self` is subnormal
fn is_subnormal(self) -> bool;
}
}

macro_rules! float_impl {
($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => {
impl Float for $ty {
type Int = $ity;
type SignedInt = $sity;
type ExpInt = $expty;

const ZERO: Self = 0.0;
const ONE: Self = 1.0;

const BITS: u32 = $bits;
const SIGNIFICAND_BITS: u32 = $significand_bits;

const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1);
const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1;
const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS;
const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK);

fn repr(self) -> Self::Int {
self.to_bits()
}
fn signed_repr(self) -> Self::SignedInt {
self.to_bits() as Self::SignedInt
}
fn eq_repr(self, rhs: Self) -> bool {
#[cfg(feature = "mangled-names")]
fn is_nan(x: $ty) -> bool {
// When using mangled-names, the "real" compiler-builtins might not have the
// necessary builtin (__unordtf2) to test whether `f128` is NaN.
// FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin
// x is NaN if all the bits of the exponent are set and the significand is non-0
x.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK
&& x.repr() & $ty::SIGNIFICAND_MASK != 0
}
#[cfg(not(feature = "mangled-names"))]
fn is_nan(x: $ty) -> bool {
x.is_nan()
}
if is_nan(self) && is_nan(rhs) {
true
} else {
self.repr() == rhs.repr()
}
}
fn is_sign_negative(self) -> bool {
self.is_sign_negative()
}
fn exp(self) -> Self::ExpInt {
((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt
}
fn frac(self) -> Self::Int {
self.to_bits() & Self::SIGNIFICAND_MASK
}
fn imp_frac(self) -> Self::Int {
self.frac() | Self::IMPLICIT_BIT
}
fn from_repr(a: Self::Int) -> Self {
Self::from_bits(a)
}
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
Self::from_repr(
((sign as Self::Int) << (Self::BITS - 1))
| ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK)
| (significand & Self::SIGNIFICAND_MASK),
)
}
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
let shift = significand
.leading_zeros()
.wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros());
(
1i32.wrapping_sub(shift as i32),
significand << shift as Self::Int,
)
}
fn is_subnormal(self) -> bool {
(self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO
}
}
};
}
#[cfg(not(feature = "public-test-deps"))]
pub(crate) use traits::{Float, HalfRep};

#[cfg(f16_enabled)]
float_impl!(f16, u16, i16, i8, 16, 10);
float_impl!(f32, u32, i32, i16, 32, 23);
float_impl!(f64, u64, i64, i16, 64, 52);
#[cfg(f128_enabled)]
float_impl!(f128, u128, i128, i16, 128, 112);
#[cfg(feature = "public-test-deps")]
pub use traits::{Float, HalfRep};
184 changes: 184 additions & 0 deletions src/float/traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
use core::ops;

use crate::int::{DInt, Int, MinInt};

/// Wrapper to extract the integer type half of the float's size
pub type HalfRep<F> = <<F as Float>::Int as DInt>::H;

/// Trait for some basic operations on floats
#[allow(dead_code)]
pub trait Float:
Copy
+ core::fmt::Debug
+ PartialEq
+ PartialOrd
+ ops::AddAssign
+ ops::MulAssign
+ ops::Add<Output = Self>
+ ops::Sub<Output = Self>
+ ops::Div<Output = Self>
+ ops::Rem<Output = Self>
{
/// A uint of the same width as the float
type Int: Int;

/// A int of the same width as the float
type SignedInt: Int;

/// An int capable of containing the exponent bits plus a sign bit. This is signed.
type ExpInt: Int;

const ZERO: Self;
const ONE: Self;

/// The bitwidth of the float type
const BITS: u32;

/// The bitwidth of the significand
const SIGNIFICAND_BITS: u32;

/// The bitwidth of the exponent
const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1;

/// The maximum value of the exponent
const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1;

/// The exponent bias value
const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1;

/// A mask for the sign bit
const SIGN_MASK: Self::Int;

/// A mask for the significand
const SIGNIFICAND_MASK: Self::Int;

/// The implicit bit of the float format
const IMPLICIT_BIT: Self::Int;

/// A mask for the exponent
const EXPONENT_MASK: Self::Int;

/// Returns `self` transmuted to `Self::Int`
fn repr(self) -> Self::Int;

/// Returns `self` transmuted to `Self::SignedInt`
fn signed_repr(self) -> Self::SignedInt;

/// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
/// represented in multiple different ways. This method returns `true` if two NaNs are
/// compared.
fn eq_repr(self, rhs: Self) -> bool;

/// Returns true if the sign is negative
fn is_sign_negative(self) -> bool;

/// Returns the exponent with bias
fn exp(self) -> Self::ExpInt;

/// Returns the significand with no implicit bit (or the "fractional" part)
fn frac(self) -> Self::Int;

/// Returns the significand with implicit bit
fn imp_frac(self) -> Self::Int;

/// Returns a `Self::Int` transmuted back to `Self`
fn from_repr(a: Self::Int) -> Self;

/// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position.
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self;

/// Returns (normalized exponent, normalized significand)
fn normalize(significand: Self::Int) -> (i32, Self::Int);

/// Returns if `self` is subnormal
fn is_subnormal(self) -> bool;
}

macro_rules! float_impl {
($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => {
impl Float for $ty {
type Int = $ity;
type SignedInt = $sity;
type ExpInt = $expty;

const ZERO: Self = 0.0;
const ONE: Self = 1.0;

const BITS: u32 = $bits;
const SIGNIFICAND_BITS: u32 = $significand_bits;

const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1);
const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1;
const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS;
const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK);

fn repr(self) -> Self::Int {
self.to_bits()
}
fn signed_repr(self) -> Self::SignedInt {
self.to_bits() as Self::SignedInt
}
fn eq_repr(self, rhs: Self) -> bool {
#[cfg(feature = "mangled-names")]
fn is_nan(x: $ty) -> bool {
// When using mangled-names, the "real" compiler-builtins might not have the
// necessary builtin (__unordtf2) to test whether `f128` is NaN.
// FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin
// x is NaN if all the bits of the exponent are set and the significand is non-0
x.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK
&& x.repr() & $ty::SIGNIFICAND_MASK != 0
}
#[cfg(not(feature = "mangled-names"))]
fn is_nan(x: $ty) -> bool {
x.is_nan()
}
if is_nan(self) && is_nan(rhs) {
true
} else {
self.repr() == rhs.repr()
}
}
fn is_sign_negative(self) -> bool {
self.is_sign_negative()
}
fn exp(self) -> Self::ExpInt {
((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt
}
fn frac(self) -> Self::Int {
self.to_bits() & Self::SIGNIFICAND_MASK
}
fn imp_frac(self) -> Self::Int {
self.frac() | Self::IMPLICIT_BIT
}
fn from_repr(a: Self::Int) -> Self {
Self::from_bits(a)
}
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
Self::from_repr(
((sign as Self::Int) << (Self::BITS - 1))
| ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK)
| (significand & Self::SIGNIFICAND_MASK),
)
}
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
let shift = significand
.leading_zeros()
.wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros());
(
1i32.wrapping_sub(shift as i32),
significand << shift as Self::Int,
)
}
fn is_subnormal(self) -> bool {
(self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO
}
}
};
}

#[cfg(not(feature = "no-f16-f128"))]
float_impl!(f16, u16, i16, i8, 16, 10);
float_impl!(f32, u32, i32, i16, 32, 23);
float_impl!(f64, u64, i64, i16, 64, 52);
#[cfg(not(feature = "no-f16-f128"))]
float_impl!(f128, u128, i128, i16, 128, 112);
Loading

0 comments on commit 6736513

Please sign in to comment.