Skip to main content

unsigned_float/
uf64.rs

1use core::cmp::Ordering;
2use core::fmt;
3use core::ops::{Add, Div, Mul, Sub};
4
5use crate::{ConversionError, dispatch};
6
7macro_rules! impl_float_format {
8    ($ty:ty, $to_float:ident) => {
9        impl fmt::Display for $ty {
10            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11                fmt::Display::fmt(&self.$to_float(), f)
12            }
13        }
14
15        impl fmt::LowerExp for $ty {
16            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17                fmt::LowerExp::fmt(&self.$to_float(), f)
18            }
19        }
20
21        impl fmt::UpperExp for $ty {
22            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23                fmt::UpperExp::fmt(&self.$to_float(), f)
24            }
25        }
26    };
27}
28
29#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
30#[repr(transparent)]
31/// A 64-bit unsigned float with 11 exponent bits and 52 mantissa bits.
32pub struct Uf64E11M52(u64);
33
34/// Default 64-bit unsigned float layout. Requires the `f128` feature.
35pub type Uf64 = Uf64E11M52;
36
37impl Uf64E11M52 {
38    pub const EXPONENT_BITS: u32 = 11;
39    pub const MANTISSA_BITS: u32 = 52;
40    pub const EXPONENT_BIAS: i32 = 1023;
41    pub const EXPONENT_MASK: u64 = 0x7ff0_0000_0000_0000;
42    pub const MANTISSA_MASK: u64 = 0x000f_ffff_ffff_ffff;
43
44    pub const ZERO: Self = Self(0);
45    pub const ONE: Self = Self(0x3ff0_0000_0000_0000);
46    pub const INFINITY: Self = Self(0x7ff0_0000_0000_0000);
47    pub const NAN: Self = Self(0x7ff8_0000_0000_0000);
48    pub const MAX: Self = Self(0x7fef_ffff_ffff_ffff);
49    pub const MIN_POSITIVE: Self = Self(0x0000_0000_0000_0001);
50    pub const MIN_NORMAL: Self = Self(0x0010_0000_0000_0000);
51
52    pub const fn from_bits(bits: u64) -> Self {
53        Self(bits)
54    }
55
56    pub const fn to_bits(self) -> u64 {
57        self.0
58    }
59
60    pub fn from_f128(value: f128) -> Self {
61        Self(dispatch::f128_to_uf64(value))
62    }
63
64    pub fn to_f128(self) -> f128 {
65        dispatch::uf64_to_f128(self.0)
66    }
67
68    pub fn try_from_f128(value: f128) -> Result<Self, ConversionError> {
69        if value.is_nan() {
70            return Err(ConversionError::Nan);
71        }
72        if value.is_infinite() {
73            return Err(ConversionError::Infinite);
74        }
75        if value < 0.0_f128 {
76            return Err(ConversionError::Negative);
77        }
78
79        let encoded = Self::from_f128(value);
80        if encoded.is_infinite() {
81            Err(ConversionError::Overflow)
82        } else if value != 0.0_f128 && encoded.is_zero() {
83            Err(ConversionError::Underflow)
84        } else {
85            Ok(encoded)
86        }
87    }
88
89    pub fn from_f64(value: f64) -> Self {
90        Self::from_f128(value as f128)
91    }
92
93    pub fn to_f64(self) -> f64 {
94        self.to_f128() as f64
95    }
96
97    pub fn try_from_f64(value: f64) -> Result<Self, ConversionError> {
98        crate::convert::check_finite_non_negative(value)?;
99
100        let encoded = Self::from_f64(value);
101        crate::convert::check_encoded(value, encoded.is_zero(), encoded.is_infinite())?;
102
103        Ok(encoded)
104    }
105
106    pub fn from_f32(value: f32) -> Self {
107        Self::from_f128(value as f128)
108    }
109
110    pub fn to_f32(self) -> f32 {
111        self.to_f128() as f32
112    }
113
114    #[cfg(feature = "f16")]
115    pub fn from_f16(value: f16) -> Self {
116        Self::from_f128(value as f128)
117    }
118
119    #[cfg(feature = "f16")]
120    pub fn to_f16(self) -> f16 {
121        self.to_f128() as f16
122    }
123
124    pub const fn exponent(self) -> u64 {
125        (self.0 & Self::EXPONENT_MASK) >> Self::MANTISSA_BITS
126    }
127
128    pub const fn mantissa(self) -> u64 {
129        self.0 & Self::MANTISSA_MASK
130    }
131
132    pub const fn is_zero(self) -> bool {
133        self.0 == 0
134    }
135
136    pub const fn is_nan(self) -> bool {
137        self.exponent() == 0x7ff && self.mantissa() != 0
138    }
139
140    pub const fn is_infinite(self) -> bool {
141        self.0 == Self::INFINITY.0
142    }
143
144    pub const fn is_finite(self) -> bool {
145        self.exponent() != 0x7ff
146    }
147
148    pub const fn is_subnormal(self) -> bool {
149        self.exponent() == 0 && self.mantissa() != 0
150    }
151}
152
153impl From<f32> for Uf64E11M52 {
154    fn from(value: f32) -> Self {
155        Self::from_f32(value)
156    }
157}
158
159impl From<f64> for Uf64E11M52 {
160    fn from(value: f64) -> Self {
161        Self::from_f64(value)
162    }
163}
164
165#[cfg(feature = "f16")]
166impl From<f16> for Uf64E11M52 {
167    fn from(value: f16) -> Self {
168        Self::from_f16(value)
169    }
170}
171
172#[cfg(feature = "f16")]
173impl From<Uf64E11M52> for f16 {
174    fn from(value: Uf64E11M52) -> Self {
175        value.to_f16()
176    }
177}
178
179impl From<Uf64E11M52> for f32 {
180    fn from(value: Uf64E11M52) -> Self {
181        value.to_f32()
182    }
183}
184
185impl From<Uf64E11M52> for f64 {
186    fn from(value: Uf64E11M52) -> Self {
187        value.to_f64()
188    }
189}
190
191impl From<Uf64E11M52> for f128 {
192    fn from(value: Uf64E11M52) -> Self {
193        value.to_f128()
194    }
195}
196
197impl TryFrom<f128> for Uf64E11M52 {
198    type Error = ConversionError;
199
200    fn try_from(value: f128) -> Result<Self, Self::Error> {
201        Self::try_from_f128(value)
202    }
203}
204
205impl Ord for Uf64E11M52 {
206    fn cmp(&self, other: &Self) -> Ordering {
207        self.0.cmp(&other.0)
208    }
209}
210
211impl PartialOrd for Uf64E11M52 {
212    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
213        Some(self.cmp(other))
214    }
215}
216
217impl Add for Uf64E11M52 {
218    type Output = Self;
219
220    fn add(self, rhs: Self) -> Self::Output {
221        Self(dispatch::add_uf64(self.0, rhs.0))
222    }
223}
224
225impl Sub for Uf64E11M52 {
226    type Output = Self;
227
228    fn sub(self, rhs: Self) -> Self::Output {
229        Self(dispatch::sub_uf64(self.0, rhs.0))
230    }
231}
232
233impl Mul for Uf64E11M52 {
234    type Output = Self;
235
236    fn mul(self, rhs: Self) -> Self::Output {
237        Self(dispatch::mul_uf64(self.0, rhs.0))
238    }
239}
240
241impl Div for Uf64E11M52 {
242    type Output = Self;
243
244    fn div(self, rhs: Self) -> Self::Output {
245        Self(dispatch::div_uf64(self.0, rhs.0))
246    }
247}
248
249impl fmt::Debug for Uf64E11M52 {
250    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251        f.debug_tuple("Uf64E11M52").field(&self.to_f64()).finish()
252    }
253}
254
255impl_float_format!(Uf64E11M52, to_f64);