1use super::*;
2
3pick! {
4 if #[cfg(target_feature="sse")] {
5 #[derive(Default, Clone, Copy, PartialEq)]
6 #[repr(C, align(16))]
7 pub struct f32x4 { pub(crate) sse: m128 }
8 } else if #[cfg(target_feature="simd128")] {
9 use core::arch::wasm32::*;
10
11 #[derive(Clone, Copy)]
12 #[repr(transparent)]
13 pub struct f32x4 { pub(crate) simd: v128 }
14
15 impl Default for f32x4 {
16 fn default() -> Self {
17 Self::splat(0.0)
18 }
19 }
20
21 impl PartialEq for f32x4 {
22 fn eq(&self, other: &Self) -> bool {
23 u32x4_all_true(f32x4_eq(self.simd, other.simd))
24 }
25 }
26 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
27 use core::arch::aarch64::*;
28 #[repr(C)]
29 #[derive(Copy, Clone)]
30 pub struct f32x4 { pub(crate) neon : float32x4_t }
31
32 impl Default for f32x4 {
33 #[inline]
34 fn default() -> Self {
35 unsafe { Self { neon: vdupq_n_f32(0.0)} }
36 }
37 }
38
39 impl PartialEq for f32x4 {
40 #[inline]
41 fn eq(&self, other: &Self) -> bool {
42 unsafe { vminvq_u32(vceqq_f32(self.neon, other.neon))==u32::MAX }
43 }
44
45 }
46 } else {
47 #[derive(Default, Clone, Copy, PartialEq)]
48 #[repr(C, align(16))]
49 pub struct f32x4 { pub(crate) arr: [f32;4] }
50 }
51}
52
53macro_rules! const_f32_as_f32x4 {
54 ($i:ident, $f:expr) => {
55 #[allow(non_upper_case_globals)]
56 pub const $i: f32x4 = f32x4::new([$f; 4]);
57 };
58}
59
60impl f32x4 {
61 const_f32_as_f32x4!(ONE, 1.0);
62 const_f32_as_f32x4!(ZERO, 0.0);
63 const_f32_as_f32x4!(HALF, 0.5);
64 const_f32_as_f32x4!(EPSILON, f32::EPSILON);
65 const_f32_as_f32x4!(MIN, f32::MIN);
66 const_f32_as_f32x4!(MIN_POSITIVE, f32::MIN_POSITIVE);
67 const_f32_as_f32x4!(MAX, f32::MAX);
68 const_f32_as_f32x4!(NAN, f32::NAN);
69 const_f32_as_f32x4!(INFINITY, f32::INFINITY);
70 const_f32_as_f32x4!(NEG_INFINITY, f32::NEG_INFINITY);
71 const_f32_as_f32x4!(E, core::f32::consts::E);
72 const_f32_as_f32x4!(FRAC_1_PI, core::f32::consts::FRAC_1_PI);
73 const_f32_as_f32x4!(FRAC_2_PI, core::f32::consts::FRAC_2_PI);
74 const_f32_as_f32x4!(FRAC_2_SQRT_PI, core::f32::consts::FRAC_2_SQRT_PI);
75 const_f32_as_f32x4!(FRAC_1_SQRT_2, core::f32::consts::FRAC_1_SQRT_2);
76 const_f32_as_f32x4!(FRAC_PI_2, core::f32::consts::FRAC_PI_2);
77 const_f32_as_f32x4!(FRAC_PI_3, core::f32::consts::FRAC_PI_3);
78 const_f32_as_f32x4!(FRAC_PI_4, core::f32::consts::FRAC_PI_4);
79 const_f32_as_f32x4!(FRAC_PI_6, core::f32::consts::FRAC_PI_6);
80 const_f32_as_f32x4!(FRAC_PI_8, core::f32::consts::FRAC_PI_8);
81 const_f32_as_f32x4!(LN_2, core::f32::consts::LN_2);
82 const_f32_as_f32x4!(LN_10, core::f32::consts::LN_10);
83 const_f32_as_f32x4!(LOG2_E, core::f32::consts::LOG2_E);
84 const_f32_as_f32x4!(LOG10_E, core::f32::consts::LOG10_E);
85 const_f32_as_f32x4!(LOG10_2, core::f32::consts::LOG10_2);
86 const_f32_as_f32x4!(LOG2_10, core::f32::consts::LOG2_10);
87 const_f32_as_f32x4!(PI, core::f32::consts::PI);
88 const_f32_as_f32x4!(SQRT_2, core::f32::consts::SQRT_2);
89 const_f32_as_f32x4!(TAU, core::f32::consts::TAU);
90}
91
92unsafe impl Zeroable for f32x4 {}
93unsafe impl Pod for f32x4 {}
94
95impl AlignTo for f32x4 {
96 type Elem = f32;
97}
98
99impl Add for f32x4 {
100 type Output = Self;
101 #[inline]
102 fn add(self, rhs: Self) -> Self::Output {
103 pick! {
104 if #[cfg(target_feature="sse")] {
105 Self { sse: add_m128(self.sse, rhs.sse) }
106 } else if #[cfg(target_feature="simd128")] {
107 Self { simd: f32x4_add(self.simd, rhs.simd) }
108 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
109 unsafe { Self { neon: vaddq_f32(self.neon, rhs.neon) } }
110 } else {
111 Self { arr: [
112 self.arr[0] + rhs.arr[0],
113 self.arr[1] + rhs.arr[1],
114 self.arr[2] + rhs.arr[2],
115 self.arr[3] + rhs.arr[3],
116 ]}
117 }
118 }
119 }
120}
121
122impl Sub for f32x4 {
123 type Output = Self;
124 #[inline]
125 fn sub(self, rhs: Self) -> Self::Output {
126 pick! {
127 if #[cfg(target_feature="sse")] {
128 Self { sse: sub_m128(self.sse, rhs.sse) }
129 } else if #[cfg(target_feature="simd128")] {
130 Self { simd: f32x4_sub(self.simd, rhs.simd) }
131 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
132 unsafe {Self { neon: vsubq_f32(self.neon, rhs.neon) }}
133 } else {
134 Self { arr: [
135 self.arr[0] - rhs.arr[0],
136 self.arr[1] - rhs.arr[1],
137 self.arr[2] - rhs.arr[2],
138 self.arr[3] - rhs.arr[3],
139 ]}
140 }
141 }
142 }
143}
144
145impl Mul for f32x4 {
146 type Output = Self;
147 #[inline]
148 fn mul(self, rhs: Self) -> Self::Output {
149 pick! {
150 if #[cfg(target_feature="sse")] {
151 Self { sse: mul_m128(self.sse, rhs.sse) }
152 } else if #[cfg(target_feature="simd128")] {
153 Self { simd: f32x4_mul(self.simd, rhs.simd) }
154 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
155 unsafe {Self { neon: vmulq_f32(self.neon, rhs.neon) }}
156 } else {
157 Self { arr: [
158 self.arr[0] * rhs.arr[0],
159 self.arr[1] * rhs.arr[1],
160 self.arr[2] * rhs.arr[2],
161 self.arr[3] * rhs.arr[3],
162 ]}
163 }
164 }
165 }
166}
167
168impl Div for f32x4 {
169 type Output = Self;
170 #[inline]
171 fn div(self, rhs: Self) -> Self::Output {
172 pick! {
173 if #[cfg(target_feature="sse")] {
174 Self { sse: div_m128(self.sse, rhs.sse) }
175 } else if #[cfg(target_feature="simd128")] {
176 Self { simd: f32x4_div(self.simd, rhs.simd) }
177 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
178 unsafe {Self { neon: vdivq_f32(self.neon, rhs.neon) }}
179 } else {
180 Self { arr: [
181 self.arr[0] / rhs.arr[0],
182 self.arr[1] / rhs.arr[1],
183 self.arr[2] / rhs.arr[2],
184 self.arr[3] / rhs.arr[3],
185 ]}
186 }
187 }
188 }
189}
190
191impl Rem for f32x4 {
192 type Output = Self;
193 #[inline]
194 fn rem(self, rhs: Self) -> Self::Output {
195 Self::new([
196 self.to_array()[0] % rhs.to_array()[0],
197 self.to_array()[1] % rhs.to_array()[1],
198 self.to_array()[2] % rhs.to_array()[2],
199 self.to_array()[3] % rhs.to_array()[3],
200 ])
201 }
202}
203
204impl Neg for f32x4 {
205 type Output = Self;
206 #[inline]
207 fn neg(self) -> Self::Output {
208 pick! {
209 if #[cfg(target_feature="sse")] {
210 Self { sse: bitxor_m128(self.sse, Self::splat(-0.0).sse) }
211 } else if #[cfg(target_feature="simd128")] {
212 Self { simd: f32x4_neg(self.simd) }
213 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
214 unsafe {Self { neon: vnegq_f32(self.neon) }}
215 } else {
216 Self { arr: [
217 -self.arr[0],
218 -self.arr[1],
219 -self.arr[2],
220 -self.arr[3],
221 ]}
222 }
223 }
224 }
225}
226
227impl Add<f32> for f32x4 {
228 type Output = Self;
229 #[inline]
230 fn add(self, rhs: f32) -> Self::Output {
231 self.add(Self::splat(rhs))
232 }
233}
234
235impl Sub<f32> for f32x4 {
236 type Output = Self;
237 #[inline]
238 fn sub(self, rhs: f32) -> Self::Output {
239 self.sub(Self::splat(rhs))
240 }
241}
242
243impl Mul<f32> for f32x4 {
244 type Output = Self;
245 #[inline]
246 fn mul(self, rhs: f32) -> Self::Output {
247 self.mul(Self::splat(rhs))
248 }
249}
250
251impl Div<f32> for f32x4 {
252 type Output = Self;
253 #[inline]
254 fn div(self, rhs: f32) -> Self::Output {
255 self.div(Self::splat(rhs))
256 }
257}
258
259impl Rem<f32> for f32x4 {
260 type Output = Self;
261 #[inline]
262 fn rem(self, rhs: f32) -> Self::Output {
263 self.rem(Self::splat(rhs))
264 }
265}
266
267impl Add<f32x4> for f32 {
268 type Output = f32x4;
269 #[inline]
270 fn add(self, rhs: f32x4) -> Self::Output {
271 f32x4::splat(self).add(rhs)
272 }
273}
274
275impl Sub<f32x4> for f32 {
276 type Output = f32x4;
277 #[inline]
278 fn sub(self, rhs: f32x4) -> Self::Output {
279 f32x4::splat(self).sub(rhs)
280 }
281}
282
283impl Mul<f32x4> for f32 {
284 type Output = f32x4;
285 #[inline]
286 fn mul(self, rhs: f32x4) -> Self::Output {
287 f32x4::splat(self).mul(rhs)
288 }
289}
290
291impl Div<f32x4> for f32 {
292 type Output = f32x4;
293 #[inline]
294 fn div(self, rhs: f32x4) -> Self::Output {
295 f32x4::splat(self).div(rhs)
296 }
297}
298
299impl Rem<f32x4> for f32 {
300 type Output = f32x4;
301 #[inline]
302 fn rem(self, rhs: f32x4) -> Self::Output {
303 f32x4::splat(self).rem(rhs)
304 }
305}
306
307impl BitAnd for f32x4 {
308 type Output = Self;
309 #[inline]
310 fn bitand(self, rhs: Self) -> Self::Output {
311 pick! {
312 if #[cfg(target_feature="sse")] {
313 Self { sse: bitand_m128(self.sse, rhs.sse) }
314 } else if #[cfg(target_feature="simd128")] {
315 Self { simd: v128_and(self.simd, rhs.simd) }
316 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
317 unsafe {Self { neon: vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(self.neon), vreinterpretq_u32_f32(rhs.neon))) }}
318 } else {
319 Self { arr: [
320 f32::from_bits(self.arr[0].to_bits() & rhs.arr[0].to_bits()),
321 f32::from_bits(self.arr[1].to_bits() & rhs.arr[1].to_bits()),
322 f32::from_bits(self.arr[2].to_bits() & rhs.arr[2].to_bits()),
323 f32::from_bits(self.arr[3].to_bits() & rhs.arr[3].to_bits()),
324 ]}
325 }
326 }
327 }
328}
329
330impl BitOr for f32x4 {
331 type Output = Self;
332 #[inline]
333 fn bitor(self, rhs: Self) -> Self::Output {
334 pick! {
335 if #[cfg(target_feature="sse")] {
336 Self { sse: bitor_m128(self.sse, rhs.sse) }
337 } else if #[cfg(target_feature="simd128")] {
338 Self { simd: v128_or(self.simd, rhs.simd) }
339 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
340 unsafe {Self { neon: vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(self.neon), vreinterpretq_u32_f32(rhs.neon))) }}
341 } else {
342 Self { arr: [
343 f32::from_bits(self.arr[0].to_bits() | rhs.arr[0].to_bits()),
344 f32::from_bits(self.arr[1].to_bits() | rhs.arr[1].to_bits()),
345 f32::from_bits(self.arr[2].to_bits() | rhs.arr[2].to_bits()),
346 f32::from_bits(self.arr[3].to_bits() | rhs.arr[3].to_bits()),
347 ]}
348 }
349 }
350 }
351}
352
353impl BitXor for f32x4 {
354 type Output = Self;
355 #[inline]
356 fn bitxor(self, rhs: Self) -> Self::Output {
357 pick! {
358 if #[cfg(target_feature="sse")] {
359 Self { sse: bitxor_m128(self.sse, rhs.sse) }
360 } else if #[cfg(target_feature="simd128")] {
361 Self { simd: v128_xor(self.simd, rhs.simd) }
362 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
363 unsafe {Self { neon: vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(self.neon), vreinterpretq_u32_f32(rhs.neon))) }}
364 } else {
365 Self { arr: [
366 f32::from_bits(self.arr[0].to_bits() ^ rhs.arr[0].to_bits()),
367 f32::from_bits(self.arr[1].to_bits() ^ rhs.arr[1].to_bits()),
368 f32::from_bits(self.arr[2].to_bits() ^ rhs.arr[2].to_bits()),
369 f32::from_bits(self.arr[3].to_bits() ^ rhs.arr[3].to_bits()),
370 ]}
371 }
372 }
373 }
374}
375
376#[expect(deprecated)]
377impl CmpEq for f32x4 {
378 type Output = Self;
379 #[inline]
380 fn simd_eq(self, rhs: Self) -> Self::Output {
381 pick! {
382 if #[cfg(target_feature="sse")] {
383 Self { sse: cmp_eq_mask_m128(self.sse, rhs.sse) }
384 } else if #[cfg(target_feature="simd128")] {
385 Self { simd: f32x4_eq(self.simd, rhs.simd) }
386 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
387 unsafe {Self { neon: vreinterpretq_f32_u32(vceqq_f32(self.neon, rhs.neon)) }}
388 } else {
389 Self { arr: [
390 if self.arr[0] == rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
391 if self.arr[1] == rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
392 if self.arr[2] == rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
393 if self.arr[3] == rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
394 ]}
395 }
396 }
397 }
398}
399
400#[expect(deprecated)]
401impl CmpGe for f32x4 {
402 type Output = Self;
403 #[inline]
404 fn simd_ge(self, rhs: Self) -> Self::Output {
405 pick! {
406 if #[cfg(target_feature="sse")] {
407 Self { sse: cmp_ge_mask_m128(self.sse, rhs.sse) }
408 } else if #[cfg(target_feature="simd128")] {
409 Self { simd: f32x4_ge(self.simd, rhs.simd) }
410 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
411 unsafe {Self { neon: vreinterpretq_f32_u32(vcgeq_f32(self.neon, rhs.neon)) }}
412 } else {
413 Self { arr: [
414 if self.arr[0] >= rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
415 if self.arr[1] >= rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
416 if self.arr[2] >= rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
417 if self.arr[3] >= rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
418 ]}
419 }
420 }
421 }
422}
423
424#[expect(deprecated)]
425impl CmpGt for f32x4 {
426 type Output = Self;
427 #[inline]
428 fn simd_gt(self, rhs: Self) -> Self::Output {
429 pick! {
430 if #[cfg(target_feature="sse")] {
431 Self { sse: cmp_gt_mask_m128(self.sse, rhs.sse) }
432 } else if #[cfg(target_feature="simd128")] {
433 Self { simd: f32x4_gt(self.simd, rhs.simd) }
434 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
435 unsafe {Self { neon: vreinterpretq_f32_u32(vcgtq_f32(self.neon, rhs.neon)) }}
436 } else {
437 Self { arr: [
438 if self.arr[0] > rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
439 if self.arr[1] > rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
440 if self.arr[2] > rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
441 if self.arr[3] > rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
442 ]}
443 }
444 }
445 }
446}
447
448#[expect(deprecated)]
449impl CmpNe for f32x4 {
450 type Output = Self;
451 #[inline]
452 fn simd_ne(self, rhs: Self) -> Self::Output {
453 pick! {
454 if #[cfg(target_feature="sse")] {
455 Self { sse: cmp_neq_mask_m128(self.sse, rhs.sse) }
456 } else if #[cfg(target_feature="simd128")] {
457 Self { simd: f32x4_ne(self.simd, rhs.simd) }
458 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
459 unsafe {Self { neon: vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(self.neon, rhs.neon))) }}
460 } else {
461 Self { arr: [
462 if self.arr[0] != rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
463 if self.arr[1] != rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
464 if self.arr[2] != rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
465 if self.arr[3] != rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
466 ]}
467 }
468 }
469 }
470}
471
472#[expect(deprecated)]
473impl CmpLe for f32x4 {
474 type Output = Self;
475 #[inline]
476 fn simd_le(self, rhs: Self) -> Self::Output {
477 pick! {
478 if #[cfg(target_feature="sse")] {
479 Self { sse: cmp_le_mask_m128(self.sse, rhs.sse) }
480 } else if #[cfg(target_feature="simd128")] {
481 Self { simd: f32x4_le(self.simd, rhs.simd) }
482 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
483 unsafe {Self { neon: vreinterpretq_f32_u32(vcleq_f32(self.neon, rhs.neon)) }}
484 } else {
485 Self { arr: [
486 if self.arr[0] <= rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
487 if self.arr[1] <= rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
488 if self.arr[2] <= rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
489 if self.arr[3] <= rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
490 ]}
491 }
492 }
493 }
494}
495
496#[expect(deprecated)]
497impl CmpLt for f32x4 {
498 type Output = Self;
499 #[inline]
500 fn simd_lt(self, rhs: Self) -> Self::Output {
501 pick! {
502 if #[cfg(target_feature="sse")] {
503 Self { sse: cmp_lt_mask_m128(self.sse, rhs.sse) }
504 } else if #[cfg(target_feature="simd128")] {
505 Self { simd: f32x4_lt(self.simd, rhs.simd) }
506 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
507 unsafe {Self { neon: vreinterpretq_f32_u32(vcltq_f32(self.neon, rhs.neon)) }}
508 } else {
509 Self { arr: [
510 if self.arr[0] < rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
511 if self.arr[1] < rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
512 if self.arr[2] < rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
513 if self.arr[3] < rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
514 ]}
515 }
516 }
517 }
518}
519
520impl f32x4 {
521 #[inline]
522 #[must_use]
523 pub const fn new(array: [f32; 4]) -> Self {
524 unsafe { core::mem::transmute(array) }
525 }
526
527 simd_comparison_fns!();
528
529 #[inline]
530 #[must_use]
531 pub fn blend(self, t: Self, f: Self) -> Self {
532 pick! {
533 if #[cfg(target_feature="sse4.1")] {
534 Self { sse: blend_varying_m128(f.sse, t.sse, self.sse) }
535 } else if #[cfg(target_feature="simd128")] {
536 Self { simd: v128_bitselect(t.simd, f.simd, self.simd) }
537 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
538 unsafe {Self { neon: vbslq_f32(vreinterpretq_u32_f32(self.neon), t.neon, f.neon) }}
539 } else {
540 generic_bit_blend(self, t, f)
541 }
542 }
543 }
544 #[inline]
545 #[must_use]
546 pub fn abs(self) -> Self {
547 pick! {
548 if #[cfg(target_feature="simd128")] {
549 Self { simd: f32x4_abs(self.simd) }
550 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
551 unsafe {Self { neon: vabsq_f32(self.neon) }}
552 } else {
553 let non_sign_bits = f32x4::from(f32::from_bits(i32::MAX as u32));
554 self & non_sign_bits
555 }
556 }
557 }
558
559 #[inline]
560 #[must_use]
561 pub fn signum(self) -> Self {
562 let result = Self::ONE | self & -Self::ZERO;
563
564 self.is_nan().blend(self, result)
565 }
566
567 #[inline]
568 #[must_use]
569 pub fn floor(self) -> Self {
570 pick! {
571 if #[cfg(target_feature="simd128")] {
572 Self { simd: f32x4_floor(self.simd) }
573 } else if #[cfg(target_feature="sse4.1")] {
574 Self { sse: floor_m128(self.sse) }
575 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
576 unsafe {Self { neon: vrndmq_f32(self.neon) }}
577 } else if #[cfg(feature="std")] {
578 let base: [f32; 4] = cast(self);
579 cast(base.map(|val| val.floor()))
580 } else {
581 let base: [f32; 4] = cast(self);
582 let rounded: [f32; 4] = cast(self.round());
583 cast([
584 if base[0] < rounded[0] { rounded[0] - 1.0 } else { rounded[0] },
585 if base[1] < rounded[1] { rounded[1] - 1.0 } else { rounded[1] },
586 if base[2] < rounded[2] { rounded[2] - 1.0 } else { rounded[2] },
587 if base[3] < rounded[3] { rounded[3] - 1.0 } else { rounded[3] },
588 ])
589 }
590 }
591 }
592 #[inline]
593 #[must_use]
594 pub fn ceil(self) -> Self {
595 pick! {
596 if #[cfg(target_feature="simd128")] {
597 Self { simd: f32x4_ceil(self.simd) }
598 } else if #[cfg(target_feature="sse4.1")] {
599 Self { sse: ceil_m128(self.sse) }
600 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
601 unsafe {Self { neon: vrndpq_f32(self.neon) }}
602 } else if #[cfg(feature="std")] {
603 let base: [f32; 4] = cast(self);
604 cast(base.map(|val| val.ceil()))
605 } else {
606 let base: [f32; 4] = cast(self);
607 let rounded: [f32; 4] = cast(self.round());
608 cast([
609 if base[0] > rounded[0] { rounded[0] + 1.0 } else { rounded[0] },
610 if base[1] > rounded[1] { rounded[1] + 1.0 } else { rounded[1] },
611 if base[2] > rounded[2] { rounded[2] + 1.0 } else { rounded[2] },
612 if base[3] > rounded[3] { rounded[3] + 1.0 } else { rounded[3] },
613 ])
614 }
615 }
616 }
617
618 #[inline]
622 #[must_use]
623 pub fn fast_max(self, rhs: Self) -> Self {
624 pick! {
625 if #[cfg(target_feature="sse")] {
626 Self { sse: max_m128(self.sse, rhs.sse) }
627 } else if #[cfg(target_feature="simd128")] {
628 Self {
629 simd: f32x4_pmax(self.simd, rhs.simd),
630 }
631 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
632 unsafe {Self { neon: vmaxq_f32(self.neon, rhs.neon) }}
633 } else {
634 Self { arr: [
635 if self.arr[0] < rhs.arr[0] { rhs.arr[0] } else { self.arr[0] },
636 if self.arr[1] < rhs.arr[1] { rhs.arr[1] } else { self.arr[1] },
637 if self.arr[2] < rhs.arr[2] { rhs.arr[2] } else { self.arr[2] },
638 if self.arr[3] < rhs.arr[3] { rhs.arr[3] } else { self.arr[3] },
639 ]}
640 }
641 }
642 }
643
644 #[inline]
648 #[must_use]
649 pub fn max(self, rhs: Self) -> Self {
650 pick! {
651 if #[cfg(target_feature="sse")] {
652 rhs.is_nan().blend(self, Self { sse: max_m128(self.sse, rhs.sse) })
656 } else if #[cfg(target_feature="simd128")] {
657 Self {
664 simd: v128_bitselect(
665 rhs.simd,
666 f32x4_pmax(self.simd, rhs.simd),
667 f32x4_ne(self.simd, self.simd), )
669 }
670 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
671 unsafe {Self { neon: vmaxnmq_f32(self.neon, rhs.neon) }}
672 } else {
673 Self { arr: [
674 self.arr[0].max(rhs.arr[0]),
675 self.arr[1].max(rhs.arr[1]),
676 self.arr[2].max(rhs.arr[2]),
677 self.arr[3].max(rhs.arr[3]),
678 ]}
679 }
680 }
681 }
682
683 #[inline]
687 #[must_use]
688 pub fn fast_min(self, rhs: Self) -> Self {
689 pick! {
690 if #[cfg(target_feature="sse")] {
691 Self { sse: min_m128(self.sse, rhs.sse) }
692 } else if #[cfg(target_feature="simd128")] {
693 Self {
694 simd: f32x4_pmin(self.simd, rhs.simd),
695 }
696 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
697 unsafe {Self { neon: vminq_f32(self.neon, rhs.neon) }}
698 } else {
699 Self { arr: [
700 if self.arr[0] < rhs.arr[0] { self.arr[0] } else { rhs.arr[0] },
701 if self.arr[1] < rhs.arr[1] { self.arr[1] } else { rhs.arr[1] },
702 if self.arr[2] < rhs.arr[2] { self.arr[2] } else { rhs.arr[2] },
703 if self.arr[3] < rhs.arr[3] { self.arr[3] } else { rhs.arr[3] },
704 ]}
705 }
706 }
707 }
708
709 #[inline]
713 #[must_use]
714 pub fn min(self, rhs: Self) -> Self {
715 pick! {
716 if #[cfg(target_feature="sse")] {
717 rhs.is_nan().blend(self, Self { sse: min_m128(self.sse, rhs.sse) })
721 } else if #[cfg(target_feature="simd128")] {
722 Self {
729 simd: v128_bitselect(
730 rhs.simd,
731 f32x4_pmin(self.simd, rhs.simd),
732 f32x4_ne(self.simd, self.simd), )
734 }
735 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
736 unsafe {Self { neon: vminnmq_f32(self.neon, rhs.neon) }}
737 } else {
738 Self { arr: [
739 self.arr[0].min(rhs.arr[0]),
740 self.arr[1].min(rhs.arr[1]),
741 self.arr[2].min(rhs.arr[2]),
742 self.arr[3].min(rhs.arr[3]),
743 ]}
744 }
745 }
746 }
747
748 #[inline]
753 #[must_use]
754 pub fn clamp(self, min: Self, max: Self) -> Self {
755 let is_nan = self.is_nan() | min.is_nan() | max.is_nan();
756 let clamped = self.fast_min(max).fast_max(min);
757 is_nan.blend(Self::splat(f32::NAN), clamped)
758 }
759
760 #[inline]
767 #[must_use]
768 pub fn fast_clamp(self, min: Self, max: Self) -> Self {
769 pick! {
770 if #[cfg(target_feature="sse")] {
771 Self { sse: min_m128(max.sse, max_m128(min.sse, self.sse)) }
774 } else if #[cfg(target_feature="simd128")] {
775 Self { simd: f32x4_min(f32x4_max(self.simd, min.simd), max.simd) }
776 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
777 unsafe { Self { neon: vminq_f32(vmaxq_f32(self.neon, min.neon), max.neon) } }
778 } else {
779 let mut result = self;
782 result = result.simd_lt(min).blend(min, self);
783 result = result.simd_gt(max).blend(max, self);
784 result
785 }
786 }
787 }
788
789 #[inline]
790 #[must_use]
791 pub fn midpoint(self, other: Self) -> Self {
792 (self + other) * 0.5
793 }
794
795 #[inline]
796 #[must_use]
797 pub fn is_nan(self) -> Self {
798 pick! {
799 if #[cfg(target_feature="sse")] {
800 Self { sse: cmp_unord_mask_m128(self.sse, self.sse) }
801 } else if #[cfg(target_feature="simd128")] {
802 Self { simd: f32x4_ne(self.simd, self.simd) }
803 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
804 unsafe {Self { neon: vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(self.neon, self.neon))) }}
805 } else {
806 Self { arr: [
807 if self.arr[0].is_nan() { f32::from_bits(u32::MAX) } else { 0.0 },
808 if self.arr[1].is_nan() { f32::from_bits(u32::MAX) } else { 0.0 },
809 if self.arr[2].is_nan() { f32::from_bits(u32::MAX) } else { 0.0 },
810 if self.arr[3].is_nan() { f32::from_bits(u32::MAX) } else { 0.0 },
811 ]}
812 }
813 }
814 }
815 #[inline]
816 #[must_use]
817 pub fn is_finite(self) -> Self {
818 let shifted_exp_mask = u32x4::from(0xFF000000);
819 let u: u32x4 = cast(self);
820 let shift_u = u << 1_u64;
821 let out = !(shift_u & shifted_exp_mask).simd_eq(shifted_exp_mask);
822 cast(out)
823 }
824 #[inline]
825 #[must_use]
826 pub fn is_inf(self) -> Self {
827 let shifted_inf = u32x4::from(0xFF000000);
828 let u: u32x4 = cast(self);
829 let shift_u = u << 1_u64;
830 let out = (shift_u).simd_eq(shifted_inf);
831 cast(out)
832 }
833
834 #[inline]
835 #[must_use]
836 pub fn round(self) -> Self {
837 pick! {
838 if #[cfg(target_feature="sse4.1")] {
839 Self { sse: round_m128::<{round_op!(Nearest)}>(self.sse) }
840 } else if #[cfg(target_feature="sse2")] {
841 let mi: m128i = convert_to_i32_m128i_from_m128(self.sse);
842 let f: f32x4 = f32x4 { sse: convert_to_m128_from_i32_m128i(mi) };
843 let i: i32x4 = cast(mi);
844 let mask: f32x4 = cast(i.simd_eq(i32x4::from(0x80000000_u32 as i32)));
845 mask.blend(self, f)
846 } else if #[cfg(target_feature="simd128")] {
847 Self { simd: f32x4_nearest(self.simd) }
848 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
849 unsafe {Self { neon: vrndnq_f32(self.neon) }}
850 } else {
851 let to_int = f32x4::from(1.0 / f32::EPSILON);
855 let u: u32x4 = cast(self);
856 let e: i32x4 = cast((u >> 23) & u32x4::from(0xff));
857 let mut y: f32x4;
858
859 let no_op_magic = i32x4::from(0x7f + 23);
860 let no_op_mask: f32x4 = cast(e.simd_gt(no_op_magic) | e.simd_eq(no_op_magic));
861 let no_op_val: f32x4 = self;
862
863 let zero_magic = i32x4::from(0x7f - 1);
864 let zero_mask: f32x4 = cast(e.simd_lt(zero_magic));
865 let zero_val: f32x4 = self * f32x4::from(0.0);
866
867 let neg_bit: f32x4 = cast(cast::<u32x4, i32x4>(u).simd_lt(i32x4::default()));
868 let x: f32x4 = neg_bit.blend(-self, self);
869 y = x + to_int - to_int - x;
870 y = y.simd_gt(f32x4::from(0.5)).blend(
871 y + x - f32x4::from(-1.0),
872 y.simd_lt(f32x4::from(-0.5)).blend(y + x + f32x4::from(1.0), y + x),
873 );
874 y = neg_bit.blend(-y, y);
875
876 no_op_mask.blend(no_op_val, zero_mask.blend(zero_val, y))
877 }
878 }
879 }
880
881 #[inline]
885 #[must_use]
886 pub fn fast_round_int(self) -> i32x4 {
887 pick! {
888 if #[cfg(target_feature="sse2")] {
889 cast(convert_to_i32_m128i_from_m128(self.sse))
890 } else {
891 self.round_int()
892 }
893 }
894 }
895
896 #[inline]
900 #[must_use]
901 pub fn round_int(self) -> i32x4 {
902 pick! {
903 if #[cfg(target_feature="sse2")] {
904 let non_nan_mask = self.simd_eq(self);
906 let non_nan = self & non_nan_mask;
907 let flip_to_max: i32x4 = cast(self.simd_ge(Self::splat(2147483648.0)));
908 let cast: i32x4 = cast(convert_to_i32_m128i_from_m128(non_nan.sse));
909 flip_to_max ^ cast
910 } else if #[cfg(target_feature="simd128")] {
911 cast(Self { simd: i32x4_trunc_sat_f32x4(f32x4_nearest(self.simd)) })
912 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
913 cast(unsafe {Self { neon: vreinterpretq_f32_s32(vcvtnq_s32_f32(self.neon)) }})
914 } else {
915 let rounded: [f32; 4] = cast(self.round());
916 cast([
917 rounded[0] as i32,
918 rounded[1] as i32,
919 rounded[2] as i32,
920 rounded[3] as i32,
921 ])
922 }
923 }
924 }
925
926 #[inline]
927 #[must_use]
928 pub fn trunc(self) -> Self {
929 pick! {
930 if #[cfg(target_feature="sse4.1")] {
931 Self { sse: round_m128::<{round_op!(Zero)}>(self.sse) }
932 } else if #[cfg(target_feature="sse2")] {
933 let result: Self = cast(convert_to_m128_from_i32_m128i(truncate_m128_to_m128i(self.sse)));
936
937 let bounds_mask: Self = cast(cmp_lt_mask_i32_m128i(
939 cast(self.abs()),
940 set_splat_i32_m128i(8388608_f32.to_bits() as i32),
941 ));
942
943 bounds_mask.abs().blend(result, self)
945 } else if #[cfg(target_feature="simd128")] {
946 Self { simd: f32x4_trunc(self.simd) }
947 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
948 unsafe { Self { neon: vrndq_f32(self.neon) } }
949 } else {
950 let array: [f32; 4] = cast(self);
951 let result: Self = cast([
952 array[0] as i32 as f32,
953 array[1] as i32 as f32,
954 array[2] as i32 as f32,
955 array[3] as i32 as f32,
956 ]);
957
958 const BOUNDS_LIMIT: i32 = 8388608_f32.to_bits() as i32;
960 let bounds_mask: Self = cast(cast::<f32x4, i32x4>(self.abs()).simd_lt(i32x4::splat(BOUNDS_LIMIT)));
961
962 bounds_mask.abs().blend(result, self)
964 }
965 }
966 }
967
968 #[inline]
972 #[must_use]
973 pub fn fast_trunc_int(self) -> i32x4 {
974 pick! {
975 if #[cfg(target_feature="sse2")] {
976 cast(truncate_m128_to_m128i(self.sse))
977 } else {
978 self.trunc_int()
979 }
980 }
981 }
982
983 #[inline]
987 #[must_use]
988 pub fn trunc_int(self) -> i32x4 {
989 pick! {
990 if #[cfg(target_feature="sse2")] {
991 let non_nan_mask = self.simd_eq(self);
993 let non_nan = self & non_nan_mask;
994 let flip_to_max: i32x4 = cast(self.simd_ge(Self::splat(2147483648.0)));
995 let cast: i32x4 = cast(truncate_m128_to_m128i(non_nan.sse));
996 flip_to_max ^ cast
997 } else if #[cfg(target_feature="simd128")] {
998 cast(Self { simd: i32x4_trunc_sat_f32x4(self.simd) })
999 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1000 cast(unsafe {Self { neon: vreinterpretq_f32_s32(vcvtq_s32_f32(self.neon)) }})
1001 } else {
1002 let n: [f32;4] = cast(self);
1003 cast([
1004 n[0] as i32,
1005 n[1] as i32,
1006 n[2] as i32,
1007 n[3] as i32,
1008 ])
1009 }
1010 }
1011 }
1012
1013 #[inline]
1014 #[must_use]
1015 pub fn fract(self) -> Self {
1016 self - self.trunc()
1017 }
1018
1019 #[inline]
1044 #[must_use]
1045 pub fn mul_add(self, m: Self, a: Self) -> Self {
1046 pick! {
1047 if #[cfg(all(target_feature="sse2",target_feature="fma"))] {
1048 Self { sse: fused_mul_add_m128(self.sse, m.sse, a.sse) }
1049 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1050 unsafe { Self { neon: vfmaq_f32(a.neon, self.neon, m.neon) } }
1051 } else {
1052 (self * m) + a
1053 }
1054 }
1055 }
1056
1057 #[inline]
1083 #[must_use]
1084 pub fn mul_sub(self, m: Self, s: Self) -> Self {
1085 pick! {
1086 if #[cfg(all(target_feature="sse2",target_feature="fma"))] {
1087 Self { sse: fused_mul_sub_m128(self.sse, m.sse, s.sse) }
1088 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1089 unsafe { Self { neon: vfmaq_f32(vnegq_f32(s.neon), self.neon, m.neon) } }
1090 } else {
1091 (self * m) - s
1092 }
1093 }
1094 }
1095
1096 #[inline]
1121 #[must_use]
1122 pub fn mul_neg_add(self, m: Self, a: Self) -> Self {
1123 pick! {
1124 if #[cfg(all(target_feature="sse2",target_feature="fma"))] {
1125 Self { sse: fused_mul_neg_add_m128(self.sse, m.sse, a.sse) }
1126 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1127 unsafe { Self { neon: vfmsq_f32(a.neon, self.neon, m.neon) } }
1128 } else {
1129 a - (self * m)
1130 }
1131 }
1132 }
1133
1134 #[inline]
1160 #[must_use]
1161 pub fn mul_neg_sub(self, m: Self, s: Self) -> Self {
1162 pick! {
1163 if #[cfg(all(target_feature="sse2",target_feature="fma"))] {
1164 Self { sse: fused_mul_neg_sub_m128(self.sse, m.sse, s.sse) }
1165 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1166 unsafe { Self { neon: vnegq_f32(vfmaq_f32(s.neon, self.neon, m.neon)) } }
1167 } else {
1168 -(self * m) - s
1169 }
1170 }
1171 }
1172
1173 #[inline]
1174 #[must_use]
1175 pub fn div_euclid(self, rhs: Self) -> Self {
1176 let q = (self / rhs).trunc();
1177 (self % rhs)
1178 .simd_lt(Self::ZERO)
1179 .blend(rhs.simd_gt(Self::ZERO).blend(q - Self::ONE, q + Self::ONE), q)
1180 }
1181
1182 #[inline]
1183 #[must_use]
1184 pub fn rem_euclid(self, rhs: Self) -> Self {
1185 let r = self % rhs;
1186 r.simd_lt(Self::ZERO).blend(r + rhs.abs(), r)
1187 }
1188
1189 #[inline]
1190 #[must_use]
1191 pub fn flip_signs(self, signs: Self) -> Self {
1192 self ^ (signs & Self::from(-0.0))
1193 }
1194
1195 #[inline]
1196 #[must_use]
1197 pub fn copysign(self, sign: Self) -> Self {
1198 let magnitude_mask = Self::from(f32::from_bits(u32::MAX >> 1));
1199 (self & magnitude_mask) | (sign & Self::from(-0.0))
1200 }
1201
1202 #[inline]
1203 pub fn asin_acos(self) -> (Self, Self) {
1204 const_f32_as_f32x4!(P4asinf, 4.2163199048E-2);
1207 const_f32_as_f32x4!(P3asinf, 2.4181311049E-2);
1208 const_f32_as_f32x4!(P2asinf, 4.5470025998E-2);
1209 const_f32_as_f32x4!(P1asinf, 7.4953002686E-2);
1210 const_f32_as_f32x4!(P0asinf, 1.6666752422E-1);
1211
1212 let xa = self.abs();
1213 let big = xa.simd_ge(f32x4::splat(0.5));
1214
1215 let x1 = f32x4::splat(0.5) * (f32x4::ONE - xa);
1216 let x2 = xa * xa;
1217 let x3 = big.blend(x1, x2);
1218
1219 let xb = x1.sqrt();
1220
1221 let x4 = big.blend(xb, xa);
1222
1223 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1224 let z = z.mul_add(x3 * x4, x4);
1225
1226 let z1 = z + z;
1227
1228 let z3 = self.simd_lt(f32x4::ZERO).blend(f32x4::PI - z1, z1);
1230 let z4 = f32x4::FRAC_PI_2 - z.flip_signs(self);
1231 let acos = big.blend(z3, z4);
1232
1233 let z3 = f32x4::FRAC_PI_2 - z1;
1235 let asin = big.blend(z3, z);
1236 let asin = asin.flip_signs(self);
1237
1238 (asin, acos)
1239 }
1240
1241 #[inline]
1242 pub fn asin(self) -> Self {
1243 const_f32_as_f32x4!(P4asinf, 4.2163199048E-2);
1246 const_f32_as_f32x4!(P3asinf, 2.4181311049E-2);
1247 const_f32_as_f32x4!(P2asinf, 4.5470025998E-2);
1248 const_f32_as_f32x4!(P1asinf, 7.4953002686E-2);
1249 const_f32_as_f32x4!(P0asinf, 1.6666752422E-1);
1250
1251 let xa = self.abs();
1252 let big = xa.simd_ge(f32x4::splat(0.5));
1253
1254 let x1 = f32x4::splat(0.5) * (f32x4::ONE - xa);
1255 let x2 = xa * xa;
1256 let x3 = big.blend(x1, x2);
1257
1258 let xb = x1.sqrt();
1259
1260 let x4 = big.blend(xb, xa);
1261
1262 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1263 let z = z.mul_add(x3 * x4, x4);
1264
1265 let z1 = z + z;
1266
1267 let z3 = f32x4::FRAC_PI_2 - z1;
1269 let asin = big.blend(z3, z);
1270 let asin = asin.flip_signs(self);
1271
1272 asin
1273 }
1274
1275 #[inline]
1276 #[must_use]
1277 pub fn acos(self) -> Self {
1278 const_f32_as_f32x4!(P4asinf, 4.2163199048E-2);
1281 const_f32_as_f32x4!(P3asinf, 2.4181311049E-2);
1282 const_f32_as_f32x4!(P2asinf, 4.5470025998E-2);
1283 const_f32_as_f32x4!(P1asinf, 7.4953002686E-2);
1284 const_f32_as_f32x4!(P0asinf, 1.6666752422E-1);
1285
1286 let xa = self.abs();
1287 let big = xa.simd_ge(f32x4::splat(0.5));
1288
1289 let x1 = f32x4::splat(0.5) * (f32x4::ONE - xa);
1290 let x2 = xa * xa;
1291 let x3 = big.blend(x1, x2);
1292
1293 let xb = x1.sqrt();
1294
1295 let x4 = big.blend(xb, xa);
1296
1297 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1298 let z = z.mul_add(x3 * x4, x4);
1299
1300 let z1 = z + z;
1301
1302 let z3 = self.simd_lt(f32x4::ZERO).blend(f32x4::PI - z1, z1);
1304 let z4 = f32x4::FRAC_PI_2 - z.flip_signs(self);
1305 let acos = big.blend(z3, z4);
1306
1307 acos
1308 }
1309
1310 #[inline]
1311 pub fn atan(self) -> Self {
1312 const_f32_as_f32x4!(P3atanf, 8.05374449538E-2);
1315 const_f32_as_f32x4!(P2atanf, -1.38776856032E-1);
1316 const_f32_as_f32x4!(P1atanf, 1.99777106478E-1);
1317 const_f32_as_f32x4!(P0atanf, -3.33329491539E-1);
1318
1319 let t = self.abs();
1320
1321 let notsmal = t.simd_ge(Self::SQRT_2 - Self::ONE);
1325 let notbig = t.simd_le(Self::SQRT_2 + Self::ONE);
1326
1327 let mut s = notbig.blend(Self::FRAC_PI_4, Self::FRAC_PI_2);
1328 s = notsmal & s;
1329
1330 let mut a = notbig & t;
1331 a = notsmal.blend(a - Self::ONE, a);
1332 let mut b = notbig & Self::ONE;
1333 b = notsmal.blend(b + t, b);
1334 let z = a / b;
1335
1336 let zz = z * z;
1337
1338 let mut re = polynomial_3!(zz, P0atanf, P1atanf, P2atanf, P3atanf);
1340 re = re.mul_add(zz * z, z) + s;
1341
1342 re = (self.is_sign_negative()).blend(-re, re);
1344
1345 re
1346 }
1347
1348 #[inline]
1349 pub fn atan2(self, x: Self) -> Self {
1350 const_f32_as_f32x4!(P3atanf, 8.05374449538E-2);
1353 const_f32_as_f32x4!(P2atanf, -1.38776856032E-1);
1354 const_f32_as_f32x4!(P1atanf, 1.99777106478E-1);
1355 const_f32_as_f32x4!(P0atanf, -3.33329491539E-1);
1356
1357 let y = self;
1358
1359 let x1 = x.abs();
1361 let y1 = y.abs();
1362 let swapxy = y1.simd_gt(x1);
1363 let mut x2 = swapxy.blend(y1, x1);
1365 let mut y2 = swapxy.blend(x1, y1);
1366
1367 let both_infinite = x.is_inf() & y.is_inf();
1369 if both_infinite.any() {
1370 let minus_one = -Self::ONE;
1371 x2 = both_infinite.blend(x2 & minus_one, x2);
1372 y2 = both_infinite.blend(y2 & minus_one, y2);
1373 }
1374
1375 let t = y2 / x2;
1377
1378 let notsmal = t.simd_ge(Self::SQRT_2 - Self::ONE);
1381
1382 let a = notsmal.blend(t - Self::ONE, t);
1383 let b = notsmal.blend(t + Self::ONE, Self::ONE);
1384 let s = notsmal & Self::FRAC_PI_4;
1385 let z = a / b;
1386
1387 let zz = z * z;
1388
1389 let mut re = polynomial_3!(zz, P0atanf, P1atanf, P2atanf, P3atanf);
1391 re = re.mul_add(zz * z, z) + s;
1392
1393 re = swapxy.blend(Self::FRAC_PI_2 - re, re);
1395 re = ((x | y).simd_eq(Self::ZERO)).blend(Self::ZERO, re);
1396 re = (x.is_sign_negative()).blend(Self::PI - re, re);
1397
1398 re = (y.is_sign_negative()).blend(-re, re);
1400
1401 re
1402 }
1403
1404 #[inline]
1405 #[must_use]
1406 pub fn sin_cos(self) -> (Self, Self) {
1407 const_f32_as_f32x4!(DP1F, 0.78515625_f32 * 2.0);
1411 const_f32_as_f32x4!(DP2F, 2.4187564849853515625E-4_f32 * 2.0);
1412 const_f32_as_f32x4!(DP3F, 3.77489497744594108E-8_f32 * 2.0);
1413
1414 const_f32_as_f32x4!(P0sinf, -1.6666654611E-1);
1415 const_f32_as_f32x4!(P1sinf, 8.3321608736E-3);
1416 const_f32_as_f32x4!(P2sinf, -1.9515295891E-4);
1417
1418 const_f32_as_f32x4!(P0cosf, 4.166664568298827E-2);
1419 const_f32_as_f32x4!(P1cosf, -1.388731625493765E-3);
1420 const_f32_as_f32x4!(P2cosf, 2.443315711809948E-5);
1421
1422 const_f32_as_f32x4!(TWO_OVER_PI, 2.0 / core::f32::consts::PI);
1423
1424 let xa = self.abs();
1425
1426 let y = (xa * TWO_OVER_PI).round();
1428 let q: i32x4 = y.round_int();
1429
1430 let x = y.mul_neg_add(DP3F, y.mul_neg_add(DP2F, y.mul_neg_add(DP1F, xa)));
1431
1432 let x2 = x * x;
1433 let mut s = polynomial_2!(x2, P0sinf, P1sinf, P2sinf) * (x * x2) + x;
1434 let mut c = polynomial_2!(x2, P0cosf, P1cosf, P2cosf) * (x2 * x2)
1435 + f32x4::from(0.5).mul_neg_add(x2, f32x4::from(1.0));
1436
1437 let swap = !(q & i32x4::from(1)).simd_eq(i32x4::from(0));
1438
1439 let mut overflow: f32x4 = cast(q.simd_gt(i32x4::from(0x2000000)));
1440 overflow &= xa.is_finite();
1441 s = overflow.blend(f32x4::from(0.0), s);
1442 c = overflow.blend(f32x4::from(1.0), c);
1443
1444 let mut sin1 = cast::<_, f32x4>(swap).blend(c, s);
1446 let sign_sin: i32x4 = (q << 30) ^ cast::<_, i32x4>(self);
1447 sin1 = sin1.flip_signs(cast(sign_sin));
1448
1449 let mut cos1 = cast::<_, f32x4>(swap).blend(s, c);
1451 let sign_cos: i32x4 = ((q + i32x4::from(1)) & i32x4::from(2)) << 30;
1452 cos1 ^= cast::<_, f32x4>(sign_cos);
1453
1454 let finite = self.is_finite();
1456 let nan = Self::splat(f32::NAN);
1457 let sin_final = finite.blend(sin1, nan);
1458 let cos_final = finite.blend(cos1, nan);
1459
1460 (sin_final, cos_final)
1461 }
1462
1463 #[inline]
1464 #[must_use]
1465 pub fn sin(self) -> Self {
1466 let (s, _) = self.sin_cos();
1467 s
1468 }
1469 #[inline]
1470 #[must_use]
1471 pub fn cos(self) -> Self {
1472 let (_, c) = self.sin_cos();
1473 c
1474 }
1475 #[inline]
1476 #[must_use]
1477 pub fn tan(self) -> Self {
1478 let (s, c) = self.sin_cos();
1479 s / c
1480 }
1481
1482 #[inline]
1484 #[must_use]
1485 pub fn sinh(self) -> Self {
1486 const_f32_as_f32x4!(P0, 1.0);
1487 const_f32_as_f32x4!(P1, 1.0 / 6.0);
1488 const_f32_as_f32x4!(P2, 1.0 / 120.0);
1489 const_f32_as_f32x4!(P3, 1.0 / 5040.0);
1490 let a = self.abs();
1491 let small = a.simd_lt(f32x4::from(0.5));
1493 let t = a * a;
1494 let poly = a * polynomial_3!(t, P0, P1, P2, P3);
1495 let exp_based = {
1496 let e = a.exp();
1497 (e - Self::ONE / e) * Self::HALF
1498 };
1499 let result = small.blend(poly, exp_based);
1500 result.flip_signs(self)
1501 }
1502
1503 #[inline]
1505 #[must_use]
1506 pub fn cosh(self) -> Self {
1507 const_f32_as_f32x4!(P0, 1.0);
1508 const_f32_as_f32x4!(P1, 1.0 / 2.0);
1509 const_f32_as_f32x4!(P2, 1.0 / 24.0);
1510 const_f32_as_f32x4!(P3, 1.0 / 720.0);
1511 let a = self.abs();
1512 let small = a.simd_lt(f32x4::from(0.5));
1514 let t = a * a;
1515 let poly = polynomial_3!(t, P0, P1, P2, P3);
1516 let exp_based = {
1517 let e = a.exp();
1518 (e + Self::ONE / e) * Self::HALF
1519 };
1520 small.blend(poly, exp_based)
1521 }
1522
1523 #[inline]
1525 #[must_use]
1526 pub fn tanh(self) -> Self {
1527 let a = self.abs();
1531 let large = a.simd_gt(f32x4::from(9.011));
1532 if large.all() {
1533 return Self::ONE.flip_signs(self);
1534 }
1535 let small = a.simd_lt(f32x4::from(2e-4));
1536 let exp_based = {
1537 let t = (Self::from(-2.0) * a).exp_m1();
1538 let pos = -t / (t + Self::from(2.0));
1539 pos.flip_signs(self)
1540 };
1541 let result = small.blend(self, exp_based);
1542 large.blend(Self::ONE.flip_signs(self), result)
1543 }
1544
1545 #[inline]
1547 #[must_use]
1548 pub fn cbrt(self) -> Self {
1549 let a = self.abs();
1550 let zero = a.simd_eq(Self::ZERO);
1551 if zero.all() {
1552 return self; }
1554 let inf = a.is_inf();
1555 let nan = self.is_nan();
1556
1557 let tiny = a.simd_lt(Self::from(f32::MIN_POSITIVE));
1558 let a_work = tiny.blend(a * Self::from(16777216.0), a);
1559
1560 let e = Self::exponent(a_work) + Self::ONE;
1561 let d = Self::fraction_2(a_work);
1562
1563 const_f32_as_f32x4!(C0, 2.2241257);
1570 const_f32_as_f32x4!(C1, -3.8095417);
1571 const_f32_as_f32x4!(C2, 5.8982625);
1572 const_f32_as_f32x4!(C3, -5.532182);
1573 const_f32_as_f32x4!(C4, 2.8208892);
1574 const_f32_as_f32x4!(C5, -0.60156447);
1575 let mut x = polynomial_5!(d, C0, C1, C2, C3, C4, C5);
1576
1577 let x2 = x * x;
1578 let x4 = x2 * x2;
1579 x = x - d.mul_add(x4, -x) * Self::from(1.0 / 3.0);
1580 let mut y = (d * x) * x;
1582 let yx = y * x;
1583 let t = Self::from(2.0 / 3.0);
1584 y = y - t * y * (yx - Self::ONE);
1585
1586 let three = Self::from(3.0);
1588 let two = Self::from(2.0);
1589 let neg = e.simd_lt(Self::ZERO);
1590 let e_adj = neg.blend(e - two, e);
1591 let k = (e_adj / three).trunc();
1592 let r = e - three * k;
1593 const_f32_as_f32x4!(CBRT2, 1.259921);
1594 const_f32_as_f32x4!(CBRT4, 1.587401);
1595 y = r.simd_eq(Self::ONE).blend(y * CBRT2, y);
1596 y = r.simd_eq(two).blend(y * CBRT4, y);
1597 y *= Self::vm_pow2n(k);
1598 y = tiny.blend(y / Self::from(256.0_f32), y);
1599
1600 let result = y.flip_signs(self);
1601 let result = nan.blend(self, result);
1602 let result = zero.blend(self, result);
1603 let result = inf.blend(self, result);
1604 result
1605 }
1606
1607 #[inline]
1608 #[must_use]
1609 pub fn to_degrees(self) -> Self {
1610 const_f32_as_f32x4!(RAD_TO_DEG_RATIO, 180.0_f32 / core::f32::consts::PI);
1611 self * RAD_TO_DEG_RATIO
1612 }
1613 #[inline]
1614 #[must_use]
1615 pub fn to_radians(self) -> Self {
1616 const_f32_as_f32x4!(DEG_TO_RAD_RATIO, core::f32::consts::PI / 180.0_f32);
1617 self * DEG_TO_RAD_RATIO
1618 }
1619 #[inline]
1620 #[must_use]
1621 pub fn recip(self) -> Self {
1622 pick! {
1623 if #[cfg(target_feature="sse")] {
1624 Self { sse: reciprocal_m128(self.sse) }
1625 } else if #[cfg(target_feature="simd128")] {
1626 Self { simd: f32x4_div(f32x4_splat(1.0), self.simd) }
1627 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1628 unsafe {Self { neon: vdivq_f32(vdupq_n_f32(1.0), self.neon) }}
1629 } else {
1630 Self { arr: [
1631 1.0 / self.arr[0],
1632 1.0 / self.arr[1],
1633 1.0 / self.arr[2],
1634 1.0 / self.arr[3],
1635 ]}
1636 }
1637 }
1638 }
1639 #[inline]
1640 #[must_use]
1641 pub fn recip_sqrt(self) -> Self {
1642 pick! {
1643 if #[cfg(target_feature="sse")] {
1644 Self { sse: reciprocal_sqrt_m128(self.sse) }
1645 } else if #[cfg(target_feature="simd128")] {
1646 Self { simd: f32x4_div(f32x4_splat(1.0), f32x4_sqrt(self.simd)) }
1647 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1648 unsafe {Self { neon: vdivq_f32(vdupq_n_f32(1.0), vsqrtq_f32(self.neon)) }}
1649 } else if #[cfg(feature="std")] {
1650 Self { arr: [
1651 1.0 / self.arr[0].sqrt(),
1652 1.0 / self.arr[1].sqrt(),
1653 1.0 / self.arr[2].sqrt(),
1654 1.0 / self.arr[3].sqrt(),
1655 ]}
1656 } else {
1657 Self { arr: [
1658 1.0 / software_sqrt(self.arr[0] as f64) as f32,
1659 1.0 / software_sqrt(self.arr[1] as f64) as f32,
1660 1.0 / software_sqrt(self.arr[2] as f64) as f32,
1661 1.0 / software_sqrt(self.arr[3] as f64) as f32,
1662 ]}
1663 }
1664 }
1665 }
1666 #[inline]
1667 #[must_use]
1668 pub fn sqrt(self) -> Self {
1669 pick! {
1670 if #[cfg(target_feature="sse")] {
1671 Self { sse: sqrt_m128(self.sse) }
1672 } else if #[cfg(target_feature="simd128")] {
1673 Self { simd: f32x4_sqrt(self.simd) }
1674 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1675 unsafe {Self { neon: vsqrtq_f32(self.neon) }}
1676 } else if #[cfg(feature="std")] {
1677 Self { arr: [
1678 self.arr[0].sqrt(),
1679 self.arr[1].sqrt(),
1680 self.arr[2].sqrt(),
1681 self.arr[3].sqrt(),
1682 ]}
1683 } else {
1684 Self { arr: [
1685 software_sqrt(self.arr[0] as f64) as f32,
1686 software_sqrt(self.arr[1] as f64) as f32,
1687 software_sqrt(self.arr[2] as f64) as f32,
1688 software_sqrt(self.arr[3] as f64) as f32,
1689 ]}
1690 }
1691 }
1692 }
1693
1694 #[inline]
1695 #[must_use]
1696 #[doc(alias("movemask", "move_mask"))]
1697 pub fn to_bitmask(self) -> u32 {
1698 pick! {
1699 if #[cfg(target_feature="sse")] {
1700 move_mask_m128(self.sse) as u32
1701 } else if #[cfg(target_feature="simd128")] {
1702 u32x4_bitmask(self.simd) as u32
1703 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1704 unsafe
1705 {
1706 let masked = vcltq_s32( vreinterpretq_s32_f32(self.neon), vdupq_n_s32(0));
1708
1709 let selectbit : uint32x4_t = core::mem::transmute([1u32, 2, 4, 8]);
1711 let r = vandq_u32(masked, selectbit);
1712
1713 vaddvq_u32(r) as u32
1715 }
1716 } else {
1717 (((self.arr[0].to_bits() as i32) < 0) as u32) << 0 |
1718 (((self.arr[1].to_bits() as i32) < 0) as u32) << 1 |
1719 (((self.arr[2].to_bits() as i32) < 0) as u32) << 2 |
1720 (((self.arr[3].to_bits() as i32) < 0) as u32) << 3
1721 }
1722 }
1723 }
1724 #[inline]
1725 #[must_use]
1726 pub fn any(self) -> bool {
1727 pick! {
1728 if #[cfg(target_feature="simd128")] {
1729 v128_any_true(self.simd)
1730 } else {
1731 self.to_bitmask() != 0
1732 }
1733 }
1734 }
1735 #[inline]
1736 #[must_use]
1737 pub fn all(self) -> bool {
1738 pick! {
1739 if #[cfg(target_feature="simd128")] {
1740 u32x4_all_true(self.simd)
1741 } else {
1742 self.to_bitmask() == 0b1111
1744 }
1745 }
1746 }
1747 #[inline]
1748 #[must_use]
1749 pub fn none(self) -> bool {
1750 !self.any()
1751 }
1752
1753 #[inline]
1754 fn vm_pow2n(self) -> Self {
1755 const_f32_as_f32x4!(pow2_23, 8388608.0);
1756 const_f32_as_f32x4!(bias, 127.0);
1757 let a = self + (bias + pow2_23);
1758 let c = cast::<_, i32x4>(a) << 23;
1759 let std_result = cast::<_, f32x4>(c);
1760
1761 let min_exp = f32x4::from(-126.0);
1762 let is_sub = self.simd_lt(min_exp);
1763 if is_sub.any() {
1764 let valid = self.simd_ge(f32x4::from(-149.0));
1765 let shift_f = self + f32x4::from(149.0);
1766 let mut shift_i = shift_f.trunc_int();
1767 shift_i = cast::<_, i32x4>(valid).blend(shift_i, i32x4::ZERO);
1768 let mantissa = i32x4::ONE << shift_i;
1769 let sub_result = cast::<_, f32x4>(mantissa);
1770 let sub_result = valid.blend(sub_result, f32x4::ZERO);
1771 is_sub.blend(sub_result, std_result)
1772 } else {
1773 std_result
1774 }
1775 }
1776
1777 #[inline]
1779 #[must_use]
1780 pub fn exp(self) -> Self {
1781 const_f32_as_f32x4!(P0, 1.0 / 2.0);
1782 const_f32_as_f32x4!(P1, 1.0 / 6.0);
1783 const_f32_as_f32x4!(P2, 1.0 / 24.0);
1784 const_f32_as_f32x4!(P3, 1.0 / 120.0);
1785 const_f32_as_f32x4!(P4, 1.0 / 720.0);
1786 const_f32_as_f32x4!(P5, 1.0 / 5040.0);
1787 const_f32_as_f32x4!(LN2D_HI, 0.693359375);
1794 const_f32_as_f32x4!(LN2D_LO, -2.12194440e-4);
1795 let max_x = f32x4::from(88.723);
1798 let min_x = f32x4::from(-103.63);
1799 let finite = self.is_finite();
1801 let neg_underflow = self.simd_lt(min_x) & finite;
1802 if neg_underflow.all() {
1803 return Self::ZERO;
1804 }
1805 let max_r = f32x4::from(127.0);
1806 let r = (self * Self::LOG2_E).round();
1807 let big = r.simd_gt(max_r);
1808 let r_safe = big.blend(max_r, r);
1809 let excess = r - max_r;
1810 let excess = big.blend(excess, Self::ZERO);
1811 let scale = Self::vm_pow2n(excess);
1812 let x = r.mul_neg_add(LN2D_HI, self);
1813 let x = r.mul_neg_add(LN2D_LO, x);
1814 let z = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1815 let x2 = x * x;
1816 let z = z.mul_add(x2, x);
1817 let n2 = Self::vm_pow2n(r_safe);
1818 let z = (z + Self::ONE) * scale * n2;
1819 let nan_mask = self.is_nan();
1820 let mut result = nan_mask.blend(Self::nan_pow(), z);
1821 let pos_overflow = self.simd_gt(max_x) & finite;
1822 result = pos_overflow.blend(Self::infinity(), result);
1823 result = neg_underflow.blend(Self::ZERO, result);
1824 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1825 result = pos_inf.blend(Self::infinity(), result);
1826 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1827 result = neg_inf.blend(Self::ZERO, result);
1828 result
1829 }
1830
1831 #[inline]
1834 #[must_use]
1835 pub fn exp_m1(self) -> Self {
1836 if self.simd_lt(f32x4::from(-17.329)).all() {
1840 return f32x4::from(-1.0);
1841 }
1842 const_f32_as_f32x4!(P0, 1.0 / 2.0);
1843 const_f32_as_f32x4!(P1, 1.0 / 6.0);
1844 const_f32_as_f32x4!(P2, 1.0 / 24.0);
1845 const_f32_as_f32x4!(P3, 1.0 / 120.0);
1846 const_f32_as_f32x4!(P4, 1.0 / 720.0);
1847 const_f32_as_f32x4!(P5, 1.0 / 5040.0);
1848 const_f32_as_f32x4!(LN2D_HI, 0.693359375);
1855 const_f32_as_f32x4!(LN2D_LO, -2.12194440e-4);
1856 let max_x = f32x4::from(88.723);
1859 let min_x = f32x4::from(-103.63);
1860 let max_r = f32x4::from(127.0);
1861 let r = (self * Self::LOG2_E).round();
1862 let big = r.simd_gt(max_r);
1863 let r_safe = big.blend(max_r, r);
1864 let excess = r - max_r;
1865 let excess = big.blend(excess, Self::ZERO);
1866 let scale = Self::vm_pow2n(excess);
1867 let x = r.mul_neg_add(LN2D_HI, self);
1868 let x = r.mul_neg_add(LN2D_LO, x);
1869 let z = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1870 let x2 = x * x;
1871 let z = z.mul_add(x2, x);
1872 let n2 = Self::vm_pow2n(r_safe);
1873 let exp_val = (z + Self::ONE) * scale * n2;
1874 let r_is_zero = r.simd_eq(Self::ZERO);
1875 let z = r_is_zero.blend(z, exp_val - Self::ONE);
1876 let nan_mask = self.is_nan();
1877 let finite = self.is_finite();
1878 let mut result = nan_mask.blend(Self::nan_pow(), z);
1879 let pos_overflow = self.simd_gt(max_x) & finite;
1880 result = pos_overflow.blend(Self::infinity(), result);
1881 let neg_underflow = self.simd_lt(min_x) & finite;
1882 result = neg_underflow.blend(-Self::ONE, result);
1883 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1884 result = pos_inf.blend(Self::infinity(), result);
1885 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1886 result = neg_inf.blend(-Self::ONE, result);
1887 let is_zero = self.simd_eq(Self::ZERO);
1888 result = is_zero.blend(self, result);
1889 result
1890 }
1891
1892 #[inline]
1894 #[must_use]
1895 pub fn exp2(self) -> Self {
1896 const_f32_as_f32x4!(P2, 1.0 / 2.0);
1897 const_f32_as_f32x4!(P3, 1.0 / 6.0);
1898 const_f32_as_f32x4!(P4, 1.0 / 24.0);
1899 const_f32_as_f32x4!(P5, 1.0 / 120.0);
1900 const_f32_as_f32x4!(P6, 1.0 / 720.0);
1901 const_f32_as_f32x4!(P7, 1.0 / 5040.0);
1902
1903 let max_x = f32x4::from(127.99999);
1906 let min_x = f32x4::from(-149.5);
1907 let finite = self.is_finite();
1908 let neg_underflow = self.simd_lt(min_x) & finite;
1909 if neg_underflow.all() {
1910 return Self::ZERO;
1911 }
1912
1913 let round = self.round();
1914 let max_r = f32x4::from(127.0);
1915 let big = round.simd_gt(max_r);
1916 let r_safe = big.blend(max_r, round);
1917 let excess = round - max_r;
1918 let excess = big.blend(excess, Self::ZERO);
1919 let scale = Self::vm_pow2n(excess);
1920
1921 let fract = (self - round) * Self::LN_2;
1922 let fract_partial_exp2 = polynomial_5!(fract, P2, P3, P4, P5, P6, P7);
1923 let fract2 = fract * fract;
1924 let fract_exp2 = fract_partial_exp2.mul_add(fract2, fract) + Self::ONE;
1925
1926 let n2 = Self::vm_pow2n(r_safe);
1927 let result = fract_exp2 * scale * n2;
1928
1929 let nan_mask = self.is_nan();
1930 let mut result = nan_mask.blend(Self::nan_pow(), result);
1931 let pos_overflow = self.simd_gt(max_x) & finite;
1932 result = pos_overflow.blend(Self::infinity(), result);
1933 result = neg_underflow.blend(Self::ZERO, result);
1934 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1935 result = pos_inf.blend(Self::infinity(), result);
1936 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1937 result = neg_inf.blend(Self::ZERO, result);
1938 result
1939 }
1940
1941 #[inline]
1942 fn exponent(self) -> f32x4 {
1943 const_f32_as_f32x4!(pow2_23, 8388608.0);
1944 const_f32_as_f32x4!(bias, 127.0);
1945 let a = cast::<_, u32x4>(self);
1946 let b = a >> 23;
1947 let c = b | cast::<_, u32x4>(pow2_23);
1948 let d = cast::<_, f32x4>(c);
1949 let e = d - (pow2_23 + bias);
1950 e
1951 }
1952
1953 #[inline]
1954 fn fraction_2(self) -> Self {
1955 let t1 = cast::<_, u32x4>(self);
1956 let t2 = cast::<_, u32x4>(
1957 (t1 & u32x4::from(0x007FFFFF)) | u32x4::from(0x3F000000),
1958 );
1959 cast::<_, f32x4>(t2)
1960 }
1961 #[inline]
1962 fn is_zero_or_subnormal(self) -> Self {
1963 let t = cast::<_, i32x4>(self);
1964 let t = t & i32x4::splat(0x7F800000);
1965 let mask = t.simd_eq(i32x4::splat(0));
1966 cast::<_, f32x4>(mask)
1967 }
1968 #[inline]
1969 fn infinity() -> Self {
1970 cast::<_, f32x4>(i32x4::splat(0x7F800000))
1971 }
1972 #[inline]
1973 fn nan_log() -> Self {
1974 cast::<_, f32x4>(i32x4::splat(0x7FC00000 | 0x101 & 0x003FFFFF))
1975 }
1976 #[inline]
1977 fn nan_pow() -> Self {
1978 cast::<_, f32x4>(i32x4::splat(0x7FC00000 | 0x101 & 0x003FFFFF))
1979 }
1980
1981 #[inline]
1984 #[must_use]
1985 pub fn is_sign_positive(self) -> Self {
1986 const SIGN_MASK: u32x4 = u32x4::splat((-0.0_f32).to_bits());
1987
1988 let bits = cast::<f32x4, u32x4>(self);
1989 let sign = bits & SIGN_MASK;
1990 let result = sign.simd_eq(u32x4::ZERO);
1991 cast::<u32x4, f32x4>(result)
1992 }
1993
1994 #[inline]
1997 #[must_use]
1998 pub fn is_sign_negative(self) -> Self {
1999 const SIGN_MASK: u32x4 = u32x4::splat((-0.0_f32).to_bits());
2000
2001 let bits = cast::<f32x4, u32x4>(self);
2002 let sign = bits & SIGN_MASK;
2003 let result = sign.simd_eq(SIGN_MASK);
2004 cast::<u32x4, f32x4>(result)
2005 }
2006
2007 #[inline]
2009 #[must_use]
2010 pub fn reduce_add(self) -> f32 {
2011 let arr: [f32; 4] = cast(self);
2012 arr.iter().sum()
2013 }
2014
2015 #[inline]
2017 #[must_use]
2018 pub fn reduce_mul(self) -> f32 {
2019 let arr: [f32; 4] = cast(self);
2020 arr.iter().product()
2021 }
2022
2023 #[inline]
2025 #[must_use]
2026 pub fn ln(self) -> Self {
2027 const_f32_as_f32x4!(HALF, 0.5);
2028 const_f32_as_f32x4!(P0, 3.3333331174E-1);
2029 const_f32_as_f32x4!(P1, -2.4999993993E-1);
2030 const_f32_as_f32x4!(P2, 2.0000714765E-1);
2031 const_f32_as_f32x4!(P3, -1.6668057665E-1);
2032 const_f32_as_f32x4!(P4, 1.4249322787E-1);
2033 const_f32_as_f32x4!(P5, -1.2420140846E-1);
2034 const_f32_as_f32x4!(P6, 1.1676998740E-1);
2035 const_f32_as_f32x4!(P7, -1.1514610310E-1);
2036 const_f32_as_f32x4!(P8, 7.0376836292E-2);
2037 const_f32_as_f32x4!(LN2F_HI, 0.693359375);
2038 const_f32_as_f32x4!(LN2F_LO, -2.12194440e-4);
2039 const_f32_as_f32x4!(VM_SMALLEST_NORMAL, 1.17549435E-38);
2040
2041 let x1 = self;
2042 let x = Self::fraction_2(x1);
2043 let e = Self::exponent(x1);
2044 let mask = x.simd_gt(Self::SQRT_2 * HALF);
2045 let x = (!mask).blend(x + x, x);
2046 let fe = mask.blend(e + Self::ONE, e);
2047 let x = x - Self::ONE;
2048 let res = polynomial_8!(x, P0, P1, P2, P3, P4, P5, P6, P7, P8);
2049 let x2 = x * x;
2050 let res = x2 * x * res;
2051 let res = fe.mul_add(LN2F_LO, res);
2052 let res = res + x2.mul_neg_add(HALF, x);
2053 let res = fe.mul_add(LN2F_HI, res);
2054 let overflow = !self.is_finite();
2055 let underflow = x1.simd_lt(VM_SMALLEST_NORMAL);
2056 let mask = overflow | underflow;
2057 if !mask.any() {
2058 res
2059 } else {
2060 let is_zero = self.is_zero_or_subnormal();
2061 let res = underflow.blend(Self::nan_log(), res);
2062 let res = is_zero.blend(-Self::infinity(), res);
2067 let res = overflow.blend(self, res);
2068 let res = (!self.is_finite() & self.is_sign_negative())
2070 .blend(Self::nan_log(), res);
2071 res
2072 }
2073 }
2074
2075 #[inline]
2078 #[must_use]
2079 pub fn ln_1p(self) -> Self {
2080 let u = self + Self::ONE;
2088 let eq = u.simd_eq(Self::ONE);
2089 let ln_u = Self::ln(u);
2090 let correction = self * (ln_u / (u - Self::ONE));
2091 let result = eq.blend(self, correction);
2092 let over = u.is_inf();
2093 over.blend(ln_u, result)
2094 }
2095
2096 #[inline]
2097 #[must_use]
2098 pub fn log2(self) -> Self {
2099 Self::ln(self) * Self::LOG2_E
2100 }
2101 #[inline]
2102 #[must_use]
2103 pub fn log10(self) -> Self {
2104 Self::ln(self) * Self::LOG10_E
2105 }
2106
2107 #[inline]
2108 #[must_use]
2109 pub fn pow_f32x4(self, y: f32x4) -> Self {
2110 const_f32_as_f32x4!(ln2f_hi, 0.693359375);
2111 const_f32_as_f32x4!(ln2f_lo, -2.12194440e-4);
2112 const_f32_as_f32x4!(P0logf, 3.3333331174E-1);
2113 const_f32_as_f32x4!(P1logf, -2.4999993993E-1);
2114 const_f32_as_f32x4!(P2logf, 2.0000714765E-1);
2115 const_f32_as_f32x4!(P3logf, -1.6668057665E-1);
2116 const_f32_as_f32x4!(P4logf, 1.4249322787E-1);
2117 const_f32_as_f32x4!(P5logf, -1.2420140846E-1);
2118 const_f32_as_f32x4!(P6logf, 1.1676998740E-1);
2119 const_f32_as_f32x4!(P7logf, -1.1514610310E-1);
2120 const_f32_as_f32x4!(P8logf, 7.0376836292E-2);
2121
2122 const_f32_as_f32x4!(p2expf, 1.0 / 2.0); const_f32_as_f32x4!(p3expf, 1.0 / 6.0);
2124 const_f32_as_f32x4!(p4expf, 1.0 / 24.0);
2125 const_f32_as_f32x4!(p5expf, 1.0 / 120.0);
2126 const_f32_as_f32x4!(p6expf, 1.0 / 720.0);
2127 const_f32_as_f32x4!(p7expf, 1.0 / 5040.0);
2128
2129 let x1 = self.abs();
2130 let x = x1.fraction_2();
2131
2132 let mask = x.simd_gt(f32x4::SQRT_2 * f32x4::HALF);
2133 let x = (!mask).blend(x + x, x);
2134
2135 let x = x - f32x4::ONE;
2136 let x2 = x * x;
2137 let lg1 = polynomial_8!(
2138 x, P0logf, P1logf, P2logf, P3logf, P4logf, P5logf, P6logf, P7logf, P8logf
2139 );
2140 let lg1 = lg1 * x2 * x;
2141
2142 let ef = x1.exponent();
2143 let ef = mask.blend(ef + f32x4::ONE, ef);
2144
2145 let e1 = (ef * y).round();
2146 let yr = ef.mul_sub(y, e1);
2147
2148 let lg = f32x4::HALF.mul_neg_add(x2, x) + lg1;
2149 let x2_err = (f32x4::HALF * x).mul_sub(x, f32x4::HALF * x2);
2150 let lg_err = f32x4::HALF.mul_add(x2, lg - x) - lg1;
2151
2152 let e2 = (lg * y * f32x4::LOG2_E).round();
2153 let v = lg.mul_sub(y, e2 * ln2f_hi);
2154 let v = e2.mul_neg_add(ln2f_lo, v);
2155 let v = v - (lg_err + x2_err).mul_sub(y, yr * f32x4::LN_2);
2156
2157 let x = v;
2158 let e3 = (x * f32x4::LOG2_E).round();
2159 let x = e3.mul_neg_add(f32x4::LN_2, x);
2160 let x2 = x * x;
2161 let z = x2.mul_add(
2162 polynomial_5!(x, p2expf, p3expf, p4expf, p5expf, p6expf, p7expf),
2163 x + f32x4::ONE,
2164 );
2165
2166 let ee = e1 + e2 + e3;
2167 let ei = cast::<_, i32x4>(ee.round_int());
2168 let ej = cast::<_, i32x4>(ei + (cast::<_, i32x4>(z) >> 23));
2169
2170 let overflow = cast::<_, f32x4>(ej.simd_gt(i32x4::splat(0x0FF)))
2171 | (ee.simd_gt(f32x4::splat(300.0)));
2172 let underflow = cast::<_, f32x4>(ej.simd_lt(i32x4::splat(0x000)))
2173 | (ee.simd_lt(f32x4::splat(-300.0)));
2174
2175 let z = cast::<_, f32x4>(cast::<_, i32x4>(z) + (ei << 23));
2177
2178 let z = if (overflow | underflow).any() {
2180 let z = underflow.blend(f32x4::ZERO, z);
2181 overflow.blend(Self::infinity(), z)
2182 } else {
2183 z
2184 };
2185
2186 let x_zero = self.is_zero_or_subnormal();
2188 let z = x_zero.blend(
2189 y.simd_lt(f32x4::ZERO).blend(
2190 Self::infinity(),
2191 y.simd_eq(f32x4::ZERO).blend(f32x4::ONE, f32x4::ZERO),
2192 ),
2193 z,
2194 );
2195
2196 let x_sign = self.is_sign_negative();
2197 let z = if x_sign.any() {
2198 let yi = y.simd_eq(y.round());
2200 let y_odd = cast::<_, i32x4>(y.round_int() << 31).round_float();
2202
2203 let z1 =
2204 yi.blend(z | y_odd, self.simd_eq(Self::ZERO).blend(z, Self::nan_pow()));
2205 x_sign.blend(z1, z)
2206 } else {
2207 z
2208 };
2209
2210 let x_finite = self.is_finite();
2211 let y_finite = y.is_finite();
2212 let e_finite = ee.is_finite();
2213 if (x_finite & y_finite & (e_finite | x_zero)).all() {
2214 return z;
2215 }
2216
2217 (self.is_nan() | y.is_nan()).blend(self + y, z)
2218 }
2219
2220 #[inline]
2221 pub fn powf(self, y: f32) -> Self {
2222 Self::pow_f32x4(self, f32x4::splat(y))
2223 }
2224
2225 #[must_use]
2226 #[inline]
2227 pub fn unpack_lo(self, b: Self) -> Self {
2228 pick! {
2229 if #[cfg(target_feature="sse")] {
2230 Self { sse: unpack_low_m128(self.sse, b.sse) }
2231 } else if #[cfg(target_feature="simd128")] {
2232 Self {
2233 simd: u32x4_shuffle::<0, 4, 1, 5>(self.simd, b.simd)
2234 }
2235 } else if #[cfg(all(target_feature="neon", target_arch="aarch64"))]{
2236 unsafe {Self { neon: vzip1q_f32(self.neon, b.neon) }}
2237 } else {
2238 Self { arr: [
2239 self.arr[0],
2240 b.arr[0],
2241 self.arr[1],
2242 b.arr[1],
2243 ]}
2244 }
2245 }
2246 }
2247
2248 #[must_use]
2249 #[inline]
2250 pub fn unpack_hi(self, b: Self) -> Self {
2251 pick! {
2252 if #[cfg(target_feature="sse")] {
2253 Self { sse: unpack_high_m128(self.sse, b.sse) }
2254 } else if #[cfg(target_feature="simd128")] {
2255 Self {
2256 simd: u32x4_shuffle::<2, 6, 3, 7>(self.simd, b.simd)
2257 }
2258 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
2259 unsafe {Self { neon: vzip2q_f32(self.neon, b.neon) }}
2260 } else {
2261 Self { arr: [
2262 self.arr[2],
2263 b.arr[2],
2264 self.arr[3],
2265 b.arr[3],
2266 ]}
2267 }
2268 }
2269 }
2270
2271 #[must_use]
2273 #[inline]
2274 pub fn transpose(data: [f32x4; 4]) -> [f32x4; 4] {
2275 pick! {
2276 if #[cfg(target_feature="sse")] {
2277 let mut e0 = data[0];
2278 let mut e1 = data[1];
2279 let mut e2 = data[2];
2280 let mut e3 = data[3];
2281
2282 transpose_four_m128(&mut e0.sse, &mut e1.sse, &mut e2.sse, &mut e3.sse);
2283
2284 [e0, e1, e2, e3]
2285 } else if #[cfg(any(all(target_feature="neon",target_arch="aarch64"), target_feature="simd128"))] {
2286 let a = data[0].unpack_lo(data[2]);
2287 let b = data[1].unpack_lo(data[3]);
2288 let c = data[0].unpack_hi(data[2]);
2289 let d = data[1].unpack_hi(data[3]);
2290
2291 [
2292 a.unpack_lo(b),
2293 a.unpack_hi(b),
2294 c.unpack_lo(d),
2295 c.unpack_hi(d),
2296 ]
2297 } else {
2298 #[inline(always)]
2299 fn transpose_column(data: &[f32x4; 4], index: usize) -> f32x4 {
2300 f32x4::new([
2301 data[0].as_array()[index],
2302 data[1].as_array()[index],
2303 data[2].as_array()[index],
2304 data[3].as_array()[index],
2305 ])
2306 }
2307
2308 [
2309 transpose_column(&data, 0),
2310 transpose_column(&data, 1),
2311 transpose_column(&data, 2),
2312 transpose_column(&data, 3),
2313 ]
2314 }
2315 }
2316 }
2317
2318 #[inline]
2319 pub fn to_array(self) -> [f32; 4] {
2320 cast(self)
2321 }
2322
2323 #[inline]
2324 pub fn as_array(&self) -> &[f32; 4] {
2325 cast_ref(self)
2326 }
2327
2328 #[inline]
2329 pub fn as_mut_array(&mut self) -> &mut [f32; 4] {
2330 cast_mut(self)
2331 }
2332
2333 #[inline]
2334 pub fn from_i32x4(v: i32x4) -> Self {
2335 pick! {
2336 if #[cfg(target_feature="sse2")] {
2337 Self { sse: convert_to_m128_from_i32_m128i(v.sse) }
2338 } else if #[cfg(target_feature="simd128")] {
2339 Self { simd: f32x4_convert_i32x4(v.simd) }
2340 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
2341 Self { neon: unsafe { vcvtq_f32_s32(v.neon) }}
2342 } else {
2343 Self { arr: [
2344 v.as_array()[0] as f32,
2345 v.as_array()[1] as f32,
2346 v.as_array()[2] as f32,
2347 v.as_array()[3] as f32,
2348 ] }
2349 }
2350 }
2351 }
2352
2353 #[inline]
2360 #[must_use]
2361 #[deprecated(since = "1.4.0", note = "renamed to `is_sign_negative`")]
2362 pub fn sign_bit(self) -> Self {
2363 self.is_sign_negative()
2364 }
2365}