Update libm Float and Int with functions from the test traits

The test versions of `Float` and `Int` have a few more methods and
constants availablee. Update the in `libm` with everything missing from
`libm_test` so we will be able to merge these.
This commit is contained in:
Trevor Gross 2024-10-31 23:47:41 -05:00 committed by Trevor Gross
parent 4c1772ed85
commit 5f54ad6389
2 changed files with 77 additions and 16 deletions

View file

@ -1,4 +1,4 @@
use core::ops;
use core::{fmt, ops};
use super::int_traits::{Int, MinInt};
@ -6,7 +6,8 @@ use super::int_traits::{Int, MinInt};
#[allow(dead_code)]
pub trait Float:
Copy
+ core::fmt::Debug
+ fmt::Debug
+ fmt::Display
+ PartialEq
+ PartialOrd
+ ops::AddAssign
@ -17,16 +18,17 @@ pub trait Float:
+ ops::Rem<Output = Self>
{
/// A uint of the same width as the float
type Int: Int<OtherSign = Self::SignedInt, UnsignedInt = Self::Int>;
type Int: Int<OtherSign = Self::SignedInt, Unsigned = Self::Int>;
/// A int of the same width as the float
type SignedInt: Int + MinInt<OtherSign = Self::Int, UnsignedInt = Self::Int>;
type SignedInt: Int + MinInt<OtherSign = Self::Int, Unsigned = Self::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;
const NEG_ONE: Self;
const INFINITY: Self;
const NEG_INFINITY: Self;
const NAN: Self;
@ -69,9 +71,18 @@ pub trait Float:
/// compared.
fn eq_repr(self, rhs: Self) -> bool;
/// Returns true if the sign is negative
/// Returns true if the value is NaN.
fn is_nan(self) -> bool;
/// Returns true if the value is +inf or -inf.
fn is_infinite(self) -> bool;
/// Returns true if the sign is negative.
fn is_sign_negative(self) -> bool;
/// Returns if `self` is subnormal
fn is_subnormal(self) -> bool;
/// Returns the exponent, not adjusting for bias.
fn exp(self) -> Self::ExpInt;
@ -95,8 +106,11 @@ pub trait Float:
/// Returns (normalized exponent, normalized significand)
fn normalize(significand: Self::Int) -> (i32, Self::Int);
/// Returns if `self` is subnormal
fn is_subnormal(self) -> bool;
/// Returns a number composed of the magnitude of self and the sign of sign.
fn copysign(self, other: Self) -> Self;
/// Returns a number that represents the sign of self.
fn signum(self) -> Self;
}
macro_rules! float_impl {
@ -108,6 +122,7 @@ macro_rules! float_impl {
const ZERO: Self = 0.0;
const ONE: Self = 1.0;
const NEG_ONE: Self = -1.0;
const INFINITY: Self = Self::INFINITY;
const NEG_INFINITY: Self = Self::NEG_INFINITY;
const NAN: Self = Self::NAN;
@ -136,9 +151,18 @@ macro_rules! float_impl {
}
if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() }
}
fn is_nan(self) -> bool {
self.is_nan()
}
fn is_infinite(self) -> bool {
self.is_infinite()
}
fn is_sign_negative(self) -> bool {
self.is_sign_negative()
}
fn is_subnormal(self) -> bool {
(self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO
}
fn exp(self) -> Self::ExpInt {
((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt
}
@ -162,8 +186,16 @@ macro_rules! float_impl {
let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS);
(1i32.wrapping_sub(shift as i32), significand << shift as Self::Int)
}
fn is_subnormal(self) -> bool {
(self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO
fn copysign(self, other: Self) -> Self {
let mut x = self.to_bits();
let y = other.to_bits();
x &= !Self::SIGN_MASK;
x |= y & Self::SIGN_MASK;
Self::from_bits(x)
}
fn signum(self) -> Self {
if self.is_nan() { self } else { Self::ONE.copysign(self) }
}
}
};

View file

@ -12,7 +12,7 @@ pub trait MinInt:
/// Type with the same width but other signedness
type OtherSign: MinInt;
/// Unsigned version of Self
type UnsignedInt: MinInt;
type Unsigned: MinInt;
/// If `Self` is a signed integer
const SIGNED: bool;
@ -30,6 +30,7 @@ pub trait MinInt:
#[allow(dead_code)]
pub trait Int:
MinInt
+ fmt::Display
+ PartialEq
+ PartialOrd
+ ops::AddAssign
@ -47,8 +48,10 @@ pub trait Int:
+ ops::BitXor<Output = Self>
+ ops::BitAnd<Output = Self>
{
fn unsigned(self) -> Self::UnsignedInt;
fn from_unsigned(unsigned: Self::UnsignedInt) -> Self;
fn signed(self) -> <Self::Unsigned as MinInt>::OtherSign;
fn unsigned(self) -> Self::Unsigned;
fn from_unsigned(unsigned: Self::Unsigned) -> Self;
fn abs(self) -> Self;
fn from_bool(b: bool) -> Self;
@ -56,10 +59,12 @@ pub trait Int:
fn logical_shr(self, other: u32) -> Self;
/// Absolute difference between two integers.
fn abs_diff(self, other: Self) -> Self::UnsignedInt;
fn abs_diff(self, other: Self) -> Self::Unsigned;
// copied from primitive integers, but put in a trait
fn is_zero(self) -> bool;
fn checked_add(self, other: Self) -> Option<Self>;
fn checked_sub(self, other: Self) -> Option<Self>;
fn wrapping_neg(self) -> Self;
fn wrapping_add(self, other: Self) -> Self;
fn wrapping_mul(self, other: Self) -> Self;
@ -86,6 +91,14 @@ macro_rules! int_impl_common {
self == Self::ZERO
}
fn checked_add(self, other: Self) -> Option<Self> {
self.checked_add(other)
}
fn checked_sub(self, other: Self) -> Option<Self> {
self.checked_sub(other)
}
fn wrapping_neg(self) -> Self {
<Self>::wrapping_neg(self)
}
@ -132,7 +145,7 @@ macro_rules! int_impl {
($ity:ty, $uty:ty) => {
impl MinInt for $uty {
type OtherSign = $ity;
type UnsignedInt = $uty;
type Unsigned = $uty;
const BITS: u32 = <Self as MinInt>::ZERO.count_zeros();
const SIGNED: bool = Self::MIN != Self::ZERO;
@ -144,10 +157,18 @@ macro_rules! int_impl {
}
impl Int for $uty {
fn unsigned(self) -> $uty {
fn signed(self) -> $ity {
self as $ity
}
fn unsigned(self) -> Self {
self
}
fn abs(self) -> Self {
unimplemented!()
}
// It makes writing macros easier if this is implemented for both signed and unsigned
#[allow(clippy::wrong_self_convention)]
fn from_unsigned(me: $uty) -> Self {
@ -163,7 +184,7 @@ macro_rules! int_impl {
impl MinInt for $ity {
type OtherSign = $uty;
type UnsignedInt = $uty;
type Unsigned = $uty;
const BITS: u32 = <Self as MinInt>::ZERO.count_zeros();
const SIGNED: bool = Self::MIN != Self::ZERO;
@ -175,10 +196,18 @@ macro_rules! int_impl {
}
impl Int for $ity {
fn signed(self) -> Self {
self
}
fn unsigned(self) -> $uty {
self as $uty
}
fn abs(self) -> Self {
self.abs()
}
fn from_unsigned(me: $uty) -> Self {
me as $ity
}