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