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)]
9pub struct Uf64E11M52(u64);
11
12pub 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}