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