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