1 #![allow(missing_docs)]
2 #![allow(non_camel_case_types)] // For the simd type aliases.
3
4 //! SIMD values based on auto-vectorization.
5
6 use crate::scalar::{Field, SubsetOf, SupersetOf};
7 use crate::simd::{
8 PrimitiveSimdValue, SimdBool, SimdComplexField, SimdPartialOrd, SimdRealField, SimdSigned,
9 SimdValue,
10 };
11 use approx::AbsDiffEq;
12 #[cfg(feature = "decimal")]
13 use decimal::d128;
14 use num::{FromPrimitive, Num, One, Zero};
15 use std::{
16 fmt,
17 ops::{
18 Add, AddAssign, BitAnd, BitOr, BitXor, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem,
19 RemAssign, Sub, SubAssign,
20 },
21 };
22
23 // This is a hack to allow use to reuse `_0` as integers or as identifier,
24 // depending on whether or not `ident_to_value` has been called in scope.
25 // This helps writing macros that define both `::new` and `From([T; lanes()])`.
26 macro_rules! ident_to_value(
27 () => {
28 const _0: usize = 0; const _1: usize = 1; const _2: usize = 2; const _3: usize = 3; const _4: usize = 4; const _5: usize = 5; const _6: usize = 6; const _7: usize = 7;
29 const _8: usize = 8; const _9: usize = 9; const _10: usize = 10; const _11: usize = 11; const _12: usize = 12; const _13: usize = 13; const _14: usize = 14; const _15: usize = 15;
30 const _16: usize = 16; const _17: usize = 17; const _18: usize = 18; const _19: usize = 19; const _20: usize = 20; const _21: usize = 21; const _22: usize = 22; const _23: usize = 23;
31 const _24: usize = 24; const _25: usize = 25; const _26: usize = 26; const _27: usize = 27; const _28: usize = 28; const _29: usize = 29; const _30: usize = 30; const _31: usize = 31;
32 const _32: usize = 32; const _33: usize = 33; const _34: usize = 34; const _35: usize = 35; const _36: usize = 36; const _37: usize = 37; const _38: usize = 38; const _39: usize = 39;
33 const _40: usize = 40; const _41: usize = 41; const _42: usize = 42; const _43: usize = 43; const _44: usize = 44; const _45: usize = 45; const _46: usize = 46; const _47: usize = 47;
34 const _48: usize = 48; const _49: usize = 49; const _50: usize = 50; const _51: usize = 51; const _52: usize = 52; const _53: usize = 53; const _54: usize = 54; const _55: usize = 55;
35 const _56: usize = 56; const _57: usize = 57; const _58: usize = 58; const _59: usize = 59; const _60: usize = 60; const _61: usize = 61; const _62: usize = 62; const _63: usize = 63;
36 }
37 );
38
39 /// An Simd structure that implements all the relevant traits from `num` an `simba`.
40 ///
41 /// This is needed to overcome the orphan rules.
42 #[repr(align(16))]
43 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
44 pub struct AutoSimd<N>(pub N);
45 /// An Simd boolean structure that implements all the relevant traits from `num` an `simba`.
46 ///
47 /// This is needed to overcome the orphan rules.
48 #[repr(align(16))]
49 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
50 pub struct AutoBoolSimd<N>(pub N);
51
52 macro_rules! impl_bool_simd(
53 ($($t: ty, $lanes: expr, $($i: ident),*;)*) => {$(
54 impl_simd_value!($t, bool, $lanes, AutoSimd<$t> $(, $i)*;);
55
56 impl From<[bool; $lanes]> for AutoSimd<$t> {
57 #[inline(always)]
58 fn from(vals: [bool; $lanes]) -> Self {
59 Self(vals)
60 }
61 }
62
63 impl Not for AutoSimd<$t> {
64 type Output = Self;
65
66 #[inline]
67 fn not(self) -> Self {
68 self.map(|x| !x)
69 }
70 }
71
72 impl BitAnd<AutoSimd<$t>> for AutoSimd<$t> {
73 type Output = Self;
74 fn bitand(self, rhs: Self) -> Self {
75 self.zip_map(rhs, |x, y| x & y)
76 }
77 }
78
79 impl BitOr<AutoSimd<$t>> for AutoSimd<$t> {
80 type Output = Self;
81 fn bitor(self, rhs: Self) -> Self {
82 self.zip_map(rhs, |x, y| x | y)
83 }
84 }
85
86 impl BitXor<AutoSimd<$t>> for AutoSimd<$t> {
87 type Output = Self;
88 fn bitxor(self, rhs: Self) -> Self {
89 self.zip_map(rhs, |x, y| x ^ y)
90 }
91 }
92
93 impl SimdBool for AutoSimd<$t> {
94 #[inline(always)]
95 fn bitmask(self) -> u64 {
96 ident_to_value!();
97 0u64 $(
98 | ((self.0[$i] as u64) << $i)
99 )*
100 }
101
102 #[inline(always)]
103 fn and(self) -> bool {
104 ident_to_value!();
105 true $(
106 && self.0[$i]
107 )*
108 }
109
110 #[inline(always)]
111 fn or(self) -> bool {
112 ident_to_value!();
113 false $(
114 || self.0[$i]
115 )*
116 }
117
118 #[inline(always)]
119 fn xor(self) -> bool {
120 ident_to_value!();
121 false $(
122 ^ self.0[$i]
123 )*
124 }
125
126 #[inline(always)]
127 fn all(self) -> bool {
128 self.and()
129 }
130
131 #[inline(always)]
132 fn any(self) -> bool {
133 self.or()
134 }
135
136 #[inline(always)]
137 fn none(self) -> bool {
138 !self.any()
139 }
140
141 #[inline(always)]
142 fn if_else<Res: SimdValue<SimdBool = Self>>(
143 self,
144 if_value: impl FnOnce() -> Res,
145 else_value: impl FnOnce() -> Res,
146 ) -> Res {
147 let a = if_value();
148 let b = else_value();
149 a.select(self, b)
150 }
151
152 #[inline(always)]
153 fn if_else2<Res: SimdValue<SimdBool = Self>>(
154 self,
155 if_value: impl FnOnce() -> Res,
156 else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
157 else_value: impl FnOnce() -> Res,
158 ) -> Res {
159 let a = if_value();
160 let b = else_if.1();
161 let c = else_value();
162
163 let cond_a = self;
164 let cond_b = else_if.0();
165
166 a.select(cond_a, b.select(cond_b, c))
167 }
168
169 #[inline(always)]
170 fn if_else3<Res: SimdValue<SimdBool = Self>>(
171 self,
172 if_value: impl FnOnce() -> Res,
173 else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
174 else_else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
175 else_value: impl FnOnce() -> Res,
176 ) -> Res {
177 let a = if_value();
178 let b = else_if.1();
179 let c = else_else_if.1();
180 let d = else_value();
181
182 let cond_a = self;
183 let cond_b = else_if.0();
184 let cond_c = else_else_if.0();
185
186 a.select(cond_a, b.select(cond_b, c.select(cond_c, d)))
187 }
188 }
189 )*}
190 );
191
192 macro_rules! impl_scalar_subset_of_simd(
193 ($($t: ty),*) => {$(
194 impl<N2> SubsetOf<AutoSimd<N2>> for $t
195 where AutoSimd<N2>: SimdValue + Copy,
196 <AutoSimd<N2> as SimdValue>::Element: SupersetOf<$t> + PartialEq, {
197 #[inline(always)]
198 fn to_superset(&self) -> AutoSimd<N2> {
199 AutoSimd::<N2>::splat(<AutoSimd<N2> as SimdValue>::Element::from_subset(self))
200 }
201
202 #[inline(always)]
203 fn from_superset_unchecked(element: &AutoSimd<N2>) -> $t {
204 element.extract(0).to_subset_unchecked()
205 }
206
207 #[inline(always)]
208 fn is_in_subset(c: &AutoSimd<N2>) -> bool {
209 let elt0 = c.extract(0);
210 elt0.is_in_subset() &&
211 (1..AutoSimd::<N2>::lanes()).all(|i| c.extract(i) == elt0)
212 }
213 }
214 )*}
215 );
216
217 impl_scalar_subset_of_simd!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64);
218 #[cfg(feature = "decimal")]
219 impl_scalar_subset_of_simd!(d128);
220
221 macro_rules! impl_simd_value(
222 ($($t: ty, $elt: ty, $lanes: expr, $bool: ty, $($i: ident),*;)*) => ($(
223 impl ArrTransform for AutoSimd<$t> {
224 #[inline(always)]
225 fn map(self, f: impl Fn(Self::Element) -> Self::Element) -> Self {
226 ident_to_value!();
227 Self([$(f(self.0[$i])),*])
228 }
229
230 #[inline(always)]
231 fn zip_map(self, other: Self, f: impl Fn(Self::Element, Self::Element) -> Self::Element) -> Self {
232 ident_to_value!();
233 Self([$(f(self.0[$i], other.0[$i])),*])
234 }
235
236 #[inline(always)]
237 fn zip_zip_map(self, b: Self, c: Self, f: impl Fn(Self::Element, Self::Element, Self::Element) -> Self::Element) -> Self {
238 ident_to_value!();
239 Self([$(f(self.0[$i], b.0[$i], c.0[$i])),*])
240 }
241
242 #[inline(always)]
243 fn map_bool(self, f: impl Fn(Self::Element) -> bool) -> Self::SimdBool {
244 ident_to_value!();
245 AutoSimd([$(f(self.0[$i])),*])
246 }
247
248 #[inline(always)]
249 fn zip_map_bool(self, other: Self, f: impl Fn(Self::Element, Self::Element) -> bool) -> Self::SimdBool {
250 ident_to_value!();
251 AutoSimd([$(f(self.0[$i], other.0[$i])),*])
252 }
253 }
254
255 impl fmt::Display for AutoSimd<$t> {
256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257 if Self::lanes() == 1 {
258 return self.extract(0).fmt(f);
259 }
260
261 write!(f, "({}", self.extract(0))?;
262
263 for i in 1..Self::lanes() {
264 write!(f, ", {}", self.extract(i))?;
265 }
266
267 write!(f, ")")
268 }
269 }
270
271 impl AutoSimd<$t> {
272 pub fn new($($i: $elt),*) -> Self {
273 AutoSimd([$($i),*])
274 }
275 }
276
277 impl PrimitiveSimdValue for AutoSimd<$t> {}
278
279 impl SimdValue for AutoSimd<$t> {
280 type Element = $elt;
281 type SimdBool = $bool;
282
283 #[inline(always)]
284 fn lanes() -> usize {
285 $lanes
286 }
287
288 #[inline(always)]
289 fn splat(val: Self::Element) -> Self {
290 AutoSimd([val; $lanes])
291 }
292
293 #[inline(always)]
294 fn extract(&self, i: usize) -> Self::Element {
295 self.0[i]
296 }
297
298 #[inline(always)]
299 unsafe fn extract_unchecked(&self, i: usize) -> Self::Element {
300 *self.0.get_unchecked(i)
301 }
302
303 #[inline(always)]
304 fn replace(&mut self, i: usize, val: Self::Element) {
305 self.0[i] = val
306 }
307
308 #[inline(always)]
309 unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
310 *self.0.get_unchecked_mut(i) = val
311 }
312
313 #[inline(always)]
314 fn select(self, cond: Self::SimdBool, other: Self) -> Self {
315 ident_to_value!();
316 Self([
317 $(if cond.0[$i] { self.0[$i] } else { other.0[$i] }),*
318 ])
319 }
320 }
321 )*)
322 );
323
324 macro_rules! impl_uint_simd(
325 ($($t: ty, $elt: ty, $lanes: expr, $bool: ty, $($i: ident),*;)*) => ($(
326 impl_simd_value!($t, $elt, $lanes, $bool $(, $i)*;);
327
328 impl From<[$elt; $lanes]> for AutoSimd<$t> {
329 #[inline(always)]
330 fn from(vals: [$elt; $lanes]) -> Self {
331 AutoSimd(vals)
332 }
333 }
334
335 impl From<AutoSimd<$t>> for [$elt; $lanes] {
336 #[inline(always)]
337 fn from(val: AutoSimd<$t>) -> [$elt; $lanes] {
338 val.0
339 }
340 }
341
342 impl SubsetOf<AutoSimd<$t>> for AutoSimd<$t> {
343 #[inline(always)]
344 fn to_superset(&self) -> Self {
345 *self
346 }
347
348 #[inline(always)]
349 fn from_superset(element: &Self) -> Option<Self> {
350 Some(*element)
351 }
352
353 #[inline(always)]
354 fn from_superset_unchecked(element: &Self) -> Self {
355 *element
356 }
357
358 #[inline(always)]
359 fn is_in_subset(_: &Self) -> bool {
360 true
361 }
362 }
363
364 impl Num for AutoSimd<$t> {
365 type FromStrRadixErr = <$elt as Num>::FromStrRadixErr;
366
367 #[inline(always)]
368 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
369 <$elt>::from_str_radix(str, radix).map(Self::splat)
370 }
371 }
372
373 impl FromPrimitive for AutoSimd<$t> {
374 #[inline(always)]
375 fn from_i64(n: i64) -> Option<Self> {
376 <$elt>::from_i64(n).map(Self::splat)
377 }
378
379 #[inline(always)]
380 fn from_u64(n: u64) -> Option<Self> {
381 <$elt>::from_u64(n).map(Self::splat)
382 }
383
384 #[inline(always)]
385 fn from_isize(n: isize) -> Option<Self> {
386 <$elt>::from_isize(n).map(Self::splat)
387 }
388
389 #[inline(always)]
390 fn from_i8(n: i8) -> Option<Self> {
391 <$elt>::from_i8(n).map(Self::splat)
392 }
393
394 #[inline(always)]
395 fn from_i16(n: i16) -> Option<Self> {
396 <$elt>::from_i16(n).map(Self::splat)
397 }
398
399 #[inline(always)]
400 fn from_i32(n: i32) -> Option<Self> {
401 <$elt>::from_i32(n).map(Self::splat)
402 }
403
404 #[inline(always)]
405 fn from_usize(n: usize) -> Option<Self> {
406 <$elt>::from_usize(n).map(Self::splat)
407 }
408
409 #[inline(always)]
410 fn from_u8(n: u8) -> Option<Self> {
411 <$elt>::from_u8(n).map(Self::splat)
412 }
413
414 #[inline(always)]
415 fn from_u16(n: u16) -> Option<Self> {
416 <$elt>::from_u16(n).map(Self::splat)
417 }
418
419 #[inline(always)]
420 fn from_u32(n: u32) -> Option<Self> {
421 <$elt>::from_u32(n).map(Self::splat)
422 }
423
424 #[inline(always)]
425 fn from_f32(n: f32) -> Option<Self> {
426 <$elt>::from_f32(n).map(Self::splat)
427 }
428
429 #[inline(always)]
430 fn from_f64(n: f64) -> Option<Self> {
431 <$elt>::from_f64(n).map(Self::splat)
432 }
433 }
434
435
436 impl Zero for AutoSimd<$t> {
437 #[inline(always)]
438 fn zero() -> Self {
439 AutoSimd([<$elt>::zero(); $lanes])
440 }
441
442 #[inline(always)]
443 fn is_zero(&self) -> bool {
444 *self == Self::zero()
445 }
446 }
447
448 impl One for AutoSimd<$t> {
449 #[inline(always)]
450 fn one() -> Self {
451 AutoSimd([<$elt>::one(); $lanes])
452 }
453 }
454
455 impl Add<AutoSimd<$t>> for AutoSimd<$t> {
456 type Output = Self;
457
458 #[inline(always)]
459 fn add(self, rhs: Self) -> Self {
460 self.zip_map(rhs, |x, y| x + y)
461 }
462 }
463
464 impl Sub<AutoSimd<$t>> for AutoSimd<$t> {
465 type Output = Self;
466
467 #[inline(always)]
468 fn sub(self, rhs: Self) -> Self {
469 self.zip_map(rhs, |x, y| x - y)
470 }
471 }
472
473 impl Mul<AutoSimd<$t>> for AutoSimd<$t> {
474 type Output = Self;
475
476 #[inline(always)]
477 fn mul(self, rhs: Self) -> Self {
478 self.zip_map(rhs, |x, y| x * y)
479 }
480 }
481
482 impl Div<AutoSimd<$t>> for AutoSimd<$t> {
483 type Output = Self;
484
485 #[inline(always)]
486 fn div(self, rhs: Self) -> Self {
487 self.zip_map(rhs, |x, y| x / y)
488 }
489 }
490
491 impl Rem<AutoSimd<$t>> for AutoSimd<$t> {
492 type Output = Self;
493
494 #[inline(always)]
495 fn rem(self, rhs: Self) -> Self {
496 self.zip_map(rhs, |x, y| x % y)
497 }
498 }
499
500 impl AddAssign<AutoSimd<$t>> for AutoSimd<$t> {
501 #[inline(always)]
502 fn add_assign(&mut self, rhs: Self) {
503 *self = *self + rhs;
504 }
505 }
506
507 impl SubAssign<AutoSimd<$t>> for AutoSimd<$t> {
508 #[inline(always)]
509 fn sub_assign(&mut self, rhs: Self) {
510 *self = *self - rhs;
511 }
512 }
513
514 impl DivAssign<AutoSimd<$t>> for AutoSimd<$t> {
515 #[inline(always)]
516 fn div_assign(&mut self, rhs: Self) {
517 *self = *self / rhs;
518 }
519 }
520
521 impl MulAssign<AutoSimd<$t>> for AutoSimd<$t> {
522 #[inline(always)]
523 fn mul_assign(&mut self, rhs: Self) {
524 *self = *self * rhs;
525 }
526 }
527
528 impl RemAssign<AutoSimd<$t>> for AutoSimd<$t> {
529 #[inline(always)]
530 fn rem_assign(&mut self, rhs: Self) {
531 *self = *self % rhs;
532 }
533 }
534
535 impl SimdPartialOrd for AutoSimd<$t> {
536 #[inline(always)]
537 fn simd_gt(self, other: Self) -> Self::SimdBool {
538 self.zip_map_bool(other, |x, y| x.simd_gt(y))
539 }
540
541 #[inline(always)]
542 fn simd_lt(self, other: Self) -> Self::SimdBool {
543 self.zip_map_bool(other, |x, y| x.simd_lt(y))
544 }
545
546 #[inline(always)]
547 fn simd_ge(self, other: Self) -> Self::SimdBool {
548 self.zip_map_bool(other, |x, y| x.simd_ge(y))
549 }
550
551 #[inline(always)]
552 fn simd_le(self, other: Self) -> Self::SimdBool {
553 self.zip_map_bool(other, |x, y| x.simd_le(y))
554 }
555
556 #[inline(always)]
557 fn simd_eq(self, other: Self) -> Self::SimdBool {
558 self.zip_map_bool(other, |x, y| x.simd_eq(y))
559 }
560
561 #[inline(always)]
562 fn simd_ne(self, other: Self) -> Self::SimdBool {
563 self.zip_map_bool(other, |x, y| x.simd_ne(y))
564 }
565
566 #[inline(always)]
567 fn simd_max(self, other: Self) -> Self {
568 self.zip_map(other, |x, y| x.simd_max(y))
569 }
570 #[inline(always)]
571 fn simd_min(self, other: Self) -> Self {
572 self.zip_map(other, |x, y| x.simd_min(y))
573 }
574
575 #[inline(always)]
576 fn simd_clamp(self, min: Self, max: Self) -> Self {
577 self.simd_max(min).simd_min(max)
578 }
579
580 #[inline(always)]
581 fn simd_horizontal_min(self) -> Self::Element {
582 ident_to_value!();
583 self.0[0] $(.simd_min(self.0[$i]))*
584 }
585
586 #[inline(always)]
587 fn simd_horizontal_max(self) -> Self::Element {
588 ident_to_value!();
589 self.0[0] $(.simd_max(self.0[$i]))*
590 }
591 }
592
593 // impl MeetSemilattice for AutoSimd<$t> {
594 // #[inline(always)]
595 // fn meet(&self, other: &Self) -> Self {
596 // AutoSimd(self.0.min(other.0))
597 // }
598 // }
599 //
600 // impl JoinSemilattice for AutoSimd<$t> {
601 // #[inline(always)]
602 // fn join(&self, other: &Self) -> Self {
603 // AutoSimd(self.0.max(other.0))
604 // }
605 // }
606 )*)
607 );
608
609 macro_rules! impl_int_simd(
610 ($($t: ty, $elt: ty, $lanes: expr, $bool: ty, $($i: ident),*;)*) => ($(
611 impl_uint_simd!($t, $elt, $lanes, $bool $(, $i)*;);
612
613 impl Neg for AutoSimd<$t> {
614 type Output = Self;
615
616 #[inline(always)]
617 fn neg(self) -> Self {
618 self.map(|x| -x)
619 }
620 }
621 )*)
622 );
623
624 macro_rules! impl_float_simd(
625 ($($t: ty, $elt: ty, $lanes: expr, $int: ty, $bool: ty, $($i: ident),*;)*) => ($(
626 impl_int_simd!($t, $elt, $lanes, $bool $(, $i)*;);
627
628 // FIXME: this should be part of impl_int_simd
629 // but those methods do not seem to be implemented
630 // by packed_simd for integers.
631 impl SimdSigned for AutoSimd<$t> {
632 #[inline(always)]
633 fn simd_abs(&self) -> Self {
634 self.map(|x| x.simd_abs())
635 }
636
637 #[inline(always)]
638 fn simd_abs_sub(&self, other: &Self) -> Self {
639 self.zip_map(*other, |x, y| x.simd_abs_sub(&y))
640 }
641
642 #[inline(always)]
643 fn simd_signum(&self) -> Self {
644 self.map(|x| x.simd_signum())
645 }
646
647 #[inline(always)]
648 fn is_simd_positive(&self) -> Self::SimdBool {
649 self.map_bool(|x| x.is_simd_positive())
650 }
651
652 #[inline(always)]
653 fn is_simd_negative(&self) -> Self::SimdBool {
654 self.map_bool(|x| x.is_simd_negative())
655 }
656 }
657
658 impl Field for AutoSimd<$t> {}
659
660 #[cfg(any(feature = "std", feature = "libm", feature = "libm_force"))]
661 impl SimdRealField for AutoSimd<$t> {
662 #[inline(always)]
663 fn simd_atan2(self, other: Self) -> Self {
664 self.zip_map(other, |x, y| x.simd_atan2(y))
665 }
666
667 #[inline(always)]
668 fn simd_copysign(self, sign: Self) -> Self {
669 self.zip_map(sign, |me, sgn| me.simd_copysign(sgn))
670 }
671
672 #[inline(always)]
673 fn simd_default_epsilon() -> Self {
674 Self::splat(<$elt>::default_epsilon())
675 }
676
677 #[inline(always)]
678 fn simd_pi() -> Self {
679 Self::splat(<$elt>::simd_pi())
680 }
681
682 #[inline(always)]
683 fn simd_two_pi() -> Self {
684 Self::splat(<$elt>::simd_two_pi())
685 }
686
687 #[inline(always)]
688 fn simd_frac_pi_2() -> Self {
689 Self::splat(<$elt>::simd_frac_pi_2())
690 }
691
692 #[inline(always)]
693 fn simd_frac_pi_3() -> Self {
694 Self::splat(<$elt>::simd_frac_pi_3())
695 }
696
697 #[inline(always)]
698 fn simd_frac_pi_4() -> Self {
699 Self::splat(<$elt>::simd_frac_pi_4())
700 }
701
702 #[inline(always)]
703 fn simd_frac_pi_6() -> Self {
704 Self::splat(<$elt>::simd_frac_pi_6())
705 }
706
707 #[inline(always)]
708 fn simd_frac_pi_8() -> Self {
709 Self::splat(<$elt>::simd_frac_pi_8())
710 }
711
712 #[inline(always)]
713 fn simd_frac_1_pi() -> Self {
714 Self::splat(<$elt>::simd_frac_1_pi())
715 }
716
717 #[inline(always)]
718 fn simd_frac_2_pi() -> Self {
719 Self::splat(<$elt>::simd_frac_2_pi())
720 }
721
722 #[inline(always)]
723 fn simd_frac_2_sqrt_pi() -> Self {
724 Self::splat(<$elt>::simd_frac_2_sqrt_pi())
725 }
726
727
728 #[inline(always)]
729 fn simd_e() -> Self {
730 Self::splat(<$elt>::simd_e())
731 }
732
733 #[inline(always)]
734 fn simd_log2_e() -> Self {
735 Self::splat(<$elt>::simd_log2_e())
736 }
737
738 #[inline(always)]
739 fn simd_log10_e() -> Self {
740 Self::splat(<$elt>::simd_log10_e() )
741 }
742
743 #[inline(always)]
744 fn simd_ln_2() -> Self {
745 Self::splat(<$elt>::simd_ln_2())
746 }
747
748 #[inline(always)]
749 fn simd_ln_10() -> Self {
750 Self::splat(<$elt>::simd_ln_10())
751 }
752 }
753
754 #[cfg(any(feature = "std", feature = "libm", feature = "libm_force"))]
755 impl SimdComplexField for AutoSimd<$t> {
756 type SimdRealField = Self;
757
758 #[inline(always)]
759 fn simd_horizontal_sum(self) -> Self::Element {
760 self.0.iter().sum()
761 }
762
763 #[inline(always)]
764 fn simd_horizontal_product(self) -> Self::Element {
765 self.0.iter().product()
766 }
767
768 #[inline(always)]
769 fn from_simd_real(re: Self::SimdRealField) -> Self {
770 re
771 }
772
773 #[inline(always)]
774 fn simd_real(self) -> Self::SimdRealField {
775 self
776 }
777
778 #[inline(always)]
779 fn simd_imaginary(self) -> Self::SimdRealField {
780 Self::zero()
781 }
782
783 #[inline(always)]
784 fn simd_norm1(self) -> Self::SimdRealField {
785 self.map(|x| x.simd_norm1())
786 }
787
788 #[inline(always)]
789 fn simd_modulus(self) -> Self::SimdRealField {
790 self.map(|x| x.simd_modulus())
791 }
792
793 #[inline(always)]
794 fn simd_modulus_squared(self) -> Self::SimdRealField {
795 self.map(|x| x.simd_modulus_squared())
796 }
797
798 #[inline(always)]
799 fn simd_argument(self) -> Self::SimdRealField {
800 self.map(|x| x.simd_argument())
801 }
802
803 #[inline(always)]
804 fn simd_to_exp(self) -> (Self::SimdRealField, Self) {
805 let ge = self.simd_ge(Self::one());
806 let exp = Self::one().select(ge, -Self::one());
807 (self * exp, exp)
808 }
809
810 #[inline(always)]
811 fn simd_recip(self) -> Self {
812 self.map(|x| x.simd_recip())
813 }
814
815 #[inline(always)]
816 fn simd_conjugate(self) -> Self {
817 self.map(|x| x.simd_conjugate())
818 }
819
820 #[inline(always)]
821 fn simd_scale(self, factor: Self::SimdRealField) -> Self {
822 self.zip_map(factor, |x, y| x.simd_scale(y))
823 }
824
825 #[inline(always)]
826 fn simd_unscale(self, factor: Self::SimdRealField) -> Self {
827 self.zip_map(factor, |x, y| x.simd_unscale(y))
828 }
829
830 #[inline(always)]
831 fn simd_floor(self) -> Self {
832 self.map(|e| e.simd_floor())
833 }
834
835 #[inline(always)]
836 fn simd_ceil(self) -> Self {
837 self.map(|e| e.simd_ceil())
838 }
839
840 #[inline(always)]
841 fn simd_round(self) -> Self {
842 self.map(|e| e.simd_round())
843 }
844
845 #[inline(always)]
846 fn simd_trunc(self) -> Self {
847 self.map(|e| e.simd_trunc())
848 }
849
850 #[inline(always)]
851 fn simd_fract(self) -> Self {
852 self.map(|e| e.simd_fract())
853 }
854
855 #[inline(always)]
856 fn simd_abs(self) -> Self {
857 self.map(|e| e.simd_abs())
858 }
859
860 #[inline(always)]
861 fn simd_signum(self) -> Self {
862 self.map(|e| e.simd_signum())
863 }
864
865 #[inline(always)]
866 fn simd_mul_add(self, a: Self, b: Self) -> Self {
867 self.zip_zip_map(a, b, |x, y, z| x.simd_mul_add(y, z))
868 }
869
870 #[inline(always)]
871 fn simd_powi(self, n: i32) -> Self {
872 self.map(|e| e.simd_powi(n))
873 }
874
875 #[inline(always)]
876 fn simd_powf(self, n: Self) -> Self {
877 self.zip_map(n, |x, y| x.simd_powf(y))
878 }
879
880 #[inline(always)]
881 fn simd_powc(self, n: Self) -> Self {
882 self.zip_map(n, |x, y| x.simd_powc(y))
883 }
884
885 #[inline(always)]
886 fn simd_sqrt(self) -> Self {
887 self.map(|x| x.simd_sqrt())
888 }
889
890 #[inline(always)]
891 fn simd_exp(self) -> Self {
892 self.map(|x| x.simd_exp())
893 }
894
895 #[inline(always)]
896 fn simd_exp2(self) -> Self {
897 self.map(|x| x.simd_exp2())
898 }
899
900
901 #[inline(always)]
902 fn simd_exp_m1(self) -> Self {
903 self.map(|x| x.simd_exp_m1())
904 }
905
906 #[inline(always)]
907 fn simd_ln_1p(self) -> Self {
908 self.map(|x| x.simd_ln_1p())
909 }
910
911 #[inline(always)]
912 fn simd_ln(self) -> Self {
913 self.map(|x| x.simd_ln())
914 }
915
916 #[inline(always)]
917 fn simd_log(self, base: Self) -> Self {
918 self.zip_map(base, |x, y| x.simd_log(y))
919 }
920
921 #[inline(always)]
922 fn simd_log2(self) -> Self {
923 self.map(|x| x.simd_log2())
924 }
925
926 #[inline(always)]
927 fn simd_log10(self) -> Self {
928 self.map(|x| x.simd_log10())
929 }
930
931 #[inline(always)]
932 fn simd_cbrt(self) -> Self {
933 self.map(|x| x.simd_cbrt())
934 }
935
936 #[inline(always)]
937 fn simd_hypot(self, other: Self) -> Self::SimdRealField {
938 self.zip_map(other, |x, y| x.simd_hypot(y))
939 }
940
941 #[inline(always)]
942 fn simd_sin(self) -> Self {
943 self.map(|x| x.simd_sin())
944 }
945
946 #[inline(always)]
947 fn simd_cos(self) -> Self {
948 self.map(|x| x.simd_cos())
949 }
950
951 #[inline(always)]
952 fn simd_tan(self) -> Self {
953 self.map(|x| x.simd_tan())
954 }
955
956 #[inline(always)]
957 fn simd_asin(self) -> Self {
958 self.map(|x| x.simd_asin())
959 }
960
961 #[inline(always)]
962 fn simd_acos(self) -> Self {
963 self.map(|x| x.simd_acos())
964 }
965
966 #[inline(always)]
967 fn simd_atan(self) -> Self {
968 self.map(|x| x.simd_atan())
969 }
970
971 #[inline(always)]
972 fn simd_sin_cos(self) -> (Self, Self) {
973 (self.simd_sin(), self.simd_cos())
974 }
975
976 // #[inline(always]
977 // fn simd_exp_m1(self) -> Self {
978 // $libm::exp_m1(self)
979 // }
980 //
981 // #[inline(always]
982 // fn simd_ln_1p(self) -> Self {
983 // $libm::ln_1p(self)
984 // }
985 //
986 #[inline(always)]
987 fn simd_sinh(self) -> Self {
988 self.map(|x| x.simd_sinh())
989 }
990
991 #[inline(always)]
992 fn simd_cosh(self) -> Self {
993 self.map(|x| x.simd_cosh())
994 }
995
996 #[inline(always)]
997 fn simd_tanh(self) -> Self {
998 self.map(|x| x.simd_tanh())
999 }
1000
1001 #[inline(always)]
1002 fn simd_asinh(self) -> Self {
1003 self.map(|x| x.simd_asinh())
1004 }
1005
1006 #[inline(always)]
1007 fn simd_acosh(self) -> Self {
1008 self.map(|x| x.simd_acosh())
1009 }
1010
1011 #[inline(always)]
1012 fn simd_atanh(self) -> Self {
1013 self.map(|x| x.simd_atanh())
1014 }
1015 }
1016
1017 // NOTE: most of the impls in there are copy-paste from the implementation of
1018 // ComplexField for num_complex::Complex. Unfortunately, we can't reuse the implementations
1019 // so easily.
1020 #[cfg(any(feature = "std", feature = "libm", feature = "libm_force"))]
1021 impl SimdComplexField for num_complex::Complex<AutoSimd<$t>> {
1022 type SimdRealField = AutoSimd<$t>;
1023
1024 #[inline(always)]
1025 fn simd_horizontal_sum(self) -> Self::Element {
1026 num_complex::Complex::new(self.re.simd_horizontal_sum(), self.im.simd_horizontal_sum())
1027 }
1028
1029 #[inline(always)]
1030 fn simd_horizontal_product(self) -> Self::Element {
1031 let mut prod = self.extract(0);
1032 for ii in 1..$lanes {
1033 prod = prod * self.extract(ii)
1034 }
1035 prod
1036 }
1037
1038 #[inline]
1039 fn from_simd_real(re: Self::SimdRealField) -> Self {
1040 Self::new(re, Self::SimdRealField::zero())
1041 }
1042
1043 #[inline]
1044 fn simd_real(self) -> Self::SimdRealField {
1045 self.re
1046 }
1047
1048 #[inline]
1049 fn simd_imaginary(self) -> Self::SimdRealField {
1050 self.im
1051 }
1052
1053 #[inline]
1054 fn simd_argument(self) -> Self::SimdRealField {
1055 self.im.simd_atan2(self.re)
1056 }
1057
1058 #[inline]
1059 fn simd_modulus(self) -> Self::SimdRealField {
1060 self.re.simd_hypot(self.im)
1061 }
1062
1063 #[inline]
1064 fn simd_modulus_squared(self) -> Self::SimdRealField {
1065 self.re * self.re + self.im * self.im
1066 }
1067
1068 #[inline]
1069 fn simd_norm1(self) -> Self::SimdRealField {
1070 self.re.simd_abs() + self.im.simd_abs()
1071 }
1072
1073 #[inline]
1074 fn simd_recip(self) -> Self {
1075 Self::one() / self
1076 }
1077
1078 #[inline]
1079 fn simd_conjugate(self) -> Self {
1080 self.conj()
1081 }
1082
1083 #[inline]
1084 fn simd_scale(self, factor: Self::SimdRealField) -> Self {
1085 self * factor
1086 }
1087
1088 #[inline]
1089 fn simd_unscale(self, factor: Self::SimdRealField) -> Self {
1090 self / factor
1091 }
1092
1093 #[inline]
1094 fn simd_floor(self) -> Self {
1095 Self::new(self.re.simd_floor(), self.im.simd_floor())
1096 }
1097
1098 #[inline]
1099 fn simd_ceil(self) -> Self {
1100 Self::new(self.re.simd_ceil(), self.im.simd_ceil())
1101 }
1102
1103 #[inline]
1104 fn simd_round(self) -> Self {
1105 Self::new(self.re.simd_round(), self.im.simd_round())
1106 }
1107
1108 #[inline]
1109 fn simd_trunc(self) -> Self {
1110 Self::new(self.re.simd_trunc(), self.im.simd_trunc())
1111 }
1112
1113 #[inline]
1114 fn simd_fract(self) -> Self {
1115 Self::new(self.re.simd_fract(), self.im.simd_fract())
1116 }
1117
1118 #[inline]
1119 fn simd_mul_add(self, a: Self, b: Self) -> Self {
1120 self * a + b
1121 }
1122
1123 #[inline]
1124 fn simd_abs(self) -> Self::SimdRealField {
1125 self.simd_modulus()
1126 }
1127
1128 #[inline]
1129 fn simd_exp2(self) -> Self {
1130 let _2 = AutoSimd::<$t>::one() + AutoSimd::<$t>::one();
1131 num_complex::Complex::new(_2, AutoSimd::<$t>::zero()).simd_powc(self)
1132 }
1133
1134 #[inline]
1135 fn simd_exp_m1(self) -> Self {
1136 self.simd_exp() - Self::one()
1137 }
1138
1139 #[inline]
1140 fn simd_ln_1p(self) -> Self {
1141 (Self::one() + self).simd_ln()
1142 }
1143
1144 #[inline]
1145 fn simd_log2(self) -> Self {
1146 let _2 = AutoSimd::<$t>::one() + AutoSimd::<$t>::one();
1147 self.simd_log(_2)
1148 }
1149
1150 #[inline]
1151 fn simd_log10(self) -> Self {
1152 let _10 = AutoSimd::<$t>::from_subset(&10.0f64);
1153 self.simd_log(_10)
1154 }
1155
1156 #[inline]
1157 fn simd_cbrt(self) -> Self {
1158 let one_third = AutoSimd::<$t>::from_subset(&(1.0 / 3.0));
1159 self.simd_powf(one_third)
1160 }
1161
1162 #[inline]
1163 fn simd_powi(self, n: i32) -> Self {
1164 // FIXME: is there a more accurate solution?
1165 let n = AutoSimd::<$t>::from_subset(&(n as f64));
1166 self.simd_powf(n)
1167 }
1168
1169 /*
1170 *
1171 *
1172 * Unfortunately we are forced to copy-paste all
1173 * those impls from https://github.com/rust-num/num-complex/blob/master/src/lib.rs
1174 * to avoid requiring `std`.
1175 *
1176 *
1177 */
1178 /// Computes `e^(self)`, where `e` is the base of the natural logarithm.
1179 #[inline]
1180 fn simd_exp(self) -> Self {
1181 // formula: e^(a + bi) = e^a (cos(b) + i*sin(b))
1182 // = from_polar(e^a, b)
1183 simd_complex_from_polar(self.re.simd_exp(), self.im)
1184 }
1185
1186 /// Computes the principal value of natural logarithm of `self`.
1187 ///
1188 /// This function has one branch cut:
1189 ///
1190 /// * `(-∞, 0]`, continuous from above.
1191 ///
1192 /// The branch satisfies `-π ≤ arg(ln(z)) ≤ π`.
1193 #[inline]
1194 fn simd_ln(self) -> Self {
1195 // formula: ln(z) = ln|z| + i*arg(z)
1196 let (r, theta) = self.simd_to_polar();
1197 Self::new(r.simd_ln(), theta)
1198 }
1199
1200 /// Computes the principal value of the square root of `self`.
1201 ///
1202 /// This function has one branch cut:
1203 ///
1204 /// * `(-∞, 0)`, continuous from above.
1205 ///
1206 /// The branch satisfies `-π/2 ≤ arg(sqrt(z)) ≤ π/2`.
1207 #[inline]
1208 fn simd_sqrt(self) -> Self {
1209 // formula: sqrt(r e^(it)) = sqrt(r) e^(it/2)
1210 let two = AutoSimd::<$t>::one() + AutoSimd::<$t>::one();
1211 let (r, theta) = self.simd_to_polar();
1212 simd_complex_from_polar(r.simd_sqrt(), theta / two)
1213 }
1214
1215 #[inline]
1216 fn simd_hypot(self, b: Self) -> Self::SimdRealField {
1217 (self.simd_modulus_squared() + b.simd_modulus_squared()).simd_sqrt()
1218 }
1219
1220 /// Raises `self` to a floating point power.
1221 #[inline]
1222 fn simd_powf(self, exp: Self::SimdRealField) -> Self {
1223 // formula: x^y = (ρ e^(i θ))^y = ρ^y e^(i θ y)
1224 // = from_polar(ρ^y, θ y)
1225 let (r, theta) = self.simd_to_polar();
1226 simd_complex_from_polar(r.simd_powf(exp), theta * exp)
1227 }
1228
1229 /// Returns the logarithm of `self` with respect to an arbitrary base.
1230 #[inline]
1231 fn simd_log(self, base: AutoSimd<$t>) -> Self {
1232 // formula: log_y(x) = log_y(ρ e^(i θ))
1233 // = log_y(ρ) + log_y(e^(i θ)) = log_y(ρ) + ln(e^(i θ)) / ln(y)
1234 // = log_y(ρ) + i θ / ln(y)
1235 let (r, theta) = self.simd_to_polar();
1236 Self::new(r.simd_log(base), theta / base.simd_ln())
1237 }
1238
1239 /// Raises `self` to a complex power.
1240 #[inline]
1241 fn simd_powc(self, exp: Self) -> Self {
1242 // formula: x^y = (a + i b)^(c + i d)
1243 // = (ρ e^(i θ))^c (ρ e^(i θ))^(i d)
1244 // where ρ=|x| and θ=arg(x)
1245 // = ρ^c e^(−d θ) e^(i c θ) ρ^(i d)
1246 // = p^c e^(−d θ) (cos(c θ)
1247 // + i sin(c θ)) (cos(d ln(ρ)) + i sin(d ln(ρ)))
1248 // = p^c e^(−d θ) (
1249 // cos(c θ) cos(d ln(ρ)) − sin(c θ) sin(d ln(ρ))
1250 // + i(cos(c θ) sin(d ln(ρ)) + sin(c θ) cos(d ln(ρ))))
1251 // = p^c e^(−d θ) (cos(c θ + d ln(ρ)) + i sin(c θ + d ln(ρ)))
1252 // = from_polar(p^c e^(−d θ), c θ + d ln(ρ))
1253 let (r, theta) = self.simd_to_polar();
1254 simd_complex_from_polar(
1255 r.simd_powf(exp.re) * (-exp.im * theta).simd_exp(),
1256 exp.re * theta + exp.im * r.simd_ln(),
1257 )
1258 }
1259
1260 /*
1261 /// Raises a floating point number to the complex power `self`.
1262 #[inline]
1263 fn simd_expf(&self, base: T) -> Self {
1264 // formula: x^(a+bi) = x^a x^bi = x^a e^(b ln(x) i)
1265 // = from_polar(x^a, b ln(x))
1266 Self::from_polar(&base.powf(self.re), &(self.im * base.ln()))
1267 }
1268 */
1269
1270 /// Computes the sine of `self`.
1271 #[inline]
1272 fn simd_sin(self) -> Self {
1273 // formula: sin(a + bi) = sin(a)cosh(b) + i*cos(a)sinh(b)
1274 Self::new(
1275 self.re.simd_sin() * self.im.simd_cosh(),
1276 self.re.simd_cos() * self.im.simd_sinh(),
1277 )
1278 }
1279
1280 /// Computes the cosine of `self`.
1281 #[inline]
1282 fn simd_cos(self) -> Self {
1283 // formula: cos(a + bi) = cos(a)cosh(b) - i*sin(a)sinh(b)
1284 Self::new(
1285 self.re.simd_cos() * self.im.simd_cosh(),
1286 -self.re.simd_sin() * self.im.simd_sinh(),
1287 )
1288 }
1289
1290 #[inline]
1291 fn simd_sin_cos(self) -> (Self, Self) {
1292 let (rsin, rcos) = self.re.simd_sin_cos();
1293 let (isinh, icosh) = self.im.simd_sinh_cosh();
1294 let sin = Self::new(rsin * icosh, rcos * isinh);
1295 let cos = Self::new(rcos * icosh, -rsin * isinh);
1296
1297 (sin, cos)
1298 }
1299
1300 /// Computes the tangent of `self`.
1301 #[inline]
1302 fn simd_tan(self) -> Self {
1303 // formula: tan(a + bi) = (sin(2a) + i*sinh(2b))/(cos(2a) + cosh(2b))
1304 let (two_re, two_im) = (self.re + self.re, self.im + self.im);
1305 Self::new(two_re.simd_sin(), two_im.simd_sinh()).unscale(two_re.simd_cos() + two_im.simd_cosh())
1306 }
1307
1308 /// Computes the principal value of the inverse sine of `self`.
1309 ///
1310 /// This function has two branch cuts:
1311 ///
1312 /// * `(-∞, -1)`, continuous from above.
1313 /// * `(1, ∞)`, continuous from below.
1314 ///
1315 /// The branch satisfies `-π/2 ≤ Re(asin(z)) ≤ π/2`.
1316 #[inline]
1317 fn simd_asin(self) -> Self {
1318 // formula: arcsin(z) = -i ln(sqrt(1-z^2) + iz)
1319 let i = Self::i();
1320 -i * ((Self::one() - self * self).simd_sqrt() + i * self).simd_ln()
1321 }
1322
1323 /// Computes the principal value of the inverse cosine of `self`.
1324 ///
1325 /// This function has two branch cuts:
1326 ///
1327 /// * `(-∞, -1)`, continuous from above.
1328 /// * `(1, ∞)`, continuous from below.
1329 ///
1330 /// The branch satisfies `0 ≤ Re(acos(z)) ≤ π`.
1331 #[inline]
1332 fn simd_acos(self) -> Self {
1333 // formula: arccos(z) = -i ln(i sqrt(1-z^2) + z)
1334 let i = Self::i();
1335 -i * (i * (Self::one() - self * self).simd_sqrt() + self).simd_ln()
1336 }
1337
1338 /// Computes the principal value of the inverse tangent of `self`.
1339 ///
1340 /// This function has two branch cuts:
1341 ///
1342 /// * `(-∞i, -i]`, continuous from the left.
1343 /// * `[i, ∞i)`, continuous from the right.
1344 ///
1345 /// The branch satisfies `-π/2 ≤ Re(atan(z)) ≤ π/2`.
1346 #[inline]
1347 fn simd_atan(self) -> Self {
1348 // formula: arctan(z) = (ln(1+iz) - ln(1-iz))/(2i)
1349 let i = Self::i();
1350 let one = Self::one();
1351 let two = one + one;
1352
1353 if self == i {
1354 return Self::new(AutoSimd::<$t>::zero(), AutoSimd::<$t>::one() / AutoSimd::<$t>::zero());
1355 } else if self == -i {
1356 return Self::new(AutoSimd::<$t>::zero(), -AutoSimd::<$t>::one() / AutoSimd::<$t>::zero());
1357 }
1358
1359 ((one + i * self).simd_ln() - (one - i * self).simd_ln()) / (two * i)
1360 }
1361
1362 /// Computes the hyperbolic sine of `self`.
1363 #[inline]
1364 fn simd_sinh(self) -> Self {
1365 // formula: sinh(a + bi) = sinh(a)cos(b) + i*cosh(a)sin(b)
1366 Self::new(
1367 self.re.simd_sinh() * self.im.simd_cos(),
1368 self.re.simd_cosh() * self.im.simd_sin(),
1369 )
1370 }
1371
1372 /// Computes the hyperbolic cosine of `self`.
1373 #[inline]
1374 fn simd_cosh(self) -> Self {
1375 // formula: cosh(a + bi) = cosh(a)cos(b) + i*sinh(a)sin(b)
1376 Self::new(
1377 self.re.simd_cosh() * self.im.simd_cos(),
1378 self.re.simd_sinh() * self.im.simd_sin(),
1379 )
1380 }
1381
1382 #[inline]
1383 fn simd_sinh_cosh(self) -> (Self, Self) {
1384 let (rsinh, rcosh) = self.re.simd_sinh_cosh();
1385 let (isin, icos) = self.im.simd_sin_cos();
1386 let sin = Self::new(rsinh * icos, rcosh * isin);
1387 let cos = Self::new(rcosh * icos, rsinh * isin);
1388
1389 (sin, cos)
1390 }
1391
1392 /// Computes the hyperbolic tangent of `self`.
1393 #[inline]
1394 fn simd_tanh(self) -> Self {
1395 // formula: tanh(a + bi) = (sinh(2a) + i*sin(2b))/(cosh(2a) + cos(2b))
1396 let (two_re, two_im) = (self.re + self.re, self.im + self.im);
1397 Self::new(two_re.simd_sinh(), two_im.simd_sin()).unscale(two_re.simd_cosh() + two_im.simd_cos())
1398 }
1399
1400 /// Computes the principal value of inverse hyperbolic sine of `self`.
1401 ///
1402 /// This function has two branch cuts:
1403 ///
1404 /// * `(-∞i, -i)`, continuous from the left.
1405 /// * `(i, ∞i)`, continuous from the right.
1406 ///
1407 /// The branch satisfies `-π/2 ≤ Im(asinh(z)) ≤ π/2`.
1408 #[inline]
1409 fn simd_asinh(self) -> Self {
1410 // formula: arcsinh(z) = ln(z + sqrt(1+z^2))
1411 let one = Self::one();
1412 (self + (one + self * self).simd_sqrt()).simd_ln()
1413 }
1414
1415 /// Computes the principal value of inverse hyperbolic cosine of `self`.
1416 ///
1417 /// This function has one branch cut:
1418 ///
1419 /// * `(-∞, 1)`, continuous from above.
1420 ///
1421 /// The branch satisfies `-π ≤ Im(acosh(z)) ≤ π` and `0 ≤ Re(acosh(z)) < ∞`.
1422 #[inline]
1423 fn simd_acosh(self) -> Self {
1424 // formula: arccosh(z) = 2 ln(sqrt((z+1)/2) + sqrt((z-1)/2))
1425 let one = Self::one();
1426 let two = one + one;
1427 two * (((self + one) / two).simd_sqrt() + ((self - one) / two).simd_sqrt()).simd_ln()
1428 }
1429
1430 /// Computes the principal value of inverse hyperbolic tangent of `self`.
1431 ///
1432 /// This function has two branch cuts:
1433 ///
1434 /// * `(-∞, -1]`, continuous from above.
1435 /// * `[1, ∞)`, continuous from below.
1436 ///
1437 /// The branch satisfies `-π/2 ≤ Im(atanh(z)) ≤ π/2`.
1438 #[inline]
1439 fn simd_atanh(self) -> Self {
1440 // formula: arctanh(z) = (ln(1+z) - ln(1-z))/2
1441 let one = Self::one();
1442 let two = one + one;
1443 if self == one {
1444 return Self::new(AutoSimd::<$t>::one() / AutoSimd::<$t>::zero(), AutoSimd::<$t>::zero());
1445 } else if self == -one {
1446 return Self::new(-AutoSimd::<$t>::one() / AutoSimd::<$t>::zero(), AutoSimd::<$t>::zero());
1447 }
1448 ((one + self).simd_ln() - (one - self).simd_ln()) / two
1449 }
1450 }
1451 )*)
1452 );
1453
1454 #[inline]
simd_complex_from_polar<N: SimdRealField>(r: N, theta: N) -> num_complex::Complex<N>1455 fn simd_complex_from_polar<N: SimdRealField>(r: N, theta: N) -> num_complex::Complex<N> {
1456 num_complex::Complex::new(r.clone() * theta.clone().simd_cos(), r * theta.simd_sin())
1457 }
1458
1459 impl_float_simd!(
1460 [f32; 2], f32, 2, [i32; 2], AutoBoolx2, _0, _1;
1461 [f32; 4], f32, 4, [i32; 4], AutoBoolx4, _0, _1, _2, _3;
1462 [f32; 8], f32, 8, [i32; 8], AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1463 [f32; 16], f32, 16, [i32; 16], AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1464 [f64; 2], f64, 2, [i64; 2], AutoBoolx2, _0, _1;
1465 [f64; 4], f64, 4, [i64; 4], AutoBoolx4, _0, _1, _2, _3;
1466 [f64; 8], f64, 8, [i64; 8], AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1467 );
1468
1469 impl_int_simd!(
1470 [i128; 1], i128, 1, AutoBoolx1, _0;
1471 [i128; 2], i128, 2, AutoBoolx2, _0, _1;
1472 [i128; 4], i128, 4, AutoBoolx4, _0, _1, _2, _3;
1473 [i16; 2], i16, 2, AutoBoolx2, _0, _1;
1474 [i16; 4], i16, 4, AutoBoolx4, _0, _1, _2, _3;
1475 [i16; 8], i16, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1476 [i16; 16], i16, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1477 [i16; 32], i16, 32, AutoBoolx32, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31;
1478 [i32; 2], i32, 2, AutoBoolx2, _0, _1;
1479 [i32; 4], i32, 4, AutoBoolx4, _0, _1, _2, _3;
1480 [i32; 8], i32, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1481 [i32; 16], i32, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1482 [i64; 2], i64, 2, AutoBoolx2, _0, _1;
1483 [i64; 4], i64, 4, AutoBoolx4, _0, _1, _2, _3;
1484 [i64; 8], i64, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1485 [i8; 2], i8, 2, AutoBoolx2, _0, _1;
1486 [i8; 4], i8, 4, AutoBoolx4, _0, _1, _2, _3;
1487 [i8; 8], i8, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1488 [i8; 16], i8, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1489 [i8; 32], i8, 32, AutoBoolx32, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31;
1490 // [i8; 64], i8, 64, AutoBoolx64, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63;
1491 [isize; 2], isize, 2, AutoBoolx2, _0, _1;
1492 [isize; 4], isize, 4, AutoBoolx4, _0, _1, _2, _3;
1493 [isize; 8], isize, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1494 );
1495
1496 impl_uint_simd!(
1497 [u128; 1], u128, 1, AutoBoolx1, _0;
1498 [u128; 2], u128, 2, AutoBoolx2, _0, _1;
1499 [u128; 4], u128, 4, AutoBoolx4, _0, _1, _2, _3;
1500 [u16; 2], u16, 2, AutoBoolx2, _0, _1;
1501 [u16; 4], u16, 4, AutoBoolx4, _0, _1, _2, _3;
1502 [u16; 8], u16, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1503 [u16; 16], u16, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1504 [u16; 32], u16, 32, AutoBoolx32, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31;
1505 [u32; 2], u32, 2, AutoBoolx2, _0, _1;
1506 [u32; 4], u32, 4, AutoBoolx4, _0, _1, _2, _3;
1507 [u32; 8], u32, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1508 [u32; 16], u32, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1509 [u64; 2], u64, 2, AutoBoolx2, _0, _1;
1510 [u64; 4], u64, 4, AutoBoolx4, _0, _1, _2, _3;
1511 [u64; 8], u64, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1512 [u8; 2], u8, 2, AutoBoolx2, _0, _1;
1513 [u8; 4], u8, 4, AutoBoolx4, _0, _1, _2, _3;
1514 [u8; 8], u8, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1515 [u8; 16], u8, 16, AutoBoolx16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1516 [u8; 32], u8, 32, AutoBoolx32, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31;
1517 // [u8; 64], u8, 64, AutoBoolx64, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63;
1518 [usize; 2], usize, 2, AutoBoolx2, _0, _1;
1519 [usize; 4], usize, 4, AutoBoolx4, _0, _1, _2, _3;
1520 [usize; 8], usize, 8, AutoBoolx8, _0, _1, _2, _3, _4, _5, _6, _7;
1521 );
1522
1523 impl_bool_simd!(
1524 [bool; 1], 1, _0;
1525 [bool; 2], 2, _0, _1;
1526 [bool; 4], 4, _0, _1, _2, _3;
1527 [bool; 8], 8, _0, _1, _2, _3, _4, _5, _6, _7;
1528 [bool; 16], 16, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15;
1529 [bool; 32], 32, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31;
1530 // [bool; 64], 64, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63;
1531 );
1532
1533 //
1534 // NOTE: the following does not work because of the orphan rules.
1535 //
1536 //macro_rules! impl_simd_complex_from(
1537 // ($($t: ty, $elt: ty $(, $i: expr)*;)*) => ($(
1538 // impl From<[num_complex::Complex<$elt>; $lanes]> for num_complex::Complex<AutoSimd<$t>> {
1539 // #[inline(always)]
1540 // fn from(vals: [num_complex::Complex<$elt>; $lanes]) -> Self {
1541 // num_complex::Complex {
1542 // re: <$t>::from([$(vals[$i].re),*]),
1543 // im: <$t>::from([$(vals[$i].im),*]),
1544 // }
1545 // }
1546 // }
1547 // )*)
1548 //);
1549 //
1550 //impl_simd_complex_from!(
1551 // [f32; 2], f32, 0, 1;
1552 // [f32; 4], f32, 0, 1, 2, 3;
1553 // [f32; 8], f32, 0, 1, 2, 3, 4, 5, 6, 7;
1554 // [f32; 16], f32, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15;
1555 //);
1556
1557 //////////////////////////////////////////
1558 // Aliases //
1559 //////////////////////////////////////////
1560
1561 pub type AutoF32x2 = AutoSimd<[f32; 2]>;
1562 pub type AutoF32x4 = AutoSimd<[f32; 4]>;
1563 pub type AutoF32x8 = AutoSimd<[f32; 8]>;
1564 pub type AutoF32x16 = AutoSimd<[f32; 16]>;
1565 pub type AutoF64x2 = AutoSimd<[f64; 2]>;
1566 pub type AutoF64x4 = AutoSimd<[f64; 4]>;
1567 pub type AutoF64x8 = AutoSimd<[f64; 8]>;
1568 pub type AutoI128x1 = AutoSimd<[i128; 1]>;
1569 pub type AutoI128x2 = AutoSimd<[i128; 2]>;
1570 pub type AutoI128x4 = AutoSimd<[i128; 4]>;
1571 pub type AutoI16x2 = AutoSimd<[i16; 2]>;
1572 pub type AutoI16x4 = AutoSimd<[i16; 4]>;
1573 pub type AutoI16x8 = AutoSimd<[i16; 8]>;
1574 pub type AutoI16x16 = AutoSimd<[i16; 16]>;
1575 pub type AutoI16x32 = AutoSimd<[i16; 32]>;
1576 pub type AutoI32x2 = AutoSimd<[i32; 2]>;
1577 pub type AutoI32x4 = AutoSimd<[i32; 4]>;
1578 pub type AutoI32x8 = AutoSimd<[i32; 8]>;
1579 pub type AutoI32x16 = AutoSimd<[i32; 16]>;
1580 pub type AutoI64x2 = AutoSimd<[i64; 2]>;
1581 pub type AutoI64x4 = AutoSimd<[i64; 4]>;
1582 pub type AutoI64x8 = AutoSimd<[i64; 8]>;
1583 pub type AutoI8x2 = AutoSimd<[i8; 2]>;
1584 pub type AutoI8x4 = AutoSimd<[i8; 4]>;
1585 pub type AutoI8x8 = AutoSimd<[i8; 8]>;
1586 pub type AutoI8x16 = AutoSimd<[i8; 16]>;
1587 pub type AutoI8x32 = AutoSimd<[i8; 32]>;
1588 // pub type AutoI8x64 = AutoSimd<[i8; 64]>;
1589 pub type AutoIsizex2 = AutoSimd<[isize; 2]>;
1590 pub type AutoIsizex4 = AutoSimd<[isize; 4]>;
1591 pub type AutoIsizex8 = AutoSimd<[isize; 8]>;
1592 pub type AutoU128x1 = AutoSimd<[u128; 1]>;
1593 pub type AutoU128x2 = AutoSimd<[u128; 2]>;
1594 pub type AutoU128x4 = AutoSimd<[u128; 4]>;
1595 pub type AutoU16x2 = AutoSimd<[u16; 2]>;
1596 pub type AutoU16x4 = AutoSimd<[u16; 4]>;
1597 pub type AutoU16x8 = AutoSimd<[u16; 8]>;
1598 pub type AutoU16x16 = AutoSimd<[u16; 16]>;
1599 pub type AutoU16x32 = AutoSimd<[u16; 32]>;
1600 pub type AutoU32x2 = AutoSimd<[u32; 2]>;
1601 pub type AutoU32x4 = AutoSimd<[u32; 4]>;
1602 pub type AutoU32x8 = AutoSimd<[u32; 8]>;
1603 pub type AutoU32x16 = AutoSimd<[u32; 16]>;
1604 pub type AutoU64x2 = AutoSimd<[u64; 2]>;
1605 pub type AutoU64x4 = AutoSimd<[u64; 4]>;
1606 pub type AutoU64x8 = AutoSimd<[u64; 8]>;
1607 pub type AutoU8x2 = AutoSimd<[u8; 2]>;
1608 pub type AutoU8x4 = AutoSimd<[u8; 4]>;
1609 pub type AutoU8x8 = AutoSimd<[u8; 8]>;
1610 pub type AutoU8x16 = AutoSimd<[u8; 16]>;
1611 pub type AutoU8x32 = AutoSimd<[u8; 32]>;
1612 // pub type AutoU8x64 = AutoSimd<[u8; 64]>;
1613 pub type AutoUsizex2 = AutoSimd<[usize; 2]>;
1614 pub type AutoUsizex4 = AutoSimd<[usize; 4]>;
1615 pub type AutoUsizex8 = AutoSimd<[usize; 8]>;
1616
1617 pub type AutoBoolx1 = AutoSimd<[bool; 1]>;
1618 pub type AutoBoolx16 = AutoSimd<[bool; 16]>;
1619 pub type AutoBoolx2 = AutoSimd<[bool; 2]>;
1620 pub type AutoBoolx32 = AutoSimd<[bool; 32]>;
1621 pub type AutoBoolx4 = AutoSimd<[bool; 4]>;
1622 // pub type AutoBoolx64 = AutoSimd<[bool; 64]>;
1623 pub type AutoBoolx8 = AutoSimd<[bool; 8]>;
1624
1625 /*
1626 * Helper trait to transform an array.
1627 */
1628 trait ArrTransform: SimdValue {
map(self, f: impl Fn(Self::Element) -> Self::Element) -> Self1629 fn map(self, f: impl Fn(Self::Element) -> Self::Element) -> Self;
zip_map( self, other: Self, f: impl Fn(Self::Element, Self::Element) -> Self::Element, ) -> Self1630 fn zip_map(
1631 self,
1632 other: Self,
1633 f: impl Fn(Self::Element, Self::Element) -> Self::Element,
1634 ) -> Self;
zip_zip_map( self, b: Self, c: Self, f: impl Fn(Self::Element, Self::Element, Self::Element) -> Self::Element, ) -> Self1635 fn zip_zip_map(
1636 self,
1637 b: Self,
1638 c: Self,
1639 f: impl Fn(Self::Element, Self::Element, Self::Element) -> Self::Element,
1640 ) -> Self;
map_bool(self, f: impl Fn(Self::Element) -> bool) -> Self::SimdBool1641 fn map_bool(self, f: impl Fn(Self::Element) -> bool) -> Self::SimdBool;
zip_map_bool( self, other: Self, f: impl Fn(Self::Element, Self::Element) -> bool, ) -> Self::SimdBool1642 fn zip_map_bool(
1643 self,
1644 other: Self,
1645 f: impl Fn(Self::Element, Self::Element) -> bool,
1646 ) -> Self::SimdBool;
1647 }
1648