cubecl_common/float/
relaxed.rs1use 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#[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 pub const MIN_POSITIVE: Self = Self(half::f16::MIN_POSITIVE.to_f32_const());
46
47 pub const fn from_f32(val: f32) -> Self {
49 flex32(val)
50 }
51
52 pub const fn from_f64(val: f64) -> Self {
54 flex32(val as f32)
55 }
56
57 pub const fn to_f32(self) -> f32 {
59 self.0
60 }
61
62 pub const fn to_f64(self) -> f64 {
64 self.0 as f64
65 }
66
67 pub fn total_cmp(&self, other: &flex32) -> Ordering {
69 self.0.total_cmp(&other.0)
70 }
71
72 pub fn is_nan(&self) -> bool {
74 self.0.is_nan()
75 }
76
77 pub fn from_bits(bits: u32) -> Self {
79 Self(f32::from_bits(bits))
80 }
81
82 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}