Skip to content

Commit 2809ddf

Browse files
committed
Move some numeric trait logic to default implementations
There are a handful of functions we can move out of the macro and to the numeric traits as default implementations; do that here. Additionally, add some bounds that make sense for completeness.
1 parent 523c8ca commit 2809ddf

File tree

3 files changed

+67
-48
lines changed

3 files changed

+67
-48
lines changed

crates/libm-test/src/test_traits.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ where
314314
// Make sure that the signs are the same before checing ULP to avoid wraparound
315315
let act_sig = actual.signum();
316316
let exp_sig = expected.signum();
317-
ensure!(act_sig == exp_sig, "mismatched signs {act_sig} {exp_sig}");
317+
ensure!(act_sig == exp_sig, "mismatched signs {act_sig:?} {exp_sig:?}");
318318

319319
if actual.is_infinite() ^ expected.is_infinite() {
320320
bail!("mismatched infinities");

src/math/support/float_traits.rs

+60-46
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::{fmt, ops};
1+
use core::{fmt, mem, ops};
22

33
use super::int_traits::{Int, MinInt};
44

@@ -7,15 +7,17 @@ use super::int_traits::{Int, MinInt};
77
pub trait Float:
88
Copy
99
+ fmt::Debug
10-
+ fmt::Display
1110
+ PartialEq
1211
+ PartialOrd
1312
+ ops::AddAssign
1413
+ ops::MulAssign
1514
+ ops::Add<Output = Self>
1615
+ ops::Sub<Output = Self>
16+
+ ops::Mul<Output = Self>
1717
+ ops::Div<Output = Self>
1818
+ ops::Rem<Output = Self>
19+
+ ops::Neg<Output = Self>
20+
+ 'static
1921
{
2022
/// A uint of the same width as the float
2123
type Int: Int<OtherSign = Self::SignedInt, Unsigned = Self::Int>;
@@ -27,11 +29,16 @@ pub trait Float:
2729
type ExpInt: Int;
2830

2931
const ZERO: Self;
32+
const NEG_ZERO: Self;
3033
const ONE: Self;
3134
const NEG_ONE: Self;
3235
const INFINITY: Self;
3336
const NEG_INFINITY: Self;
3437
const NAN: Self;
38+
const MAX: Self;
39+
const MIN: Self;
40+
const PI: Self;
41+
const FRAC_PI_2: Self;
3542

3643
/// The bitwidth of the float type
3744
const BITS: u32;
@@ -69,7 +76,19 @@ pub trait Float:
6976
/// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
7077
/// represented in multiple different ways. This method returns `true` if two NaNs are
7178
/// compared.
72-
fn eq_repr(self, rhs: Self) -> bool;
79+
fn eq_repr(self, rhs: Self) -> bool {
80+
let is_nan = |x: Self| -> bool {
81+
// }
82+
// fn is_nan(x: Self) -> bool {
83+
// When using mangled-names, the "real" compiler-builtins might not have the
84+
// necessary builtin (__unordtf2) to test whether `f128` is NaN.
85+
// FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin
86+
// x is NaN if all the bits of the exponent are set and the significand is non-0
87+
x.to_bits() & Self::EXP_MASK == Self::EXP_MASK
88+
&& x.to_bits() & Self::SIG_MASK != Self::Int::ZERO
89+
};
90+
if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() }
91+
}
7392

7493
/// Returns true if the value is NaN.
7594
fn is_nan(self) -> bool;
@@ -81,22 +100,35 @@ pub trait Float:
81100
fn is_sign_negative(self) -> bool;
82101

83102
/// Returns if `self` is subnormal
84-
fn is_subnormal(self) -> bool;
103+
fn is_subnormal(self) -> bool {
104+
(self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO
105+
}
85106

86107
/// Returns the exponent, not adjusting for bias.
87108
fn exp(self) -> Self::ExpInt;
88109

89110
/// Returns the significand with no implicit bit (or the "fractional" part)
90-
fn frac(self) -> Self::Int;
111+
fn frac(self) -> Self::Int {
112+
self.to_bits() & Self::SIG_MASK
113+
}
91114

92115
/// Returns the significand with implicit bit
93-
fn imp_frac(self) -> Self::Int;
116+
fn imp_frac(self) -> Self::Int {
117+
self.frac() | Self::IMPLICIT_BIT
118+
}
94119

95120
/// Returns a `Self::Int` transmuted back to `Self`
96121
fn from_bits(a: Self::Int) -> Self;
97122

98123
/// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position.
99-
fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self;
124+
fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self {
125+
let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO };
126+
Self::from_bits(
127+
(sign << (Self::BITS - 1))
128+
| ((exponent << Self::SIG_BITS) & Self::EXP_MASK)
129+
| (significand & Self::SIG_MASK),
130+
)
131+
}
100132

101133
fn abs(self) -> Self {
102134
let abs_mask = !Self::SIGN_MASK;
@@ -107,10 +139,18 @@ pub trait Float:
107139
fn normalize(significand: Self::Int) -> (i32, Self::Int);
108140

109141
/// Returns a number composed of the magnitude of self and the sign of sign.
110-
fn copysign(self, other: Self) -> Self;
142+
fn copysign(self, other: Self) -> Self {
143+
let mut x = self.to_bits();
144+
let y = other.to_bits();
145+
x &= !Self::SIGN_MASK;
146+
x |= y & Self::SIGN_MASK;
147+
Self::from_bits(x)
148+
}
111149

112150
/// Returns a number that represents the sign of self.
113-
fn signum(self) -> Self;
151+
fn signum(self) -> Self {
152+
if self.is_nan() { self } else { Self::ONE.copysign(self) }
153+
}
114154
}
115155

116156
macro_rules! float_impl {
@@ -121,11 +161,22 @@ macro_rules! float_impl {
121161
type ExpInt = $expty;
122162

123163
const ZERO: Self = 0.0;
164+
const NEG_ZERO: Self = -0.0;
124165
const ONE: Self = 1.0;
125166
const NEG_ONE: Self = -1.0;
126167
const INFINITY: Self = Self::INFINITY;
127168
const NEG_INFINITY: Self = Self::NEG_INFINITY;
128169
const NAN: Self = Self::NAN;
170+
const MAX: Self = -Self::MIN;
171+
// Sign bit set, saturated mantissa, saturated exponent with last bit zeroed
172+
// FIXME(msrv): just use `from_bits` when available
173+
// SAFETY: POD cast with no preconditions
174+
const MIN: Self = unsafe {
175+
mem::transmute::<Self::Int, Self>(Self::Int::MAX & !(1 << Self::SIG_BITS))
176+
};
177+
178+
const PI: Self = core::$ty::consts::PI;
179+
const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2;
129180

130181
const BITS: u32 = $bits;
131182
const SIG_BITS: u32 = $significand_bits;
@@ -141,16 +192,6 @@ macro_rules! float_impl {
141192
fn to_bits_signed(self) -> Self::SignedInt {
142193
self.to_bits() as Self::SignedInt
143194
}
144-
fn eq_repr(self, rhs: Self) -> bool {
145-
fn is_nan(x: $ty) -> bool {
146-
// When using mangled-names, the "real" compiler-builtins might not have the
147-
// necessary builtin (__unordtf2) to test whether `f128` is NaN.
148-
// FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin
149-
// x is NaN if all the bits of the exponent are set and the significand is non-0
150-
x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0
151-
}
152-
if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() }
153-
}
154195
fn is_nan(self) -> bool {
155196
self.is_nan()
156197
}
@@ -160,43 +201,16 @@ macro_rules! float_impl {
160201
fn is_sign_negative(self) -> bool {
161202
self.is_sign_negative()
162203
}
163-
fn is_subnormal(self) -> bool {
164-
(self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO
165-
}
166204
fn exp(self) -> Self::ExpInt {
167205
((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt
168206
}
169-
fn frac(self) -> Self::Int {
170-
self.to_bits() & Self::SIG_MASK
171-
}
172-
fn imp_frac(self) -> Self::Int {
173-
self.frac() | Self::IMPLICIT_BIT
174-
}
175207
fn from_bits(a: Self::Int) -> Self {
176208
Self::from_bits(a)
177209
}
178-
fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self {
179-
Self::from_bits(
180-
((negative as Self::Int) << (Self::BITS - 1))
181-
| ((exponent << Self::SIG_BITS) & Self::EXP_MASK)
182-
| (significand & Self::SIG_MASK),
183-
)
184-
}
185210
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
186211
let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS);
187212
(1i32.wrapping_sub(shift as i32), significand << shift as Self::Int)
188213
}
189-
fn copysign(self, other: Self) -> Self {
190-
let mut x = self.to_bits();
191-
let y = other.to_bits();
192-
x &= !Self::SIGN_MASK;
193-
x |= y & Self::SIGN_MASK;
194-
Self::from_bits(x)
195-
}
196-
197-
fn signum(self) -> Self {
198-
if self.is_nan() { self } else { Self::ONE.copysign(self) }
199-
}
200214
}
201215
};
202216
}

src/math/support/int_traits.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::{fmt, ops};
1+
use core::{cmp, fmt, ops};
22

33
/// Minimal integer implementations needed on all integer types, including wide integers.
44
#[allow(dead_code)]
@@ -31,6 +31,8 @@ pub trait MinInt:
3131
pub trait Int:
3232
MinInt
3333
+ fmt::Display
34+
+ fmt::Binary
35+
+ fmt::LowerHex
3436
+ PartialEq
3537
+ PartialOrd
3638
+ ops::AddAssign
@@ -47,6 +49,9 @@ pub trait Int:
4749
+ ops::Shr<u32, Output = Self>
4850
+ ops::BitXor<Output = Self>
4951
+ ops::BitAnd<Output = Self>
52+
+ cmp::Ord
53+
+ CastInto<usize>
54+
+ CastFrom<u8>
5055
{
5156
fn signed(self) -> <Self::Unsigned as MinInt>::OtherSign;
5257
fn unsigned(self) -> Self::Unsigned;

0 commit comments

Comments
 (0)