Skip to main content

cubecl_common/float/
relaxed.rs

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