1use super::*;
2
3pick! {
4 if #[cfg(target_feature="sse")] {
5 #[derive(Default, Clone, Copy, PartialEq)]
12 #[repr(C, align(16))]
13 pub struct f32x4 { pub(crate) sse: m128 }
14 } else if #[cfg(target_feature="simd128")] {
15 use core::arch::wasm32::*;
16
17 #[derive(Clone, Copy)]
24 #[repr(transparent)]
25 pub struct f32x4 { pub(crate) simd: v128 }
26
27 impl Default for f32x4 {
28 fn default() -> Self {
29 Self::splat(0.0)
30 }
31 }
32
33 impl PartialEq for f32x4 {
34 fn eq(&self, other: &Self) -> bool {
35 u32x4_all_true(f32x4_eq(self.simd, other.simd))
36 }
37 }
38 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
39 use core::arch::aarch64::*;
40
41 #[repr(C)]
48 #[derive(Copy, Clone)]
49 pub struct f32x4 { pub(crate) neon : float32x4_t }
50
51 impl Default for f32x4 {
52 #[inline]
53 fn default() -> Self {
54 unsafe { Self { neon: vdupq_n_f32(0.0)} }
55 }
56 }
57
58 impl PartialEq for f32x4 {
59 #[inline]
60 fn eq(&self, other: &Self) -> bool {
61 unsafe { vminvq_u32(vceqq_f32(self.neon, other.neon))==u32::MAX }
62 }
63
64 }
65 } else {
66 #[derive(Default, Clone, Copy, PartialEq)]
73 #[repr(C, align(16))]
74 pub struct f32x4 { pub(crate) arr: [f32;4] }
75 }
76}
77
78macro_rules! const_f32_as_f32x4 {
79 ($i:ident, $f:expr) => {
80 #[allow(non_upper_case_globals)]
81 pub const $i: f32x4 = f32x4::new([$f; 4]);
82 };
83}
84
85impl_simd! {
86 unsafe {
87 T = f32,
88 N = 4,
89 Simd = f32x4,
90 optional_type_x86_inner { X86Inner = __m128 },
91 optional_type_arm_inner { ArmInner = float32x4_t },
92 optional_type_wasm_inner { WasmInner = v128 },
93 }
94
95 #[inline]
96 fn simd_eq(self, rhs: Self) -> Self::Output {
97 pick! {
98 if #[cfg(target_feature="sse")] {
99 Self { sse: cmp_eq_mask_m128(self.sse, rhs.sse) }
100 } else if #[cfg(target_feature="simd128")] {
101 Self { simd: f32x4_eq(self.simd, rhs.simd) }
102 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
103 unsafe {Self { neon: vreinterpretq_f32_u32(vceqq_f32(self.neon, rhs.neon)) }}
104 } else {
105 Self { arr: [
106 if self.arr[0] == rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
107 if self.arr[1] == rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
108 if self.arr[2] == rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
109 if self.arr[3] == rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
110 ]}
111 }
112 }
113 }
114
115 #[inline]
116 fn simd_ne(self, rhs: Self) -> Self::Output {
117 pick! {
118 if #[cfg(target_feature="sse")] {
119 Self { sse: cmp_neq_mask_m128(self.sse, rhs.sse) }
120 } else if #[cfg(target_feature="simd128")] {
121 Self { simd: f32x4_ne(self.simd, rhs.simd) }
122 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
123 unsafe {Self { neon: vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(self.neon, rhs.neon))) }}
124 } else {
125 Self { arr: [
126 if self.arr[0] != rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
127 if self.arr[1] != rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
128 if self.arr[2] != rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
129 if self.arr[3] != rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
130 ]}
131 }
132 }
133 }
134
135 #[inline]
136 fn simd_lt(self, rhs: Self) -> Self::Output {
137 pick! {
138 if #[cfg(target_feature="sse")] {
139 Self { sse: cmp_lt_mask_m128(self.sse, rhs.sse) }
140 } else if #[cfg(target_feature="simd128")] {
141 Self { simd: f32x4_lt(self.simd, rhs.simd) }
142 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
143 unsafe {Self { neon: vreinterpretq_f32_u32(vcltq_f32(self.neon, rhs.neon)) }}
144 } else {
145 Self { arr: [
146 if self.arr[0] < rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
147 if self.arr[1] < rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
148 if self.arr[2] < rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
149 if self.arr[3] < rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
150 ]}
151 }
152 }
153 }
154
155 #[inline]
156 fn simd_gt(self, rhs: Self) -> Self::Output {
157 pick! {
158 if #[cfg(target_feature="sse")] {
159 Self { sse: cmp_gt_mask_m128(self.sse, rhs.sse) }
160 } else if #[cfg(target_feature="simd128")] {
161 Self { simd: f32x4_gt(self.simd, rhs.simd) }
162 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
163 unsafe {Self { neon: vreinterpretq_f32_u32(vcgtq_f32(self.neon, rhs.neon)) }}
164 } else {
165 Self { arr: [
166 if self.arr[0] > rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
167 if self.arr[1] > rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
168 if self.arr[2] > rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
169 if self.arr[3] > rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
170 ]}
171 }
172 }
173 }
174
175 #[inline]
176 fn simd_le(self, rhs: Self) -> Self::Output {
177 pick! {
178 if #[cfg(target_feature="sse")] {
179 Self { sse: cmp_le_mask_m128(self.sse, rhs.sse) }
180 } else if #[cfg(target_feature="simd128")] {
181 Self { simd: f32x4_le(self.simd, rhs.simd) }
182 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
183 unsafe {Self { neon: vreinterpretq_f32_u32(vcleq_f32(self.neon, rhs.neon)) }}
184 } else {
185 Self { arr: [
186 if self.arr[0] <= rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
187 if self.arr[1] <= rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
188 if self.arr[2] <= rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
189 if self.arr[3] <= rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
190 ]}
191 }
192 }
193 }
194
195 #[inline]
196 fn simd_ge(self, rhs: Self) -> Self::Output {
197 pick! {
198 if #[cfg(target_feature="sse")] {
199 Self { sse: cmp_ge_mask_m128(self.sse, rhs.sse) }
200 } else if #[cfg(target_feature="simd128")] {
201 Self { simd: f32x4_ge(self.simd, rhs.simd) }
202 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
203 unsafe {Self { neon: vreinterpretq_f32_u32(vcgeq_f32(self.neon, rhs.neon)) }}
204 } else {
205 Self { arr: [
206 if self.arr[0] >= rhs.arr[0] { f32::from_bits(u32::MAX) } else { 0.0 },
207 if self.arr[1] >= rhs.arr[1] { f32::from_bits(u32::MAX) } else { 0.0 },
208 if self.arr[2] >= rhs.arr[2] { f32::from_bits(u32::MAX) } else { 0.0 },
209 if self.arr[3] >= rhs.arr[3] { f32::from_bits(u32::MAX) } else { 0.0 },
210 ]}
211 }
212 }
213 }
214
215 #[inline]
216 pub fn bitselect(self, if_one: Self, if_zero: Self) -> Self {
217 pick! {
218 if #[cfg(target_feature="sse2")] {
219 Self {
220 sse: bitor_m128(
221 bitand_m128(if_one.sse, self.sse),
222 bitandnot_m128(self.sse, if_zero.sse),
223 ),
224 }
225 } else if #[cfg(target_feature="simd128")] {
226 Self { simd: v128_bitselect(if_one.simd, if_zero.simd, self.simd) }
227 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
228 unsafe {Self { neon: vbslq_f32(vreinterpretq_u32_f32(self.neon), if_one.neon, if_zero.neon) }}
229 } else {
230 generic_bit_blend(self, if_one, if_zero)
231 }
232 }
233 }
234
235 #[inline]
236 pub fn select(self, if_true: Self, if_false: Self) -> Self {
237 pick! {
238 if #[cfg(target_feature="sse4.1")] {
239 Self { sse: blend_varying_m128(if_false.sse, if_true.sse, self.sse) }
240 } else if #[cfg(target_feature="simd128")] {
241 Self { simd: v128_bitselect(if_true.simd, if_false.simd, self.simd) }
242 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
243 unsafe {Self { neon: vbslq_f32(vreinterpretq_u32_f32(self.neon), if_true.neon, if_false.neon) }}
244 } else {
245 generic_bit_blend(self, if_true, if_false)
246 }
247 }
248 }
249
250 #[inline]
251 pub fn to_bitmask(self) -> u32 {
252 pick! {
253 if #[cfg(target_feature="sse")] {
254 move_mask_m128(self.sse) as u32
255 } else if #[cfg(target_feature="simd128")] {
256 u32x4_bitmask(self.simd) as u32
257 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
258 unsafe
259 {
260 let masked = vcltq_s32( vreinterpretq_s32_f32(self.neon), vdupq_n_s32(0));
262
263 let selectbit : uint32x4_t = core::mem::transmute([1u32, 2, 4, 8]);
265 let r = vandq_u32(masked, selectbit);
266
267 vaddvq_u32(r) as u32
269 }
270 } else {
271 (((self.arr[0].to_bits() as i32) < 0) as u32) |
272 (((self.arr[1].to_bits() as i32) < 0) as u32) << 1 |
273 (((self.arr[2].to_bits() as i32) < 0) as u32) << 2 |
274 (((self.arr[3].to_bits() as i32) < 0) as u32) << 3
275 }
276 }
277 }
278
279 #[inline]
280 pub fn any(self) -> bool {
281 pick! {
282 if #[cfg(target_feature="simd128")] {
283 v128_any_true(self.simd)
284 } else {
285 self.to_bitmask() != 0
286 }
287 }
288 }
289
290 #[inline]
291 pub fn all(self) -> bool {
292 pick! {
293 if #[cfg(target_feature="simd128")] {
294 u32x4_all_true(self.simd)
295 } else {
296 self.to_bitmask() == 0b1111
298 }
299 }
300 }
301
302 #[inline]
305 pub fn transpose(data: [f32x4; 4]) -> [f32x4; 4] {
306 pick! {
307 if #[cfg(target_feature="sse")] {
308 let mut e0 = data[0];
309 let mut e1 = data[1];
310 let mut e2 = data[2];
311 let mut e3 = data[3];
312
313 transpose_four_m128(&mut e0.sse, &mut e1.sse, &mut e2.sse, &mut e3.sse);
314
315 [e0, e1, e2, e3]
316 } else if #[cfg(any(all(target_feature="neon",target_arch="aarch64"), target_feature="simd128"))] {
317 let a = data[0].unpack_lo(data[2]);
318 let b = data[1].unpack_lo(data[3]);
319 let c = data[0].unpack_hi(data[2]);
320 let d = data[1].unpack_hi(data[3]);
321
322 [
323 a.unpack_lo(b),
324 a.unpack_hi(b),
325 c.unpack_lo(d),
326 c.unpack_hi(d),
327 ]
328 } else {
329 #[inline(always)]
330 fn transpose_column(data: &[f32x4; 4], index: usize) -> f32x4 {
331 f32x4::new([
332 data[0].as_array()[index],
333 data[1].as_array()[index],
334 data[2].as_array()[index],
335 data[3].as_array()[index],
336 ])
337 }
338
339 [
340 transpose_column(&data, 0),
341 transpose_column(&data, 1),
342 transpose_column(&data, 2),
343 transpose_column(&data, 3),
344 ]
345 }
346 }
347 }
348}
349
350impl_simd_float! {
351 unsafe {
352 T = f32,
353 N = 4,
354 Simd = f32x4,
355 UnsignedT = u32,
356 UnsignedSimd = u32x4,
357 }
358 old_powf_simd_fn_name = pow_f32x4,
359
360 #[inline]
361 fn neg(self) -> Self::Output {
362 pick! {
363 if #[cfg(target_feature="sse")] {
364 Self { sse: bitxor_m128(self.sse, Self::splat(-0.0).sse) }
365 } else if #[cfg(target_feature="simd128")] {
366 Self { simd: f32x4_neg(self.simd) }
367 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
368 unsafe {Self { neon: vnegq_f32(self.neon) }}
369 } else {
370 Self { arr: [
371 -self.arr[0],
372 -self.arr[1],
373 -self.arr[2],
374 -self.arr[3],
375 ]}
376 }
377 }
378 }
379
380 #[inline]
381 fn not(self) -> Self::Output {
382 self ^ cast::<u128, f32x4>(u128::MAX)
383 }
384
385 #[inline]
386 fn add(self, rhs: Self) -> Self::Output {
387 pick! {
388 if #[cfg(target_feature="sse")] {
389 Self { sse: add_m128(self.sse, rhs.sse) }
390 } else if #[cfg(target_feature="simd128")] {
391 Self { simd: f32x4_add(self.simd, rhs.simd) }
392 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
393 unsafe { Self { neon: vaddq_f32(self.neon, rhs.neon) } }
394 } else {
395 Self { arr: [
396 self.arr[0] + rhs.arr[0],
397 self.arr[1] + rhs.arr[1],
398 self.arr[2] + rhs.arr[2],
399 self.arr[3] + rhs.arr[3],
400 ]}
401 }
402 }
403 }
404
405 #[inline]
406 fn sub(self, rhs: Self) -> Self::Output {
407 pick! {
408 if #[cfg(target_feature="sse")] {
409 Self { sse: sub_m128(self.sse, rhs.sse) }
410 } else if #[cfg(target_feature="simd128")] {
411 Self { simd: f32x4_sub(self.simd, rhs.simd) }
412 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
413 unsafe {Self { neon: vsubq_f32(self.neon, rhs.neon) }}
414 } else {
415 Self { arr: [
416 self.arr[0] - rhs.arr[0],
417 self.arr[1] - rhs.arr[1],
418 self.arr[2] - rhs.arr[2],
419 self.arr[3] - rhs.arr[3],
420 ]}
421 }
422 }
423 }
424
425 #[inline]
426 fn mul(self, rhs: Self) -> Self::Output {
427 pick! {
428 if #[cfg(target_feature="sse")] {
429 Self { sse: mul_m128(self.sse, rhs.sse) }
430 } else if #[cfg(target_feature="simd128")] {
431 Self { simd: f32x4_mul(self.simd, rhs.simd) }
432 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
433 unsafe {Self { neon: vmulq_f32(self.neon, rhs.neon) }}
434 } else {
435 Self { arr: [
436 self.arr[0] * rhs.arr[0],
437 self.arr[1] * rhs.arr[1],
438 self.arr[2] * rhs.arr[2],
439 self.arr[3] * rhs.arr[3],
440 ]}
441 }
442 }
443 }
444
445 #[inline]
446 fn div(self, rhs: Self) -> Self::Output {
447 pick! {
448 if #[cfg(target_feature="sse")] {
449 Self { sse: div_m128(self.sse, rhs.sse) }
450 } else if #[cfg(target_feature="simd128")] {
451 Self { simd: f32x4_div(self.simd, rhs.simd) }
452 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
453 unsafe {Self { neon: vdivq_f32(self.neon, rhs.neon) }}
454 } else {
455 Self { arr: [
456 self.arr[0] / rhs.arr[0],
457 self.arr[1] / rhs.arr[1],
458 self.arr[2] / rhs.arr[2],
459 self.arr[3] / rhs.arr[3],
460 ]}
461 }
462 }
463 }
464
465 #[inline]
466 fn rem(self, rhs: Self) -> Self::Output {
467 Self::new([
468 self.to_array()[0] % rhs.to_array()[0],
469 self.to_array()[1] % rhs.to_array()[1],
470 self.to_array()[2] % rhs.to_array()[2],
471 self.to_array()[3] % rhs.to_array()[3],
472 ])
473 }
474
475 #[inline]
476 fn bitand(self, rhs: Self) -> Self::Output {
477 pick! {
478 if #[cfg(target_feature="sse")] {
479 Self { sse: bitand_m128(self.sse, rhs.sse) }
480 } else if #[cfg(target_feature="simd128")] {
481 Self { simd: v128_and(self.simd, rhs.simd) }
482 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
483 unsafe {Self { neon: vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(self.neon), vreinterpretq_u32_f32(rhs.neon))) }}
484 } else {
485 Self { arr: [
486 f32::from_bits(self.arr[0].to_bits() & rhs.arr[0].to_bits()),
487 f32::from_bits(self.arr[1].to_bits() & rhs.arr[1].to_bits()),
488 f32::from_bits(self.arr[2].to_bits() & rhs.arr[2].to_bits()),
489 f32::from_bits(self.arr[3].to_bits() & rhs.arr[3].to_bits()),
490 ]}
491 }
492 }
493 }
494
495 #[inline]
496 fn bitor(self, rhs: Self) -> Self::Output {
497 pick! {
498 if #[cfg(target_feature="sse")] {
499 Self { sse: bitor_m128(self.sse, rhs.sse) }
500 } else if #[cfg(target_feature="simd128")] {
501 Self { simd: v128_or(self.simd, rhs.simd) }
502 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
503 unsafe {Self { neon: vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(self.neon), vreinterpretq_u32_f32(rhs.neon))) }}
504 } else {
505 Self { arr: [
506 f32::from_bits(self.arr[0].to_bits() | rhs.arr[0].to_bits()),
507 f32::from_bits(self.arr[1].to_bits() | rhs.arr[1].to_bits()),
508 f32::from_bits(self.arr[2].to_bits() | rhs.arr[2].to_bits()),
509 f32::from_bits(self.arr[3].to_bits() | rhs.arr[3].to_bits()),
510 ]}
511 }
512 }
513 }
514
515 #[inline]
516 fn bitxor(self, rhs: Self) -> Self::Output {
517 pick! {
518 if #[cfg(target_feature="sse")] {
519 Self { sse: bitxor_m128(self.sse, rhs.sse) }
520 } else if #[cfg(target_feature="simd128")] {
521 Self { simd: v128_xor(self.simd, rhs.simd) }
522 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
523 unsafe {Self { neon: vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(self.neon), vreinterpretq_u32_f32(rhs.neon))) }}
524 } else {
525 Self { arr: [
526 f32::from_bits(self.arr[0].to_bits() ^ rhs.arr[0].to_bits()),
527 f32::from_bits(self.arr[1].to_bits() ^ rhs.arr[1].to_bits()),
528 f32::from_bits(self.arr[2].to_bits() ^ rhs.arr[2].to_bits()),
529 f32::from_bits(self.arr[3].to_bits() ^ rhs.arr[3].to_bits()),
530 ]}
531 }
532 }
533 }
534
535 #[inline]
536 pub fn reduce_add(self) -> f32 {
537 let arr: [f32; 4] = cast(self);
538 arr.iter().sum()
539 }
540
541 #[inline]
542 pub fn reduce_mul(self) -> f32 {
543 let arr: [f32; 4] = cast(self);
544 arr.iter().product()
545 }
546
547 #[inline]
548 pub fn is_nan(self) -> Self {
549 pick! {
550 if #[cfg(target_feature="sse")] {
551 Self { sse: cmp_unord_mask_m128(self.sse, self.sse) }
552 } else if #[cfg(target_feature="simd128")] {
553 Self { simd: f32x4_ne(self.simd, self.simd) }
554 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
555 unsafe {Self { neon: vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(self.neon, self.neon))) }}
556 } else {
557 Self { arr: [
558 if self.arr[0].is_nan() { f32::from_bits(u32::MAX) } else { 0.0 },
559 if self.arr[1].is_nan() { f32::from_bits(u32::MAX) } else { 0.0 },
560 if self.arr[2].is_nan() { f32::from_bits(u32::MAX) } else { 0.0 },
561 if self.arr[3].is_nan() { f32::from_bits(u32::MAX) } else { 0.0 },
562 ]}
563 }
564 }
565 }
566
567 #[inline]
568 pub fn is_inf(self) -> Self {
569 let shifted_inf = u32x4::from(0xFF000000);
570 let u: u32x4 = cast(self);
571 let shift_u = u << 1_u64;
572 let out = (shift_u).simd_eq(shifted_inf);
573 cast(out)
574 }
575
576 #[inline]
577 pub fn is_finite(self) -> Self {
578 let shifted_exp_mask = u32x4::from(0xFF000000);
579 let u: u32x4 = cast(self);
580 let shift_u = u << 1_u64;
581 let out = !(shift_u & shifted_exp_mask).simd_eq(shifted_exp_mask);
582 cast(out)
583 }
584
585 #[inline]
586 pub fn is_sign_positive(self) -> Self {
587 const SIGN_MASK: u32x4 = u32x4::splat((-0.0_f32).to_bits());
588
589 let bits = cast::<f32x4, u32x4>(self);
590 let sign = bits & SIGN_MASK;
591 let result = sign.simd_eq(u32x4::ZERO);
592 cast::<u32x4, f32x4>(result)
593 }
594
595 #[inline]
596 pub fn is_sign_negative(self) -> Self {
597 const SIGN_MASK: u32x4 = u32x4::splat((-0.0_f32).to_bits());
598
599 let bits = cast::<f32x4, u32x4>(self);
600 let sign = bits & SIGN_MASK;
601 let result = sign.simd_eq(SIGN_MASK);
602 cast::<u32x4, f32x4>(result)
603 }
604
605 #[inline]
606 pub fn recip(self) -> Self {
607 pick! {
608 if #[cfg(target_feature="sse")] {
609 Self { sse: reciprocal_m128(self.sse) }
610 } else if #[cfg(target_feature="simd128")] {
611 Self { simd: f32x4_div(f32x4_splat(1.0), self.simd) }
612 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
613 unsafe {Self { neon: vdivq_f32(vdupq_n_f32(1.0), self.neon) }}
614 } else {
615 Self { arr: [
616 1.0 / self.arr[0],
617 1.0 / self.arr[1],
618 1.0 / self.arr[2],
619 1.0 / self.arr[3],
620 ]}
621 }
622 }
623 }
624
625 #[inline]
626 pub fn recip_sqrt(self) -> Self {
627 pick! {
628 if #[cfg(target_feature="sse")] {
629 Self { sse: reciprocal_sqrt_m128(self.sse) }
630 } else if #[cfg(target_feature="simd128")] {
631 Self { simd: f32x4_div(f32x4_splat(1.0), f32x4_sqrt(self.simd)) }
632 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
633 unsafe {Self { neon: vdivq_f32(vdupq_n_f32(1.0), vsqrtq_f32(self.neon)) }}
634 } else if #[cfg(feature="std")] {
635 Self { arr: [
636 1.0 / self.arr[0].sqrt(),
637 1.0 / self.arr[1].sqrt(),
638 1.0 / self.arr[2].sqrt(),
639 1.0 / self.arr[3].sqrt(),
640 ]}
641 } else {
642 Self { arr: [
643 1.0 / software_sqrt(self.arr[0] as f64) as f32,
644 1.0 / software_sqrt(self.arr[1] as f64) as f32,
645 1.0 / software_sqrt(self.arr[2] as f64) as f32,
646 1.0 / software_sqrt(self.arr[3] as f64) as f32,
647 ]}
648 }
649 }
650 }
651
652 #[inline]
653 pub fn max(self, rhs: Self) -> Self {
654 pick! {
655 if #[cfg(target_feature="sse")] {
656 rhs.is_nan().select(self, Self { sse: max_m128(self.sse, rhs.sse) })
660 } else if #[cfg(target_feature="simd128")] {
661 Self {
668 simd: v128_bitselect(
669 rhs.simd,
670 f32x4_pmax(self.simd, rhs.simd),
671 f32x4_ne(self.simd, self.simd), )
673 }
674 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
675 unsafe {Self { neon: vmaxnmq_f32(self.neon, rhs.neon) }}
676 } else {
677 Self { arr: [
678 self.arr[0].max(rhs.arr[0]),
679 self.arr[1].max(rhs.arr[1]),
680 self.arr[2].max(rhs.arr[2]),
681 self.arr[3].max(rhs.arr[3]),
682 ]}
683 }
684 }
685 }
686
687 #[inline]
688 pub fn fast_max(self, rhs: Self) -> Self {
689 pick! {
690 if #[cfg(target_feature="sse")] {
691 Self { sse: max_m128(self.sse, rhs.sse) }
692 } else if #[cfg(target_feature="simd128")] {
693 Self {
694 simd: f32x4_pmax(self.simd, rhs.simd),
695 }
696 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
697 unsafe {Self { neon: vmaxq_f32(self.neon, rhs.neon) }}
698 } else {
699 Self { arr: [
700 if self.arr[0] < rhs.arr[0] { rhs.arr[0] } else { self.arr[0] },
701 if self.arr[1] < rhs.arr[1] { rhs.arr[1] } else { self.arr[1] },
702 if self.arr[2] < rhs.arr[2] { rhs.arr[2] } else { self.arr[2] },
703 if self.arr[3] < rhs.arr[3] { rhs.arr[3] } else { self.arr[3] },
704 ]}
705 }
706 }
707 }
708
709 #[inline]
710 pub fn min(self, rhs: Self) -> Self {
711 pick! {
712 if #[cfg(target_feature="sse")] {
713 rhs.is_nan().select(self, Self { sse: min_m128(self.sse, rhs.sse) })
717 } else if #[cfg(target_feature="simd128")] {
718 Self {
725 simd: v128_bitselect(
726 rhs.simd,
727 f32x4_pmin(self.simd, rhs.simd),
728 f32x4_ne(self.simd, self.simd), )
730 }
731 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
732 unsafe {Self { neon: vminnmq_f32(self.neon, rhs.neon) }}
733 } else {
734 Self { arr: [
735 self.arr[0].min(rhs.arr[0]),
736 self.arr[1].min(rhs.arr[1]),
737 self.arr[2].min(rhs.arr[2]),
738 self.arr[3].min(rhs.arr[3]),
739 ]}
740 }
741 }
742 }
743
744 #[inline]
745 pub fn fast_min(self, rhs: Self) -> Self {
746 pick! {
747 if #[cfg(target_feature="sse")] {
748 Self { sse: min_m128(self.sse, rhs.sse) }
749 } else if #[cfg(target_feature="simd128")] {
750 Self {
751 simd: f32x4_pmin(self.simd, rhs.simd),
752 }
753 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
754 unsafe {Self { neon: vminq_f32(self.neon, rhs.neon) }}
755 } else {
756 Self { arr: [
757 if self.arr[0] < rhs.arr[0] { self.arr[0] } else { rhs.arr[0] },
758 if self.arr[1] < rhs.arr[1] { self.arr[1] } else { rhs.arr[1] },
759 if self.arr[2] < rhs.arr[2] { self.arr[2] } else { rhs.arr[2] },
760 if self.arr[3] < rhs.arr[3] { self.arr[3] } else { rhs.arr[3] },
761 ]}
762 }
763 }
764 }
765
766 #[inline]
767 pub fn clamp(self, min: Self, max: Self) -> Self {
768 pick! {
769 if #[cfg(any(
770 target_feature="simd128",
771 all(target_feature="neon",target_arch="aarch64"),
772 ))] {
773 self.fast_clamp(min, max)
775 } else {
776 self.fast_clamp(min, max) | min.is_nan() | max.is_nan()
778 }
779 }
780 }
781
782 #[inline]
783 pub fn fast_clamp(self, min: Self, max: Self) -> Self {
784 pick! {
785 if #[cfg(target_feature="sse")] {
786 Self { sse: max_m128(min.sse, min_m128(max.sse, self.sse)) }
789 } else if #[cfg(target_feature="simd128")] {
790 Self { simd: f32x4_max(f32x4_min(self.simd, max.simd), min.simd) }
791 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
792 unsafe { Self { neon: vmaxq_f32(vminq_f32(self.neon, max.neon), min.neon) } }
793 } else {
794 let mut result = self;
797 result = result.simd_gt(max).select(max, result);
798 result = result.simd_lt(min).select(min, result);
799 result
800 }
801 }
802 }
803
804 #[inline]
805 pub fn abs(self) -> Self {
806 pick! {
807 if #[cfg(target_feature="simd128")] {
808 Self { simd: f32x4_abs(self.simd) }
809 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
810 unsafe {Self { neon: vabsq_f32(self.neon) }}
811 } else {
812 let non_sign_bits = f32x4::from(f32::from_bits(i32::MAX as u32));
813 self & non_sign_bits
814 }
815 }
816 }
817
818 #[inline]
819 pub fn floor(self) -> Self {
820 pick! {
821 if #[cfg(target_feature="simd128")] {
822 Self { simd: f32x4_floor(self.simd) }
823 } else if #[cfg(target_feature="sse4.1")] {
824 Self { sse: floor_m128(self.sse) }
825 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
826 unsafe {Self { neon: vrndmq_f32(self.neon) }}
827 } else if #[cfg(feature="std")] {
828 let base: [f32; 4] = cast(self);
829 cast(base.map(|val| val.floor()))
830 } else {
831 let base: [f32; 4] = cast(self);
832 let rounded: [f32; 4] = cast(self.round());
833 cast([
834 if base[0] < rounded[0] { rounded[0] - 1.0 } else { rounded[0] },
835 if base[1] < rounded[1] { rounded[1] - 1.0 } else { rounded[1] },
836 if base[2] < rounded[2] { rounded[2] - 1.0 } else { rounded[2] },
837 if base[3] < rounded[3] { rounded[3] - 1.0 } else { rounded[3] },
838 ])
839 }
840 }
841 }
842
843 #[inline]
844 pub fn ceil(self) -> Self {
845 pick! {
846 if #[cfg(target_feature="simd128")] {
847 Self { simd: f32x4_ceil(self.simd) }
848 } else if #[cfg(target_feature="sse4.1")] {
849 Self { sse: ceil_m128(self.sse) }
850 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
851 unsafe {Self { neon: vrndpq_f32(self.neon) }}
852 } else if #[cfg(feature="std")] {
853 let base: [f32; 4] = cast(self);
854 cast(base.map(|val| val.ceil()))
855 } else {
856 let base: [f32; 4] = cast(self);
857 let rounded: [f32; 4] = cast(self.round());
858 cast([
859 if base[0] > rounded[0] { rounded[0] + 1.0 } else { rounded[0] },
860 if base[1] > rounded[1] { rounded[1] + 1.0 } else { rounded[1] },
861 if base[2] > rounded[2] { rounded[2] + 1.0 } else { rounded[2] },
862 if base[3] > rounded[3] { rounded[3] + 1.0 } else { rounded[3] },
863 ])
864 }
865 }
866 }
867
868 #[inline]
869 pub fn round(self) -> Self {
870 pick! {
871 if #[cfg(target_feature="sse4.1")] {
872 const_f32_as_f32x4!(HALF_NEXT_DOWN, 0.5_f32.next_down());
873 const_f32_as_f32x4!(BOUNDS_LIMIT, 8388608.0);
874
875 let self_abs = self.abs();
876
877 let adjusted_self = self_abs + Self::HALF;
878 let result_abs = Self { sse: round_m128::<{round_op!(Zero)}>(adjusted_self.sse) };
879 let result_abs = result_abs & self_abs.simd_ne(HALF_NEXT_DOWN);
882
883 let bounds_mask: Self = cast(cmp_lt_mask_i32_m128i(cast(self_abs), cast(BOUNDS_LIMIT)));
885
886 bounds_mask.abs().bitselect(result_abs, self)
888 } else if #[cfg(target_feature="sse2")] {
889 const_f32_as_f32x4!(HALF_NEXT_DOWN, 0.5_f32.next_down());
890 const_f32_as_f32x4!(BOUNDS_LIMIT, 8388608.0);
891
892 let self_abs = self.abs();
893
894 let adjusted_self = self_abs + Self::HALF;
895 let result_abs = Self {
896 sse: convert_to_m128_from_i32_m128i(truncate_m128_to_m128i(adjusted_self.sse)),
897 };
898 let result_abs = result_abs & self_abs.simd_ne(HALF_NEXT_DOWN);
901
902 let bounds_mask: Self = cast(cmp_lt_mask_i32_m128i(cast(self_abs), cast(BOUNDS_LIMIT)));
904
905 bounds_mask.abs().bitselect(result_abs, self)
907 } else if #[cfg(target_feature="simd128")] {
908 const_f32_as_f32x4!(HALF_NEXT_DOWN, 0.5_f32.next_down());
909 const_f32_as_f32x4!(BOUNDS_LIMIT, 8388608.0);
910
911 let self_abs = self.abs();
912
913 let adjusted_self = self_abs + Self::HALF;
914 let result_abs = Self { simd: f32x4_trunc(adjusted_self.simd) };
915 let result_abs = result_abs & self_abs.simd_ne(HALF_NEXT_DOWN);
918
919 let bounds_mask = Self { simd: i32x4_lt(self_abs.simd, BOUNDS_LIMIT.simd) };
921
922 bounds_mask.abs().bitselect(result_abs, self)
924 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
925 unsafe {Self { neon: vrndaq_f32(self.neon) }}
926 } else {
927 const_f32_as_f32x4!(HALF_NEXT_DOWN, 0.5_f32.next_down());
928 const_f32_as_f32x4!(BOUNDS_LIMIT, 8388608.0);
929
930 let self_abs = self.abs();
931
932 let adjusted_self = (self_abs + Self::HALF).to_array();
933 let result_abs = Self::new([
934 adjusted_self[0] as u32 as f32,
935 adjusted_self[1] as u32 as f32,
936 adjusted_self[2] as u32 as f32,
937 adjusted_self[3] as u32 as f32,
938 ]);
939 let result_abs = result_abs & self_abs.simd_ne(HALF_NEXT_DOWN);
942
943 let bounds_mask: Self = cast(cast::<_, i32x4>(self_abs).simd_lt(cast::<_, i32x4>(BOUNDS_LIMIT)));
945
946 bounds_mask.abs().bitselect(result_abs, self)
948 }
949 }
950 }
951
952 #[inline]
953 pub fn round_int(self) -> i32x4 {
954 pick! {
955 if #[cfg(target_feature="sse2")] {
956 let non_nan_mask = self.simd_eq(self);
958 let non_nan = self & non_nan_mask;
959 let flip_to_max: i32x4 = cast(self.simd_ge(Self::splat(2147483648.0)));
960 let cast: i32x4 = cast(convert_to_i32_m128i_from_m128(non_nan.sse));
961 flip_to_max ^ cast
962 } else if #[cfg(target_feature="simd128")] {
963 cast(Self { simd: i32x4_trunc_sat_f32x4(f32x4_nearest(self.simd)) })
964 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
965 cast(unsafe {Self { neon: vreinterpretq_f32_s32(vcvtnq_s32_f32(self.neon)) }})
966 } else {
967 let rounded: [f32; 4] = cast(self.round());
968 cast([
969 rounded[0] as i32,
970 rounded[1] as i32,
971 rounded[2] as i32,
972 rounded[3] as i32,
973 ])
974 }
975 }
976 }
977
978 #[inline]
979 pub fn fast_round_int(self) -> i32x4 {
980 pick! {
981 if #[cfg(target_feature="sse2")] {
982 cast(convert_to_i32_m128i_from_m128(self.sse))
983 } else {
984 self.round_int()
985 }
986 }
987 }
988
989 #[inline]
990 pub fn round_ties_even(self) -> Self {
991 pick! {
992 if #[cfg(target_feature="sse4.1")] {
993 Self { sse: round_m128::<{round_op!(Nearest)}>(self.sse) }
994 } else if #[cfg(target_feature="sse2")] {
995 let mi: m128i = convert_to_i32_m128i_from_m128(self.sse);
996 let f: f32x4 = f32x4 { sse: convert_to_m128_from_i32_m128i(mi) };
997 let i: i32x4 = cast(mi);
998 let mask: f32x4 = cast(i.simd_eq(i32x4::from(0x80000000_u32 as i32)));
999 mask.select(self, f)
1000 } else if #[cfg(target_feature="simd128")] {
1001 Self { simd: f32x4_nearest(self.simd) }
1002 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1003 unsafe {Self { neon: vrndnq_f32(self.neon) }}
1004 } else {
1005 let to_int = f32x4::from(1.0 / f32::EPSILON);
1009 let u: u32x4 = cast(self);
1010 let e: i32x4 = cast((u >> 23) & u32x4::from(0xff));
1011 let mut y: f32x4;
1012
1013 let no_op_magic = i32x4::from(0x7f + 23);
1014 let no_op_mask: f32x4 = cast(e.simd_gt(no_op_magic) | e.simd_eq(no_op_magic));
1015 let no_op_val: f32x4 = self;
1016
1017 let zero_magic = i32x4::from(0x7f - 1);
1018 let zero_mask: f32x4 = cast(e.simd_lt(zero_magic));
1019 let zero_val: f32x4 = self * f32x4::from(0.0);
1020
1021 let neg_bit: f32x4 = cast(cast::<u32x4, i32x4>(u).simd_lt(i32x4::default()));
1022 let x: f32x4 = neg_bit.select(-self, self);
1023 y = x + to_int - to_int - x;
1024 y = y.simd_gt(f32x4::from(0.5)).select(
1025 y + x - f32x4::from(-1.0),
1026 y.simd_lt(f32x4::from(-0.5)).select(y + x + f32x4::from(1.0), y + x),
1027 );
1028 y = neg_bit.select(-y, y);
1029
1030 no_op_mask.select(no_op_val, zero_mask.select(zero_val, y))
1031 }
1032 }
1033 }
1034
1035 #[inline]
1036 pub fn trunc(self) -> Self {
1037 pick! {
1038 if #[cfg(target_feature="sse4.1")] {
1039 Self { sse: round_m128::<{round_op!(Zero)}>(self.sse) }
1040 } else if #[cfg(target_feature="sse2")] {
1041 let result: Self = cast(convert_to_m128_from_i32_m128i(truncate_m128_to_m128i(self.sse)));
1044
1045 let bounds_mask: Self = cast(cmp_lt_mask_i32_m128i(
1047 cast(self.abs()),
1048 set_splat_i32_m128i(8388608_f32.to_bits() as i32),
1049 ));
1050
1051 bounds_mask.abs().select(result, self)
1053 } else if #[cfg(target_feature="simd128")] {
1054 Self { simd: f32x4_trunc(self.simd) }
1055 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1056 unsafe { Self { neon: vrndq_f32(self.neon) } }
1057 } else {
1058 let array: [f32; 4] = cast(self);
1059 let result: Self = cast([
1060 array[0] as i32 as f32,
1061 array[1] as i32 as f32,
1062 array[2] as i32 as f32,
1063 array[3] as i32 as f32,
1064 ]);
1065
1066 const BOUNDS_LIMIT: i32 = 8388608_f32.to_bits() as i32;
1068 let bounds_mask: Self = cast(cast::<f32x4, i32x4>(self.abs()).simd_lt(i32x4::splat(BOUNDS_LIMIT)));
1069
1070 bounds_mask.abs().select(result, self)
1072 }
1073 }
1074 }
1075
1076 #[inline]
1077 pub fn trunc_int(self) -> i32x4 {
1078 pick! {
1079 if #[cfg(target_feature="sse2")] {
1080 let non_nan_mask = self.simd_eq(self);
1082 let non_nan = self & non_nan_mask;
1083 let flip_to_max: i32x4 = cast(self.simd_ge(Self::splat(2147483648.0)));
1084 let cast: i32x4 = cast(truncate_m128_to_m128i(non_nan.sse));
1085 flip_to_max ^ cast
1086 } else if #[cfg(target_feature="simd128")] {
1087 cast(Self { simd: i32x4_trunc_sat_f32x4(self.simd) })
1088 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1089 cast(unsafe {Self { neon: vreinterpretq_f32_s32(vcvtq_s32_f32(self.neon)) }})
1090 } else {
1091 let n: [f32;4] = cast(self);
1092 cast([
1093 n[0] as i32,
1094 n[1] as i32,
1095 n[2] as i32,
1096 n[3] as i32,
1097 ])
1098 }
1099 }
1100 }
1101
1102 #[inline]
1103 pub fn fast_trunc_int(self) -> i32x4 {
1104 pick! {
1105 if #[cfg(target_feature="sse2")] {
1106 cast(truncate_m128_to_m128i(self.sse))
1107 } else {
1108 self.trunc_int()
1109 }
1110 }
1111 }
1112
1113 #[inline]
1121 pub fn mul_add(self, a: Self, b: Self) -> Self {
1122 pick! {
1123 if #[cfg(all(target_feature="sse2",target_feature="fma"))] {
1124 Self { sse: fused_mul_add_m128(self.sse, a.sse, b.sse) }
1125 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1126 unsafe { Self { neon: vfmaq_f32(b.neon, self.neon, a.neon) } }
1127 } else {
1128 (self * a) + b
1129 }
1130 }
1131 }
1132
1133 #[inline]
1142 pub fn mul_sub(self, a: Self, b: Self) -> Self {
1143 pick! {
1144 if #[cfg(all(target_feature="sse2",target_feature="fma"))] {
1145 Self { sse: fused_mul_sub_m128(self.sse, a.sse, b.sse) }
1146 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1147 unsafe { Self { neon: vfmaq_f32(vnegq_f32(b.neon), self.neon, a.neon) } }
1148 } else {
1149 (self * a) - b
1150 }
1151 }
1152 }
1153
1154 #[inline]
1162 pub fn mul_neg_add(self, a: Self, b: Self) -> Self {
1163 pick! {
1164 if #[cfg(all(target_feature="sse2",target_feature="fma"))] {
1165 Self { sse: fused_mul_neg_add_m128(self.sse, a.sse, b.sse) }
1166 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1167 unsafe { Self { neon: vfmsq_f32(b.neon, self.neon, a.neon) } }
1168 } else {
1169 b - (self * a)
1170 }
1171 }
1172 }
1173
1174 #[inline]
1183 pub fn mul_neg_sub(self, a: Self, b: Self) -> Self {
1184 pick! {
1185 if #[cfg(all(target_feature="sse2",target_feature="fma"))] {
1186 Self { sse: fused_mul_neg_sub_m128(self.sse, a.sse, b.sse) }
1187 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1188 unsafe { Self { neon: vnegq_f32(vfmaq_f32(b.neon, self.neon, a.neon)) } }
1189 } else {
1190 -(self * a) - b
1191 }
1192 }
1193 }
1194
1195 #[inline]
1196 pub fn powf_simd(self, n: Self) -> Self {
1197 const_f32_as_f32x4!(ln2f_hi, 0.693359375);
1198 const_f32_as_f32x4!(ln2f_lo, -2.12194440e-4);
1199 const_f32_as_f32x4!(P0logf, 3.3333331174E-1);
1200 const_f32_as_f32x4!(P1logf, -2.4999993993E-1);
1201 const_f32_as_f32x4!(P2logf, 2.0000714765E-1);
1202 const_f32_as_f32x4!(P3logf, -1.6668057665E-1);
1203 const_f32_as_f32x4!(P4logf, 1.4249322787E-1);
1204 const_f32_as_f32x4!(P5logf, -1.2420140846E-1);
1205 const_f32_as_f32x4!(P6logf, 1.1676998740E-1);
1206 const_f32_as_f32x4!(P7logf, -1.1514610310E-1);
1207 const_f32_as_f32x4!(P8logf, 7.0376836292E-2);
1208
1209 const_f32_as_f32x4!(p2expf, 1.0 / 2.0); const_f32_as_f32x4!(p3expf, 1.0 / 6.0);
1211 const_f32_as_f32x4!(p4expf, 1.0 / 24.0);
1212 const_f32_as_f32x4!(p5expf, 1.0 / 120.0);
1213 const_f32_as_f32x4!(p6expf, 1.0 / 720.0);
1214 const_f32_as_f32x4!(p7expf, 1.0 / 5040.0);
1215
1216 let x1 = self.abs();
1217 let x = x1.fraction_2();
1218
1219 let mask = x.simd_gt(f32x4::SQRT_2 * f32x4::HALF);
1220 let x = (!mask).select(x + x, x);
1221
1222 let x = x - f32x4::ONE;
1223 let x2 = x * x;
1224 let lg1 = polynomial_8!(
1225 x, P0logf, P1logf, P2logf, P3logf, P4logf, P5logf, P6logf, P7logf, P8logf
1226 );
1227 let lg1 = lg1 * x2 * x;
1228
1229 let ef = x1.exponent();
1230 let ef = mask.select(ef + f32x4::ONE, ef);
1231
1232 let e1 = (ef * n).round_ties_even();
1233 let yr = ef.mul_sub(n, e1);
1234
1235 let lg = f32x4::HALF.mul_neg_add(x2, x) + lg1;
1236 let x2_err = (f32x4::HALF * x).mul_sub(x, f32x4::HALF * x2);
1237 let lg_err = f32x4::HALF.mul_add(x2, lg - x) - lg1;
1238
1239 let e2 = (lg * n * f32x4::LOG2_E).round_ties_even();
1240 let v = lg.mul_sub(n, e2 * ln2f_hi);
1241 let v = e2.mul_neg_add(ln2f_lo, v);
1242 let v = v - (lg_err + x2_err).mul_sub(n, yr * f32x4::LN_2);
1243
1244 let x = v;
1245 let e3 = (x * f32x4::LOG2_E).round_ties_even();
1246 let x = e3.mul_neg_add(f32x4::LN_2, x);
1247 let x2 = x * x;
1248 let z = x2.mul_add(
1249 polynomial_5!(x, p2expf, p3expf, p4expf, p5expf, p6expf, p7expf),
1250 x + f32x4::ONE,
1251 );
1252
1253 let ee = e1 + e2 + e3;
1254 let ei = cast::<_, i32x4>(ee.round_int());
1255 let ej = cast::<_, i32x4>(ei + (cast::<_, i32x4>(z) >> 23));
1256
1257 let overflow = cast::<_, f32x4>(ej.simd_gt(i32x4::splat(0x0FF)))
1258 | (ee.simd_gt(f32x4::splat(300.0)));
1259 let underflow = cast::<_, f32x4>(ej.simd_lt(i32x4::splat(0x000)))
1260 | (ee.simd_lt(f32x4::splat(-300.0)));
1261
1262 let z = cast::<_, f32x4>(cast::<_, i32x4>(z) + (ei << 23));
1264
1265 let z = if (overflow | underflow).any() {
1267 let z = underflow.select(f32x4::ZERO, z);
1268 overflow.select(Self::infinity(), z)
1269 } else {
1270 z
1271 };
1272
1273 let x_zero = self.is_zero_or_subnormal();
1275 let z = x_zero.select(
1276 n.simd_lt(f32x4::ZERO).select(
1277 Self::infinity(),
1278 n.simd_eq(f32x4::ZERO).select(f32x4::ONE, f32x4::ZERO),
1279 ),
1280 z,
1281 );
1282
1283 let x_sign = self.is_sign_negative();
1284 let z = if x_sign.any() {
1285 let yi = n.simd_eq(n.round_ties_even());
1287 let y_odd = cast::<i32x4, f32x4>(n.round_int() << 31);
1289
1290 let z1 = yi
1291 .select(z | y_odd, self.simd_eq(Self::ZERO).select(z, Self::nan_pow()));
1292 x_sign.select(z1, z)
1293 } else {
1294 z
1295 };
1296
1297 let x_finite = self.is_finite();
1298 let y_finite = n.is_finite();
1299 let e_finite = ee.is_finite();
1300 if (x_finite & y_finite & (e_finite | x_zero)).all() {
1301 return z;
1302 }
1303
1304 (self.is_nan() | n.is_nan()).select(self + n, z)
1305 }
1306
1307 #[inline]
1308 pub fn sqrt(self) -> Self {
1309 pick! {
1310 if #[cfg(target_feature="sse")] {
1311 Self { sse: sqrt_m128(self.sse) }
1312 } else if #[cfg(target_feature="simd128")] {
1313 Self { simd: f32x4_sqrt(self.simd) }
1314 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1315 unsafe {Self { neon: vsqrtq_f32(self.neon) }}
1316 } else if #[cfg(feature="std")] {
1317 Self { arr: [
1318 self.arr[0].sqrt(),
1319 self.arr[1].sqrt(),
1320 self.arr[2].sqrt(),
1321 self.arr[3].sqrt(),
1322 ]}
1323 } else {
1324 Self { arr: [
1325 software_sqrt(self.arr[0] as f64) as f32,
1326 software_sqrt(self.arr[1] as f64) as f32,
1327 software_sqrt(self.arr[2] as f64) as f32,
1328 software_sqrt(self.arr[3] as f64) as f32,
1329 ]}
1330 }
1331 }
1332 }
1333
1334 #[inline]
1336 pub fn exp(self) -> Self {
1337 const_f32_as_f32x4!(P0, 1.0 / 2.0);
1338 const_f32_as_f32x4!(P1, 1.0 / 6.0);
1339 const_f32_as_f32x4!(P2, 1.0 / 24.0);
1340 const_f32_as_f32x4!(P3, 1.0 / 120.0);
1341 const_f32_as_f32x4!(P4, 1.0 / 720.0);
1342 const_f32_as_f32x4!(P5, 1.0 / 5040.0);
1343 const_f32_as_f32x4!(LN2D_HI, 0.693359375);
1350 const_f32_as_f32x4!(LN2D_LO, -2.12194440e-4);
1351 let max_x = f32x4::from(88.723);
1354 let min_x = f32x4::from(-103.63);
1355 let finite = self.is_finite();
1357 let neg_underflow = self.simd_lt(min_x) & finite;
1358 if neg_underflow.all() {
1359 return Self::ZERO;
1360 }
1361 let max_r = f32x4::from(127.0);
1362 let r = (self * Self::LOG2_E).round_ties_even();
1363 let big = r.simd_gt(max_r);
1364 let r_safe = big.select(max_r, r);
1365 let excess = r - max_r;
1366 let excess = big.select(excess, Self::ZERO);
1367 let scale = Self::vm_pow2n(excess);
1368 let x = r.mul_neg_add(LN2D_HI, self);
1369 let x = r.mul_neg_add(LN2D_LO, x);
1370 let z = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1371 let x2 = x * x;
1372 let z = z.mul_add(x2, x);
1373 let n2 = Self::vm_pow2n(r_safe);
1374 let z = (z + Self::ONE) * scale * n2;
1375 let nan_mask = self.is_nan();
1376 let mut result = nan_mask.select(Self::nan_pow(), z);
1377 let pos_overflow = self.simd_gt(max_x) & finite;
1378 result = pos_overflow.select(Self::infinity(), result);
1379 result = neg_underflow.select(Self::ZERO, result);
1380 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1381 result = pos_inf.select(Self::infinity(), result);
1382 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1383 result = neg_inf.select(Self::ZERO, result);
1384 result
1385 }
1386
1387 #[inline]
1388 pub fn exp2(self) -> Self {
1389 const_f32_as_f32x4!(P2, 1.0 / 2.0);
1390 const_f32_as_f32x4!(P3, 1.0 / 6.0);
1391 const_f32_as_f32x4!(P4, 1.0 / 24.0);
1392 const_f32_as_f32x4!(P5, 1.0 / 120.0);
1393 const_f32_as_f32x4!(P6, 1.0 / 720.0);
1394 const_f32_as_f32x4!(P7, 1.0 / 5040.0);
1395
1396 let max_x = f32x4::from(127.99999);
1399 let min_x = f32x4::from(-149.5);
1400 let finite = self.is_finite();
1401 let neg_underflow = self.simd_lt(min_x) & finite;
1402 if neg_underflow.all() {
1403 return Self::ZERO;
1404 }
1405
1406 let round = self.round_ties_even();
1407 let max_r = f32x4::from(127.0);
1408 let big = round.simd_gt(max_r);
1409 let r_safe = big.select(max_r, round);
1410 let excess = round - max_r;
1411 let excess = big.select(excess, Self::ZERO);
1412 let scale = Self::vm_pow2n(excess);
1413
1414 let fract = (self - round) * Self::LN_2;
1415 let fract_partial_exp2 = polynomial_5!(fract, P2, P3, P4, P5, P6, P7);
1416 let fract2 = fract * fract;
1417 let fract_exp2 = fract_partial_exp2.mul_add(fract2, fract) + Self::ONE;
1418
1419 let n2 = Self::vm_pow2n(r_safe);
1420 let result = fract_exp2 * scale * n2;
1421
1422 let nan_mask = self.is_nan();
1423 let mut result = nan_mask.select(Self::nan_pow(), result);
1424 let pos_overflow = self.simd_gt(max_x) & finite;
1425 result = pos_overflow.select(Self::infinity(), result);
1426 result = neg_underflow.select(Self::ZERO, result);
1427 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1428 result = pos_inf.select(Self::infinity(), result);
1429 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1430 result = neg_inf.select(Self::ZERO, result);
1431 result
1432 }
1433
1434 #[inline]
1435 pub fn ln(self) -> Self {
1436 const_f32_as_f32x4!(HALF, 0.5);
1437 const_f32_as_f32x4!(P0, 3.3333331174E-1);
1438 const_f32_as_f32x4!(P1, -2.4999993993E-1);
1439 const_f32_as_f32x4!(P2, 2.0000714765E-1);
1440 const_f32_as_f32x4!(P3, -1.6668057665E-1);
1441 const_f32_as_f32x4!(P4, 1.4249322787E-1);
1442 const_f32_as_f32x4!(P5, -1.2420140846E-1);
1443 const_f32_as_f32x4!(P6, 1.1676998740E-1);
1444 const_f32_as_f32x4!(P7, -1.1514610310E-1);
1445 const_f32_as_f32x4!(P8, 7.0376836292E-2);
1446 const_f32_as_f32x4!(LN2F_HI, 0.693359375);
1447 const_f32_as_f32x4!(LN2F_LO, -2.12194440e-4);
1448 const_f32_as_f32x4!(VM_SMALLEST_NORMAL, 1.17549435E-38);
1449
1450 let x1 = self;
1451 let x = Self::fraction_2(x1);
1452 let e = Self::exponent(x1);
1453 let mask = x.simd_gt(Self::SQRT_2 * HALF);
1454 let x = (!mask).select(x + x, x);
1455 let fe = mask.select(e + Self::ONE, e);
1456 let x = x - Self::ONE;
1457 let res = polynomial_8!(x, P0, P1, P2, P3, P4, P5, P6, P7, P8);
1458 let x2 = x * x;
1459 let res = x2 * x * res;
1460 let res = fe.mul_add(LN2F_LO, res);
1461 let res = res + x2.mul_neg_add(HALF, x);
1462 let res = fe.mul_add(LN2F_HI, res);
1463 let overflow = !self.is_finite();
1464 let underflow = x1.simd_lt(VM_SMALLEST_NORMAL);
1465 let mask = overflow | underflow;
1466 if !mask.any() {
1467 res
1468 } else {
1469 let is_zero = self.is_zero_or_subnormal();
1470 let res = underflow.select(Self::nan_log(), res);
1471 let res = is_zero.select(-Self::infinity(), res);
1476 let res = overflow.select(self, res);
1477 let res = (!self.is_finite() & self.is_sign_negative())
1479 .select(Self::nan_log(), res);
1480 res
1481 }
1482 }
1483
1484 #[inline]
1485 pub fn cbrt(self) -> Self {
1486 let a = self.abs();
1487 let zero = a.simd_eq(Self::ZERO);
1488 if zero.all() {
1489 return self; }
1491 let inf = a.is_inf();
1492 let nan = self.is_nan();
1493
1494 let tiny = a.simd_lt(Self::from(f32::MIN_POSITIVE));
1495 let a_work = tiny.select(a * Self::from(16777216.0), a);
1496
1497 let e = Self::exponent(a_work) + Self::ONE;
1498 let d = Self::fraction_2(a_work);
1499
1500 const_f32_as_f32x4!(C0, 2.2241257);
1507 const_f32_as_f32x4!(C1, -3.8095417);
1508 const_f32_as_f32x4!(C2, 5.8982625);
1509 const_f32_as_f32x4!(C3, -5.532182);
1510 const_f32_as_f32x4!(C4, 2.8208892);
1511 const_f32_as_f32x4!(C5, -0.60156447);
1512 let mut x = polynomial_5!(d, C0, C1, C2, C3, C4, C5);
1513
1514 let x2 = x * x;
1515 let x4 = x2 * x2;
1516 x = x - d.mul_add(x4, -x) * Self::from(1.0 / 3.0);
1517 let mut y = (d * x) * x;
1519 let yx = y * x;
1520 let t = Self::from(2.0 / 3.0);
1521 y = y - t * y * (yx - Self::ONE);
1522
1523 let three = Self::from(3.0);
1525 let two = Self::from(2.0);
1526 let neg = e.simd_lt(Self::ZERO);
1527 let e_adj = neg.select(e - two, e);
1528 let k = (e_adj / three).trunc();
1529 let r = e - three * k;
1530 const_f32_as_f32x4!(CBRT2, 1.259921);
1531 const_f32_as_f32x4!(CBRT4, 1.587401);
1532 y = r.simd_eq(Self::ONE).select(y * CBRT2, y);
1533 y = r.simd_eq(two).select(y * CBRT4, y);
1534 y *= Self::vm_pow2n(k);
1535 y = tiny.select(y / Self::from(256.0_f32), y);
1536
1537 let result = y.flip_signs(self);
1538 let result = nan.select(self, result);
1539 let result = zero.select(self, result);
1540 let result = inf.select(self, result);
1541 result
1542 }
1543
1544 #[inline]
1545 pub fn asin(self) -> Self {
1546 const_f32_as_f32x4!(P4asinf, 4.2163199048E-2);
1549 const_f32_as_f32x4!(P3asinf, 2.4181311049E-2);
1550 const_f32_as_f32x4!(P2asinf, 4.5470025998E-2);
1551 const_f32_as_f32x4!(P1asinf, 7.4953002686E-2);
1552 const_f32_as_f32x4!(P0asinf, 1.6666752422E-1);
1553
1554 let xa = self.abs();
1555 let big = xa.simd_ge(f32x4::splat(0.5));
1556
1557 let x1 = f32x4::splat(0.5) * (f32x4::ONE - xa);
1558 let x2 = xa * xa;
1559 let x3 = big.select(x1, x2);
1560
1561 let xb = x1.sqrt();
1562
1563 let x4 = big.select(xb, xa);
1564
1565 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1566 let z = z.mul_add(x3 * x4, x4);
1567
1568 let z1 = z + z;
1569
1570 let z3 = f32x4::FRAC_PI_2 - z1;
1572 let asin = big.select(z3, z);
1573 let asin = asin.flip_signs(self);
1574
1575 asin
1576 }
1577
1578 #[inline]
1579 pub fn acos(self) -> Self {
1580 const_f32_as_f32x4!(P4asinf, 4.2163199048E-2);
1583 const_f32_as_f32x4!(P3asinf, 2.4181311049E-2);
1584 const_f32_as_f32x4!(P2asinf, 4.5470025998E-2);
1585 const_f32_as_f32x4!(P1asinf, 7.4953002686E-2);
1586 const_f32_as_f32x4!(P0asinf, 1.6666752422E-1);
1587
1588 let xa = self.abs();
1589 let big = xa.simd_ge(f32x4::splat(0.5));
1590
1591 let x1 = f32x4::splat(0.5) * (f32x4::ONE - xa);
1592 let x2 = xa * xa;
1593 let x3 = big.select(x1, x2);
1594
1595 let xb = x1.sqrt();
1596
1597 let x4 = big.select(xb, xa);
1598
1599 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1600 let z = z.mul_add(x3 * x4, x4);
1601
1602 let z1 = z + z;
1603
1604 let z3 = self.simd_lt(f32x4::ZERO).select(f32x4::PI - z1, z1);
1606 let z4 = f32x4::FRAC_PI_2 - z.flip_signs(self);
1607 let acos = big.select(z3, z4);
1608
1609 acos
1610 }
1611
1612 #[inline]
1613 pub fn atan(self) -> Self {
1614 const_f32_as_f32x4!(P3atanf, 8.05374449538E-2);
1617 const_f32_as_f32x4!(P2atanf, -1.38776856032E-1);
1618 const_f32_as_f32x4!(P1atanf, 1.99777106478E-1);
1619 const_f32_as_f32x4!(P0atanf, -3.33329491539E-1);
1620
1621 let t = self.abs();
1622
1623 let notsmal = t.simd_ge(Self::SQRT_2 - Self::ONE);
1627 let notbig = t.simd_le(Self::SQRT_2 + Self::ONE);
1628
1629 let mut s = notbig.select(Self::FRAC_PI_4, Self::FRAC_PI_2);
1630 s = notsmal & s;
1631
1632 let mut a = notbig & t;
1633 a = notsmal.select(a - Self::ONE, a);
1634 let mut b = notbig & Self::ONE;
1635 b = notsmal.select(b + t, b);
1636 let z = a / b;
1637
1638 let zz = z * z;
1639
1640 let mut re = polynomial_3!(zz, P0atanf, P1atanf, P2atanf, P3atanf);
1642 re = re.mul_add(zz * z, z) + s;
1643
1644 re = (self.is_sign_negative()).select(-re, re);
1646
1647 re
1648 }
1649
1650 #[inline]
1651 pub fn atan2(self, x: Self) -> Self {
1652 const_f32_as_f32x4!(P3atanf, 8.05374449538E-2);
1655 const_f32_as_f32x4!(P2atanf, -1.38776856032E-1);
1656 const_f32_as_f32x4!(P1atanf, 1.99777106478E-1);
1657 const_f32_as_f32x4!(P0atanf, -3.33329491539E-1);
1658
1659 let y = self;
1660
1661 let x1 = x.abs();
1663 let y1 = y.abs();
1664 let swapxy = y1.simd_gt(x1);
1665 let mut x2 = swapxy.select(y1, x1);
1667 let mut y2 = swapxy.select(x1, y1);
1668
1669 let both_infinite = x.is_inf() & y.is_inf();
1671 if both_infinite.any() {
1672 let minus_one = -Self::ONE;
1673 x2 = both_infinite.select(x2 & minus_one, x2);
1674 y2 = both_infinite.select(y2 & minus_one, y2);
1675 }
1676
1677 let t = y2 / x2;
1679
1680 let notsmal = t.simd_ge(Self::SQRT_2 - Self::ONE);
1683
1684 let a = notsmal.select(t - Self::ONE, t);
1685 let b = notsmal.select(t + Self::ONE, Self::ONE);
1686 let s = notsmal & Self::FRAC_PI_4;
1687 let z = a / b;
1688
1689 let zz = z * z;
1690
1691 let mut re = polynomial_3!(zz, P0atanf, P1atanf, P2atanf, P3atanf);
1693 re = re.mul_add(zz * z, z) + s;
1694
1695 re = swapxy.select(Self::FRAC_PI_2 - re, re);
1697 re = ((x | y).simd_eq(Self::ZERO)).select(Self::ZERO, re);
1698 re = (x.is_sign_negative()).select(Self::PI - re, re);
1699
1700 re = (y.is_sign_negative()).select(-re, re);
1702
1703 re
1704 }
1705
1706 #[inline]
1707 pub fn sin_cos(self) -> (Self, Self) {
1708 const_f32_as_f32x4!(DP1F, 0.78515625_f32 * 2.0);
1712 const_f32_as_f32x4!(DP2F, 2.4187564849853515625E-4_f32 * 2.0);
1713 const_f32_as_f32x4!(DP3F, 3.77489497744594108E-8_f32 * 2.0);
1714
1715 const_f32_as_f32x4!(P0sinf, -1.6666654611E-1);
1716 const_f32_as_f32x4!(P1sinf, 8.3321608736E-3);
1717 const_f32_as_f32x4!(P2sinf, -1.9515295891E-4);
1718
1719 const_f32_as_f32x4!(P0cosf, 4.166664568298827E-2);
1720 const_f32_as_f32x4!(P1cosf, -1.388731625493765E-3);
1721 const_f32_as_f32x4!(P2cosf, 2.443315711809948E-5);
1722
1723 const_f32_as_f32x4!(TWO_OVER_PI, 2.0 / core::f32::consts::PI);
1724
1725 let xa = self.abs();
1726
1727 let y = (xa * TWO_OVER_PI).round_ties_even();
1729 let q: i32x4 = y.round_int();
1730
1731 let x = y.mul_neg_add(DP3F, y.mul_neg_add(DP2F, y.mul_neg_add(DP1F, xa)));
1732
1733 let x2 = x * x;
1734 let mut s = polynomial_2!(x2, P0sinf, P1sinf, P2sinf) * (x * x2) + x;
1735 let mut c = polynomial_2!(x2, P0cosf, P1cosf, P2cosf) * (x2 * x2)
1736 + f32x4::from(0.5).mul_neg_add(x2, f32x4::from(1.0));
1737
1738 let swap = !(q & i32x4::from(1)).simd_eq(i32x4::from(0));
1739
1740 let mut overflow: f32x4 = cast(q.simd_gt(i32x4::from(0x2000000)));
1741 overflow &= xa.is_finite();
1742 s = overflow.select(f32x4::from(0.0), s);
1743 c = overflow.select(f32x4::from(1.0), c);
1744
1745 let mut sin1 = cast::<_, f32x4>(swap).select(c, s);
1747 let sign_sin: i32x4 = (q << 30) ^ cast::<_, i32x4>(self);
1748 sin1 = sin1.flip_signs(cast(sign_sin));
1749
1750 let mut cos1 = cast::<_, f32x4>(swap).select(s, c);
1752 let sign_cos: i32x4 = ((q + i32x4::from(1)) & i32x4::from(2)) << 30;
1753 cos1 ^= cast::<_, f32x4>(sign_cos);
1754
1755 let finite = self.is_finite();
1757 let nan = Self::splat(f32::NAN);
1758 let sin_final = finite.select(sin1, nan);
1759 let cos_final = finite.select(cos1, nan);
1760
1761 (sin_final, cos_final)
1762 }
1763
1764 #[inline]
1765 pub fn asin_acos(self) -> (Self, Self) {
1766 const_f32_as_f32x4!(P4asinf, 4.2163199048E-2);
1769 const_f32_as_f32x4!(P3asinf, 2.4181311049E-2);
1770 const_f32_as_f32x4!(P2asinf, 4.5470025998E-2);
1771 const_f32_as_f32x4!(P1asinf, 7.4953002686E-2);
1772 const_f32_as_f32x4!(P0asinf, 1.6666752422E-1);
1773
1774 let xa = self.abs();
1775 let big = xa.simd_ge(f32x4::splat(0.5));
1776
1777 let x1 = f32x4::splat(0.5) * (f32x4::ONE - xa);
1778 let x2 = xa * xa;
1779 let x3 = big.select(x1, x2);
1780
1781 let xb = x1.sqrt();
1782
1783 let x4 = big.select(xb, xa);
1784
1785 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1786 let z = z.mul_add(x3 * x4, x4);
1787
1788 let z1 = z + z;
1789
1790 let z3 = self.simd_lt(f32x4::ZERO).select(f32x4::PI - z1, z1);
1792 let z4 = f32x4::FRAC_PI_2 - z.flip_signs(self);
1793 let acos = big.select(z3, z4);
1794
1795 let z3 = f32x4::FRAC_PI_2 - z1;
1797 let asin = big.select(z3, z);
1798 let asin = asin.flip_signs(self);
1799
1800 (asin, acos)
1801 }
1802
1803 #[inline]
1804 pub fn exp_m1(self) -> Self {
1805 if self.simd_lt(f32x4::from(-17.329)).all() {
1809 return f32x4::from(-1.0);
1810 }
1811 const_f32_as_f32x4!(P0, 1.0 / 2.0);
1812 const_f32_as_f32x4!(P1, 1.0 / 6.0);
1813 const_f32_as_f32x4!(P2, 1.0 / 24.0);
1814 const_f32_as_f32x4!(P3, 1.0 / 120.0);
1815 const_f32_as_f32x4!(P4, 1.0 / 720.0);
1816 const_f32_as_f32x4!(P5, 1.0 / 5040.0);
1817 const_f32_as_f32x4!(LN2D_HI, 0.693359375);
1824 const_f32_as_f32x4!(LN2D_LO, -2.12194440e-4);
1825 let max_x = f32x4::from(88.723);
1828 let min_x = f32x4::from(-103.63);
1829 let max_r = f32x4::from(127.0);
1830 let r = (self * Self::LOG2_E).round_ties_even();
1831 let big = r.simd_gt(max_r);
1832 let r_safe = big.select(max_r, r);
1833 let excess = r - max_r;
1834 let excess = big.select(excess, Self::ZERO);
1835 let scale = Self::vm_pow2n(excess);
1836 let x = r.mul_neg_add(LN2D_HI, self);
1837 let x = r.mul_neg_add(LN2D_LO, x);
1838 let z = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1839 let x2 = x * x;
1840 let z = z.mul_add(x2, x);
1841 let n2 = Self::vm_pow2n(r_safe);
1842 let exp_val = (z + Self::ONE) * scale * n2;
1843 let r_is_zero = r.simd_eq(Self::ZERO);
1844 let z = r_is_zero.select(z, exp_val - Self::ONE);
1845 let nan_mask = self.is_nan();
1846 let finite = self.is_finite();
1847 let mut result = nan_mask.select(Self::nan_pow(), z);
1848 let pos_overflow = self.simd_gt(max_x) & finite;
1849 result = pos_overflow.select(Self::infinity(), result);
1850 let neg_underflow = self.simd_lt(min_x) & finite;
1851 result = neg_underflow.select(-Self::ONE, result);
1852 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1853 result = pos_inf.select(Self::infinity(), result);
1854 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1855 result = neg_inf.select(-Self::ONE, result);
1856 let is_zero = self.simd_eq(Self::ZERO);
1857 result = is_zero.select(self, result);
1858 result
1859 }
1860
1861 #[inline]
1862 pub fn ln_1p(self) -> Self {
1863 let u = self + Self::ONE;
1871 let eq = u.simd_eq(Self::ONE);
1872 let ln_u = Self::ln(u);
1873 let correction = self * (ln_u / (u - Self::ONE));
1874 let result = eq.select(self, correction);
1875 let over = u.is_inf();
1876 over.select(ln_u, result)
1877 }
1878
1879 #[inline]
1880 pub fn sinh(self) -> Self {
1881 const_f32_as_f32x4!(P0, 1.0);
1882 const_f32_as_f32x4!(P1, 1.0 / 6.0);
1883 const_f32_as_f32x4!(P2, 1.0 / 120.0);
1884 const_f32_as_f32x4!(P3, 1.0 / 5040.0);
1885 let a = self.abs();
1886 let small = a.simd_lt(f32x4::from(0.5));
1888 let t = a * a;
1889 let poly = a * polynomial_3!(t, P0, P1, P2, P3);
1890 let exp_based = {
1891 let e = a.exp();
1892 (e - Self::ONE / e) * Self::HALF
1893 };
1894 let result = small.select(poly, exp_based);
1895 result.flip_signs(self)
1896 }
1897
1898 #[inline]
1899 pub fn cosh(self) -> Self {
1900 const_f32_as_f32x4!(P0, 1.0);
1901 const_f32_as_f32x4!(P1, 1.0 / 2.0);
1902 const_f32_as_f32x4!(P2, 1.0 / 24.0);
1903 const_f32_as_f32x4!(P3, 1.0 / 720.0);
1904 let a = self.abs();
1905 let small = a.simd_lt(f32x4::from(0.5));
1907 let t = a * a;
1908 let poly = polynomial_3!(t, P0, P1, P2, P3);
1909 let exp_based = {
1910 let e = a.exp();
1911 (e + Self::ONE / e) * Self::HALF
1912 };
1913 small.select(poly, exp_based)
1914 }
1915
1916 #[inline]
1917 pub fn tanh(self) -> Self {
1918 let a = self.abs();
1922 let large = a.simd_gt(f32x4::from(9.011));
1923 if large.all() {
1924 return Self::ONE.flip_signs(self);
1925 }
1926 let small = a.simd_lt(f32x4::from(2e-4));
1927 let exp_based = {
1928 let t = (Self::from(-2.0) * a).exp_m1();
1929 let pos = -t / (t + Self::from(2.0));
1930 pos.flip_signs(self)
1931 };
1932 let result = small.select(self, exp_based);
1933 large.select(Self::ONE.flip_signs(self), result)
1934 }
1935}
1936
1937impl f32x4 {
1940 #[inline]
1941 fn vm_pow2n(self) -> Self {
1942 const_f32_as_f32x4!(pow2_23, 8388608.0);
1943 const_f32_as_f32x4!(bias, 127.0);
1944 let a = self + (bias + pow2_23);
1945 let c = cast::<_, i32x4>(a) << 23;
1946 let std_result = cast::<_, f32x4>(c);
1947
1948 let min_exp = f32x4::from(-126.0);
1949 let is_sub = self.simd_lt(min_exp);
1950 if is_sub.any() {
1951 let valid = self.simd_ge(f32x4::from(-149.0));
1952 let shift_f = self + f32x4::from(149.0);
1953 let mut shift_i = shift_f.trunc_int();
1954 shift_i = cast::<_, i32x4>(valid).select(shift_i, i32x4::ZERO);
1955 let mantissa = i32x4::ONE << shift_i;
1956 let sub_result = cast::<_, f32x4>(mantissa);
1957 let sub_result = valid.select(sub_result, f32x4::ZERO);
1958 is_sub.select(sub_result, std_result)
1959 } else {
1960 std_result
1961 }
1962 }
1963
1964 #[inline]
1965 fn exponent(self) -> f32x4 {
1966 const_f32_as_f32x4!(pow2_23, 8388608.0);
1967 const_f32_as_f32x4!(bias, 127.0);
1968 let a = cast::<_, u32x4>(self);
1969 let b = a >> 23;
1970 let c = b | cast::<_, u32x4>(pow2_23);
1971 let d = cast::<_, f32x4>(c);
1972 let e = d - (pow2_23 + bias);
1973 e
1974 }
1975
1976 #[inline]
1977 fn fraction_2(self) -> Self {
1978 let t1 = cast::<_, u32x4>(self);
1979 let t2 = cast::<_, u32x4>(
1980 (t1 & u32x4::from(0x007FFFFF)) | u32x4::from(0x3F000000),
1981 );
1982 cast::<_, f32x4>(t2)
1983 }
1984 #[inline]
1985 fn is_zero_or_subnormal(self) -> Self {
1986 let t = cast::<_, i32x4>(self);
1987 let t = t & i32x4::splat(0x7F800000);
1988 let mask = t.simd_eq(i32x4::splat(0));
1989 cast::<_, f32x4>(mask)
1990 }
1991 #[inline]
1992 fn infinity() -> Self {
1993 cast::<_, f32x4>(i32x4::splat(0x7F800000))
1994 }
1995 #[inline]
1996 fn nan_log() -> Self {
1997 cast::<_, f32x4>(i32x4::splat(0x7FC00000 | 0x101 & 0x003FFFFF))
1998 }
1999 #[inline]
2000 fn nan_pow() -> Self {
2001 cast::<_, f32x4>(i32x4::splat(0x7FC00000 | 0x101 & 0x003FFFFF))
2002 }
2003
2004 #[must_use]
2006 #[inline]
2007 pub fn unpack_lo(self, b: Self) -> Self {
2008 pick! {
2009 if #[cfg(target_feature="sse")] {
2010 Self { sse: unpack_low_m128(self.sse, b.sse) }
2011 } else if #[cfg(target_feature="simd128")] {
2012 Self {
2013 simd: u32x4_shuffle::<0, 4, 1, 5>(self.simd, b.simd)
2014 }
2015 } else if #[cfg(all(target_feature="neon", target_arch="aarch64"))]{
2016 unsafe {Self { neon: vzip1q_f32(self.neon, b.neon) }}
2017 } else {
2018 Self { arr: [
2019 self.arr[0],
2020 b.arr[0],
2021 self.arr[1],
2022 b.arr[1],
2023 ]}
2024 }
2025 }
2026 }
2027
2028 #[must_use]
2030 #[inline]
2031 pub fn unpack_hi(self, b: Self) -> Self {
2032 pick! {
2033 if #[cfg(target_feature="sse")] {
2034 Self { sse: unpack_high_m128(self.sse, b.sse) }
2035 } else if #[cfg(target_feature="simd128")] {
2036 Self {
2037 simd: u32x4_shuffle::<2, 6, 3, 7>(self.simd, b.simd)
2038 }
2039 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
2040 unsafe {Self { neon: vzip2q_f32(self.neon, b.neon) }}
2041 } else {
2042 Self { arr: [
2043 self.arr[2],
2044 b.arr[2],
2045 self.arr[3],
2046 b.arr[3],
2047 ]}
2048 }
2049 }
2050 }
2051
2052 #[inline]
2054 pub fn from_i32x4(v: i32x4) -> Self {
2055 pick! {
2056 if #[cfg(target_feature="sse2")] {
2057 Self { sse: convert_to_m128_from_i32_m128i(v.sse) }
2058 } else if #[cfg(target_feature="simd128")] {
2059 Self { simd: f32x4_convert_i32x4(v.simd) }
2060 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
2061 Self { neon: unsafe { vcvtq_f32_s32(v.neon) }}
2062 } else {
2063 Self { arr: [
2064 v.as_array()[0] as f32,
2065 v.as_array()[1] as f32,
2066 v.as_array()[2] as f32,
2067 v.as_array()[3] as f32,
2068 ] }
2069 }
2070 }
2071 }
2072
2073 #[inline]
2083 #[must_use]
2084 #[deprecated(since = "1.4.0", note = "renamed to `is_sign_negative`")]
2085 pub fn sign_bit(self) -> Self {
2086 self.is_sign_negative()
2087 }
2088}