Skip to main content

cubecl_common/float/
relaxed.rs

1use core::f32;
2use core::{
3    cmp::Ordering,
4    ops::{Div, DivAssign, Mul, MulAssign, Rem, RemAssign},
5};
6
7use bytemuck::{Pod, Zeroable};
8use derive_more::derive::{
9    Add, AddAssign, Display, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
10};
11use num_traits::{Num, NumCast, One, ToPrimitive, Zero};
12
13/// A floating point type with relaxed precision, minimum [`prim@f16`], max [`prim@f32`].
14///
15#[allow(non_camel_case_types)]
16#[repr(transparent)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[derive(
19    Clone,
20    Copy,
21    Default,
22    Zeroable,
23    Pod,
24    PartialEq,
25    PartialOrd,
26    Neg,
27    Add,
28    Sub,
29    Mul,
30    Div,
31    Rem,
32    AddAssign,
33    SubAssign,
34    MulAssign,
35    DivAssign,
36    RemAssign,
37    Debug,
38    Display,
39)]
40pub struct flex32(f32);
41
42impl flex32 {
43    /// Minimum positive flex32 value
44    pub const MIN_POSITIVE: Self = Self(half::f16::MIN_POSITIVE.to_f32_const());
45
46    /// Create a `flex32` from [`prim@f32`]
47    pub const fn from_f32(val: f32) -> Self {
48        flex32(val)
49    }
50
51    /// Create a `flex32` from [`prim@f64`]
52    pub const fn from_f64(val: f64) -> Self {
53        flex32(val as f32)
54    }
55
56    /// Turn a `flex32` into [`prim@f32`]
57    pub const fn to_f32(self) -> f32 {
58        self.0
59    }
60
61    /// Turn a `flex32` into [`prim@f64`]
62    pub const fn to_f64(self) -> f64 {
63        self.0 as f64
64    }
65
66    /// Compare two flex32 numbers
67    pub fn total_cmp(&self, other: &flex32) -> Ordering {
68        self.0.total_cmp(&other.0)
69    }
70
71    /// Whether this flex32 represents `NaN`
72    pub fn is_nan(&self) -> bool {
73        self.0.is_nan()
74    }
75
76    /// Raw transmutation from `u32`.
77    pub fn from_bits(bits: u32) -> Self {
78        Self(f32::from_bits(bits))
79    }
80
81    /// Raw transmutation to `u32`.
82    pub fn to_bits(&self) -> u32 {
83        self.0.to_bits()
84    }
85}
86
87impl Mul for flex32 {
88    type Output = flex32;
89
90    fn mul(self, rhs: Self) -> Self::Output {
91        flex32(self.0 * rhs.0)
92    }
93}
94
95impl Div for flex32 {
96    type Output = flex32;
97
98    fn div(self, rhs: Self) -> Self::Output {
99        flex32(self.0 / rhs.0)
100    }
101}
102
103impl Rem for flex32 {
104    type Output = flex32;
105
106    fn rem(self, rhs: Self) -> Self::Output {
107        flex32(self.0 % rhs.0)
108    }
109}
110
111impl MulAssign for flex32 {
112    fn mul_assign(&mut self, rhs: Self) {
113        self.0 *= rhs.0;
114    }
115}
116
117impl DivAssign for flex32 {
118    fn div_assign(&mut self, rhs: Self) {
119        self.0 /= rhs.0;
120    }
121}
122
123impl RemAssign for flex32 {
124    fn rem_assign(&mut self, rhs: Self) {
125        self.0 %= rhs.0;
126    }
127}
128
129impl From<f32> for flex32 {
130    fn from(value: f32) -> Self {
131        Self::from_f32(value)
132    }
133}
134
135impl From<flex32> for f32 {
136    fn from(val: flex32) -> Self {
137        val.to_f32()
138    }
139}
140
141impl ToPrimitive for flex32 {
142    fn to_i64(&self) -> Option<i64> {
143        Some((*self).to_f32() as i64)
144    }
145
146    fn to_u64(&self) -> Option<u64> {
147        Some((*self).to_f32() as u64)
148    }
149
150    fn to_f32(&self) -> Option<f32> {
151        Some((*self).to_f32())
152    }
153
154    fn to_f64(&self) -> Option<f64> {
155        Some((*self).to_f32() as f64)
156    }
157}
158
159impl NumCast for flex32 {
160    fn from<T: num_traits::ToPrimitive>(n: T) -> Option<Self> {
161        Some(flex32::from_f32(n.to_f32()?))
162    }
163}
164
165impl num_traits::Float for flex32 {
166    fn nan() -> Self {
167        flex32(f32::nan())
168    }
169
170    fn infinity() -> Self {
171        flex32(f32::infinity())
172    }
173
174    fn neg_infinity() -> Self {
175        flex32(f32::neg_infinity())
176    }
177
178    fn neg_zero() -> Self {
179        flex32(f32::neg_zero())
180    }
181
182    fn min_value() -> Self {
183        flex32(<f32 as num_traits::Float>::min_value())
184    }
185
186    fn min_positive_value() -> Self {
187        flex32(f32::min_positive_value())
188    }
189
190    fn max_value() -> Self {
191        flex32(<f32 as num_traits::Float>::max_value())
192    }
193
194    fn is_nan(self) -> bool {
195        self.0.is_nan()
196    }
197
198    fn is_infinite(self) -> bool {
199        self.0.is_infinite()
200    }
201
202    fn is_finite(self) -> bool {
203        self.0.is_finite()
204    }
205
206    fn is_normal(self) -> bool {
207        self.0.is_normal()
208    }
209
210    fn classify(self) -> core::num::FpCategory {
211        self.0.classify()
212    }
213
214    fn floor(self) -> Self {
215        flex32(self.0.floor())
216    }
217
218    fn ceil(self) -> Self {
219        flex32(self.0.ceil())
220    }
221
222    fn round(self) -> Self {
223        flex32(self.0.round())
224    }
225
226    fn trunc(self) -> Self {
227        flex32(self.0.trunc())
228    }
229
230    fn fract(self) -> Self {
231        flex32(self.0.fract())
232    }
233
234    fn abs(self) -> Self {
235        flex32(self.0.abs())
236    }
237
238    fn signum(self) -> Self {
239        flex32(self.0.signum())
240    }
241
242    fn is_sign_positive(self) -> bool {
243        self.0.is_sign_positive()
244    }
245
246    fn is_sign_negative(self) -> bool {
247        self.0.is_sign_negative()
248    }
249
250    fn mul_add(self, a: Self, b: Self) -> Self {
251        flex32(self.0.mul_add(a.0, b.0))
252    }
253
254    fn recip(self) -> Self {
255        flex32(self.0.recip())
256    }
257
258    fn powi(self, n: i32) -> Self {
259        flex32(self.0.powi(n))
260    }
261
262    fn powf(self, n: Self) -> Self {
263        flex32(self.0.powf(n.0))
264    }
265
266    fn sqrt(self) -> Self {
267        flex32(self.0.sqrt())
268    }
269
270    fn exp(self) -> Self {
271        flex32(self.0.exp())
272    }
273
274    fn exp2(self) -> Self {
275        flex32(self.0.exp2())
276    }
277
278    fn ln(self) -> Self {
279        flex32(self.0.ln())
280    }
281
282    fn log(self, base: Self) -> Self {
283        flex32(self.0.log(base.0))
284    }
285
286    fn log2(self) -> Self {
287        flex32(self.0.log2())
288    }
289
290    fn log10(self) -> Self {
291        flex32(self.0.log10())
292    }
293
294    fn max(self, other: Self) -> Self {
295        flex32(self.0.max(other.0))
296    }
297
298    fn min(self, other: Self) -> Self {
299        flex32(self.0.min(other.0))
300    }
301
302    fn abs_sub(self, other: Self) -> Self {
303        flex32((self.0 - other.0).abs())
304    }
305
306    fn cbrt(self) -> Self {
307        flex32(self.0.cbrt())
308    }
309
310    fn hypot(self, other: Self) -> Self {
311        flex32(self.0.hypot(other.0))
312    }
313
314    fn sin(self) -> Self {
315        flex32(self.0.sin())
316    }
317
318    fn cos(self) -> Self {
319        flex32(self.0.cos())
320    }
321
322    fn tan(self) -> Self {
323        flex32(self.0.tan())
324    }
325
326    fn asin(self) -> Self {
327        flex32(self.0.asin())
328    }
329
330    fn acos(self) -> Self {
331        flex32(self.0.acos())
332    }
333
334    fn atan(self) -> Self {
335        flex32(self.0.atan())
336    }
337
338    fn atan2(self, other: Self) -> Self {
339        flex32(self.0.atan2(other.0))
340    }
341
342    fn sin_cos(self) -> (Self, Self) {
343        let (a, b) = self.0.sin_cos();
344        (flex32(a), flex32(b))
345    }
346
347    fn exp_m1(self) -> Self {
348        flex32(self.0.exp_m1())
349    }
350
351    fn ln_1p(self) -> Self {
352        flex32(self.0.ln_1p())
353    }
354
355    fn sinh(self) -> Self {
356        flex32(self.0.sinh())
357    }
358
359    fn cosh(self) -> Self {
360        flex32(self.0.cosh())
361    }
362
363    fn tanh(self) -> Self {
364        flex32(self.0.tanh())
365    }
366
367    fn asinh(self) -> Self {
368        flex32(self.0.asinh())
369    }
370
371    fn acosh(self) -> Self {
372        flex32(self.0.acosh())
373    }
374
375    fn atanh(self) -> Self {
376        flex32(self.0.atanh())
377    }
378
379    fn integer_decode(self) -> (u64, i16, i8) {
380        self.0.integer_decode()
381    }
382
383    fn epsilon() -> Self {
384        Self::from_f32(half::f16::EPSILON.to_f32())
385    }
386}
387
388impl Num for flex32 {
389    type FromStrRadixErr = <f32 as Num>::FromStrRadixErr;
390
391    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
392        Ok(flex32(f32::from_str_radix(str, radix)?))
393    }
394}
395
396impl One for flex32 {
397    fn one() -> Self {
398        flex32(1.0)
399    }
400}
401
402impl Zero for flex32 {
403    fn zero() -> Self {
404        flex32(0.0)
405    }
406
407    fn is_zero(&self) -> bool {
408        self.0 == 0.0
409    }
410}