1use super::*;
2
3pick! {
4 if #[cfg(target_feature="sse2")] {
5 #[derive(Default, Clone, Copy, PartialEq)]
6 #[repr(C, align(16))]
7 pub struct f64x2 { pub(crate) sse: m128d }
8 } else if #[cfg(target_feature="simd128")] {
9 use core::arch::wasm32::*;
10
11 #[derive(Clone, Copy)]
12 #[repr(transparent)]
13 pub struct f64x2 { pub(crate) simd: v128 }
14
15 impl Default for f64x2 {
16 fn default() -> Self {
17 Self::splat(0.0)
18 }
19 }
20
21 impl PartialEq for f64x2 {
22 fn eq(&self, other: &Self) -> bool {
23 u64x2_all_true(f64x2_eq(self.simd, other.simd))
24 }
25 }
26 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
27 use core::arch::aarch64::*;
28 #[repr(C)]
29 #[derive(Copy, Clone)]
30 pub struct f64x2 { pub(crate) neon: float64x2_t }
31
32 impl Default for f64x2 {
33 #[inline]
34 fn default() -> Self {
35 unsafe { Self { neon: vdupq_n_f64(0.0)} }
36 }
37 }
38
39 impl PartialEq for f64x2 {
40 #[inline]
41 fn eq(&self, other: &Self) -> bool {
42 unsafe
43 { let e = vceqq_f64(self.neon, other.neon);
44 vgetq_lane_u64(e,0) == u64::MAX && vgetq_lane_u64(e,1) == u64::MAX
45 }
46 }
47
48 }
49 } else {
50 #[derive(Default, Clone, Copy, PartialEq)]
51 #[repr(C, align(16))]
52 pub struct f64x2 { pub(crate) arr: [f64;2] }
53 }
54}
55
56macro_rules! const_f64_as_f64x2 {
57 ($i:ident, $f:expr) => {
58 #[allow(non_upper_case_globals)]
59 pub const $i: f64x2 = f64x2::new([$f; 2]);
60 };
61}
62
63impl f64x2 {
64 const_f64_as_f64x2!(ONE, 1.0);
65 const_f64_as_f64x2!(ZERO, 0.0);
66 const_f64_as_f64x2!(HALF, 0.5);
67 const_f64_as_f64x2!(EPSILON, f64::EPSILON);
68 const_f64_as_f64x2!(MIN, f64::MIN);
69 const_f64_as_f64x2!(MIN_POSITIVE, f64::MIN_POSITIVE);
70 const_f64_as_f64x2!(MAX, f64::MAX);
71 const_f64_as_f64x2!(NAN, f64::NAN);
72 const_f64_as_f64x2!(INFINITY, f64::INFINITY);
73 const_f64_as_f64x2!(NEG_INFINITY, f64::NEG_INFINITY);
74 const_f64_as_f64x2!(E, core::f64::consts::E);
75 const_f64_as_f64x2!(FRAC_1_PI, core::f64::consts::FRAC_1_PI);
76 const_f64_as_f64x2!(FRAC_2_PI, core::f64::consts::FRAC_2_PI);
77 const_f64_as_f64x2!(FRAC_2_SQRT_PI, core::f64::consts::FRAC_2_SQRT_PI);
78 const_f64_as_f64x2!(FRAC_1_SQRT_2, core::f64::consts::FRAC_1_SQRT_2);
79 const_f64_as_f64x2!(FRAC_PI_2, core::f64::consts::FRAC_PI_2);
80 const_f64_as_f64x2!(FRAC_PI_3, core::f64::consts::FRAC_PI_3);
81 const_f64_as_f64x2!(FRAC_PI_4, core::f64::consts::FRAC_PI_4);
82 const_f64_as_f64x2!(FRAC_PI_6, core::f64::consts::FRAC_PI_6);
83 const_f64_as_f64x2!(FRAC_PI_8, core::f64::consts::FRAC_PI_8);
84 const_f64_as_f64x2!(LN_2, core::f64::consts::LN_2);
85 const_f64_as_f64x2!(LN_10, core::f64::consts::LN_10);
86 const_f64_as_f64x2!(LOG2_E, core::f64::consts::LOG2_E);
87 const_f64_as_f64x2!(LOG10_E, core::f64::consts::LOG10_E);
88 const_f64_as_f64x2!(LOG10_2, core::f64::consts::LOG10_2);
89 const_f64_as_f64x2!(LOG2_10, core::f64::consts::LOG2_10);
90 const_f64_as_f64x2!(PI, core::f64::consts::PI);
91 const_f64_as_f64x2!(SQRT_2, core::f64::consts::SQRT_2);
92 const_f64_as_f64x2!(TAU, core::f64::consts::TAU);
93}
94
95unsafe impl Zeroable for f64x2 {}
96unsafe impl Pod for f64x2 {}
97
98impl AlignTo for f64x2 {
99 type Elem = f64;
100}
101
102impl Add for f64x2 {
103 type Output = Self;
104 #[inline]
105 fn add(self, rhs: Self) -> Self::Output {
106 pick! {
107 if #[cfg(target_feature="sse2")] {
108 Self { sse: add_m128d(self.sse, rhs.sse) }
109 } else if #[cfg(target_feature="simd128")] {
110 Self { simd: f64x2_add(self.simd, rhs.simd) }
111 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
112 unsafe { Self { neon: vaddq_f64(self.neon, rhs.neon) } }
113 } else {
114 Self { arr: [
115 self.arr[0] + rhs.arr[0],
116 self.arr[1] + rhs.arr[1],
117 ]}
118 }
119 }
120 }
121}
122
123impl Sub for f64x2 {
124 type Output = Self;
125 #[inline]
126 fn sub(self, rhs: Self) -> Self::Output {
127 pick! {
128 if #[cfg(target_feature="sse2")] {
129 Self { sse: sub_m128d(self.sse, rhs.sse) }
130 } else if #[cfg(target_feature="simd128")] {
131 Self { simd: f64x2_sub(self.simd, rhs.simd) }
132 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
133 unsafe { Self { neon: vsubq_f64(self.neon, rhs.neon) } }
134 } else {
135 Self { arr: [
136 self.arr[0] - rhs.arr[0],
137 self.arr[1] - rhs.arr[1],
138 ]}
139 }
140 }
141 }
142}
143
144impl Mul for f64x2 {
145 type Output = Self;
146 #[inline]
147 fn mul(self, rhs: Self) -> Self::Output {
148 pick! {
149 if #[cfg(target_feature="sse2")] {
150 Self { sse: mul_m128d(self.sse, rhs.sse) }
151 } else if #[cfg(target_feature="simd128")] {
152 Self { simd: f64x2_mul(self.simd, rhs.simd) }
153 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
154 unsafe {Self { neon: vmulq_f64(self.neon, rhs.neon) }}
155 } else {
156 Self { arr: [
157 self.arr[0] * rhs.arr[0],
158 self.arr[1] * rhs.arr[1],
159 ]}
160 }
161 }
162 }
163}
164
165impl Div for f64x2 {
166 type Output = Self;
167 #[inline]
168 fn div(self, rhs: Self) -> Self::Output {
169 pick! {
170 if #[cfg(target_feature="sse2")] {
171 Self { sse: div_m128d(self.sse, rhs.sse) }
172 } else if #[cfg(target_feature="simd128")] {
173 Self { simd: f64x2_div(self.simd, rhs.simd) }
174 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
175 unsafe {Self { neon: vdivq_f64(self.neon, rhs.neon) }}
176 } else {
177 Self { arr: [
178 self.arr[0] / rhs.arr[0],
179 self.arr[1] / rhs.arr[1],
180 ]}
181 }
182 }
183 }
184}
185
186impl Rem for f64x2 {
187 type Output = Self;
188 #[inline]
189 fn rem(self, rhs: Self) -> Self::Output {
190 Self::new([
191 self.to_array()[0] % rhs.to_array()[0],
192 self.to_array()[1] % rhs.to_array()[1],
193 ])
194 }
195}
196
197impl Neg for f64x2 {
198 type Output = Self;
199 #[inline]
200 fn neg(self) -> Self::Output {
201 pick! {
202 if #[cfg(target_feature="sse")] {
203 Self { sse: bitxor_m128d(self.sse, Self::splat(-0.0).sse) }
204 } else if #[cfg(target_feature="simd128")] {
205 Self { simd: f64x2_neg(self.simd) }
206 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
207 unsafe {Self { neon: vnegq_f64(self.neon) }}
208 } else {
209 Self { arr: [
210 -self.arr[0],
211 -self.arr[1],
212 ]}
213 }
214 }
215 }
216}
217
218impl Add<f64> for f64x2 {
219 type Output = Self;
220 #[inline]
221 fn add(self, rhs: f64) -> Self::Output {
222 self.add(Self::splat(rhs))
223 }
224}
225
226impl Sub<f64> for f64x2 {
227 type Output = Self;
228 #[inline]
229 fn sub(self, rhs: f64) -> Self::Output {
230 self.sub(Self::splat(rhs))
231 }
232}
233
234impl Mul<f64> for f64x2 {
235 type Output = Self;
236 #[inline]
237 fn mul(self, rhs: f64) -> Self::Output {
238 self.mul(Self::splat(rhs))
239 }
240}
241
242impl Div<f64> for f64x2 {
243 type Output = Self;
244 #[inline]
245 fn div(self, rhs: f64) -> Self::Output {
246 self.div(Self::splat(rhs))
247 }
248}
249
250impl Rem<f64> for f64x2 {
251 type Output = Self;
252 #[inline]
253 fn rem(self, rhs: f64) -> Self::Output {
254 self.rem(Self::splat(rhs))
255 }
256}
257
258impl Add<f64x2> for f64 {
259 type Output = f64x2;
260 #[inline]
261 fn add(self, rhs: f64x2) -> Self::Output {
262 f64x2::splat(self).add(rhs)
263 }
264}
265
266impl Sub<f64x2> for f64 {
267 type Output = f64x2;
268 #[inline]
269 fn sub(self, rhs: f64x2) -> Self::Output {
270 f64x2::splat(self).sub(rhs)
271 }
272}
273
274impl Mul<f64x2> for f64 {
275 type Output = f64x2;
276 #[inline]
277 fn mul(self, rhs: f64x2) -> Self::Output {
278 f64x2::splat(self).mul(rhs)
279 }
280}
281
282impl Div<f64x2> for f64 {
283 type Output = f64x2;
284 #[inline]
285 fn div(self, rhs: f64x2) -> Self::Output {
286 f64x2::splat(self).div(rhs)
287 }
288}
289
290impl Rem<f64x2> for f64 {
291 type Output = f64x2;
292 #[inline]
293 fn rem(self, rhs: f64x2) -> Self::Output {
294 f64x2::splat(self).rem(rhs)
295 }
296}
297
298impl BitAnd for f64x2 {
299 type Output = Self;
300 #[inline]
301 fn bitand(self, rhs: Self) -> Self::Output {
302 pick! {
303 if #[cfg(target_feature="sse2")] {
304 Self { sse: bitand_m128d(self.sse, rhs.sse) }
305 } else if #[cfg(target_feature="simd128")] {
306 Self { simd: v128_and(self.simd, rhs.simd) }
307 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
308 unsafe {Self { neon: vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(self.neon), vreinterpretq_u64_f64(rhs.neon))) }}
309 } else {
310 Self { arr: [
311 f64::from_bits(self.arr[0].to_bits() & rhs.arr[0].to_bits()),
312 f64::from_bits(self.arr[1].to_bits() & rhs.arr[1].to_bits()),
313 ]}
314 }
315 }
316 }
317}
318
319impl BitOr for f64x2 {
320 type Output = Self;
321 #[inline]
322 fn bitor(self, rhs: Self) -> Self::Output {
323 pick! {
324 if #[cfg(target_feature="sse2")] {
325 Self { sse: bitor_m128d(self.sse, rhs.sse) }
326 } else if #[cfg(target_feature="simd128")] {
327 Self { simd: v128_or(self.simd, rhs.simd) }
328 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
329 unsafe {Self { neon: vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(self.neon), vreinterpretq_u64_f64(rhs.neon))) }}
330 } else {
331 Self { arr: [
332 f64::from_bits(self.arr[0].to_bits() | rhs.arr[0].to_bits()),
333 f64::from_bits(self.arr[1].to_bits() | rhs.arr[1].to_bits()),
334 ]}
335 }
336 }
337 }
338}
339
340impl BitXor for f64x2 {
341 type Output = Self;
342 #[inline]
343 fn bitxor(self, rhs: Self) -> Self::Output {
344 pick! {
345 if #[cfg(target_feature="sse2")] {
346 Self { sse: bitxor_m128d(self.sse, rhs.sse) }
347 } else if #[cfg(target_feature="simd128")] {
348 Self { simd: v128_xor(self.simd, rhs.simd) }
349 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
350 unsafe {Self { neon: vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(self.neon), vreinterpretq_u64_f64(rhs.neon))) }}
351 } else {
352 Self { arr: [
353 f64::from_bits(self.arr[0].to_bits() ^ rhs.arr[0].to_bits()),
354 f64::from_bits(self.arr[1].to_bits() ^ rhs.arr[1].to_bits()),
355 ]}
356 }
357 }
358 }
359}
360
361#[expect(deprecated)]
362impl CmpEq for f64x2 {
363 type Output = Self;
364 #[inline]
365 fn simd_eq(self, rhs: Self) -> Self::Output {
366 pick! {
367 if #[cfg(target_feature="sse2")] {
368 Self { sse: cmp_eq_mask_m128d(self.sse, rhs.sse) }
369 } else if #[cfg(target_feature="simd128")] {
370 Self { simd: f64x2_eq(self.simd, rhs.simd) }
371 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
372 unsafe {Self { neon: vreinterpretq_f64_u64(vceqq_f64(self.neon, rhs.neon)) }}
373 } else {
374 Self { arr: [
375 if self.arr[0] == rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
376 if self.arr[1] == rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
377 ]}
378 }
379 }
380 }
381}
382
383#[expect(deprecated)]
384impl CmpGe for f64x2 {
385 type Output = Self;
386 #[inline]
387 fn simd_ge(self, rhs: Self) -> Self::Output {
388 pick! {
389 if #[cfg(target_feature="sse2")] {
390 Self { sse: cmp_ge_mask_m128d(self.sse, rhs.sse) }
391 } else if #[cfg(target_feature="simd128")] {
392 Self { simd: f64x2_ge(self.simd, rhs.simd) }
393 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
394 unsafe {Self { neon: vreinterpretq_f64_u64(vcgeq_f64(self.neon, rhs.neon)) }}
395 } else {
396 Self { arr: [
397 if self.arr[0] >= rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
398 if self.arr[1] >= rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
399 ]}
400 }
401 }
402 }
403}
404
405#[expect(deprecated)]
406impl CmpGt for f64x2 {
407 type Output = Self;
408 #[inline]
409 fn simd_gt(self, rhs: Self) -> Self::Output {
410 pick! {
411 if #[cfg(target_feature="avx")] {
412 Self { sse: cmp_op_mask_m128d::<{cmp_op!(GreaterThanOrdered)}>(self.sse, rhs.sse) }
413 } else if #[cfg(target_feature="sse2")] {
414 Self { sse: cmp_gt_mask_m128d(self.sse, rhs.sse) }
415 } else if #[cfg(target_feature="simd128")] {
416 Self { simd: f64x2_gt(self.simd, rhs.simd) }
417 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
418 unsafe {Self { neon: vreinterpretq_f64_u64(vcgtq_f64(self.neon, rhs.neon)) }}
419 } else {
420 Self { arr: [
421 if self.arr[0] > rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
422 if self.arr[1] > rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
423 ]}
424 }
425 }
426 }
427}
428
429#[expect(deprecated)]
430impl CmpNe for f64x2 {
431 type Output = Self;
432 #[inline]
433 fn simd_ne(self, rhs: Self) -> Self::Output {
434 pick! {
435 if #[cfg(target_feature="sse2")] {
436 Self { sse: cmp_neq_mask_m128d(self.sse, rhs.sse) }
437 } else if #[cfg(target_feature="simd128")] {
438 Self { simd: f64x2_ne(self.simd, rhs.simd) }
439 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
440 unsafe {Self { neon: vreinterpretq_f64_u64(vceqq_f64(self.neon, rhs.neon)) }.not() }
441 } else {
442 Self { arr: [
443 if self.arr[0] != rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
444 if self.arr[1] != rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
445 ]}
446 }
447 }
448 }
449}
450
451#[expect(deprecated)]
452impl CmpLe for f64x2 {
453 type Output = Self;
454 #[inline]
455 fn simd_le(self, rhs: Self) -> Self::Output {
456 pick! {
457 if #[cfg(target_feature="sse2")] {
458 Self { sse: cmp_le_mask_m128d(self.sse, rhs.sse) }
459 } else if #[cfg(target_feature="simd128")] {
460 Self { simd: f64x2_le(self.simd, rhs.simd) }
461 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
462 unsafe {Self { neon: vreinterpretq_f64_u64(vcleq_f64(self.neon, rhs.neon)) }}
463 } else {
464 Self { arr: [
465 if self.arr[0] <= rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
466 if self.arr[1] <= rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
467 ]}
468 }
469 }
470 }
471}
472
473#[expect(deprecated)]
474impl CmpLt for f64x2 {
475 type Output = Self;
476 #[inline]
477 fn simd_lt(self, rhs: Self) -> Self::Output {
478 pick! {
479 if #[cfg(target_feature="sse2")] {
480 Self { sse: cmp_lt_mask_m128d(self.sse, rhs.sse) }
481 } else if #[cfg(target_feature="simd128")] {
482 Self { simd: f64x2_lt(self.simd, rhs.simd) }
483 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
484 unsafe {Self { neon: vreinterpretq_f64_u64(vcltq_f64(self.neon, rhs.neon)) }}
485 } else {
486 Self { arr: [
487 if self.arr[0] < rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
488 if self.arr[1] < rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
489 ]}
490 }
491 }
492 }
493}
494
495impl f64x2 {
496 #[inline]
497 #[must_use]
498 pub const fn new(array: [f64; 2]) -> Self {
499 unsafe { core::mem::transmute(array) }
500 }
501
502 simd_comparison_fns!();
503
504 #[inline]
505 #[must_use]
506 pub fn blend(self, t: Self, f: Self) -> Self {
507 pick! {
508 if #[cfg(target_feature="sse4.1")] {
509 Self { sse: blend_varying_m128d(f.sse, t.sse, self.sse) }
510 } else if #[cfg(target_feature="simd128")] {
511 Self { simd: v128_bitselect(t.simd, f.simd, self.simd) }
512 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
513 unsafe {Self { neon: vbslq_f64(vreinterpretq_u64_f64(self.neon), t.neon, f.neon) }}
514 } else {
515 generic_bit_blend(self, t, f)
516 }
517 }
518 }
519 #[inline]
520 #[must_use]
521 pub fn abs(self) -> Self {
522 pick! {
523 if #[cfg(target_feature="simd128")] {
524 Self { simd: f64x2_abs(self.simd) }
525 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
526 unsafe {Self { neon: vabsq_f64(self.neon) }}
527 } else {
528 let non_sign_bits = f64x2::from(f64::from_bits(i64::MAX as u64));
529 self & non_sign_bits
530 }
531 }
532 }
533
534 #[inline]
535 #[must_use]
536 pub fn signum(self) -> Self {
537 let result = Self::ONE | self & -Self::ZERO;
538
539 self.is_nan().blend(self, result)
540 }
541
542 #[inline]
543 #[must_use]
544 pub fn floor(self) -> Self {
545 pick! {
546 if #[cfg(target_feature="simd128")] {
547 Self { simd: f64x2_floor(self.simd) }
548 } else if #[cfg(target_feature="sse4.1")] {
549 Self { sse: floor_m128d(self.sse) }
550 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
551 unsafe {Self { neon: vrndmq_f64(self.neon) }}
552 } else if #[cfg(feature="std")] {
553 let base: [f64; 2] = cast(self);
554 cast(base.map(|val| val.floor()))
555 } else {
556 let base: [f64; 2] = cast(self);
557 let rounded: [f64; 2] = cast(self.round());
558 cast([
559 if base[0] < rounded[0] { rounded[0] - 1.0 } else { rounded[0] },
560 if base[1] < rounded[1] { rounded[1] - 1.0 } else { rounded[1] },
561 ])
562 }
563 }
564 }
565 #[inline]
566 #[must_use]
567 pub fn ceil(self) -> Self {
568 pick! {
569 if #[cfg(target_feature="simd128")] {
570 Self { simd: f64x2_ceil(self.simd) }
571 } else if #[cfg(target_feature="sse4.1")] {
572 Self { sse: ceil_m128d(self.sse) }
573 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
574 unsafe {Self { neon: vrndpq_f64(self.neon) }}
575 } else if #[cfg(feature="std")] {
576 let base: [f64; 2] = cast(self);
577 cast(base.map(|val| val.ceil()))
578 } else {
579 let base: [f64; 2] = cast(self);
580 let rounded: [f64; 2] = cast(self.round());
581 cast([
582 if base[0] > rounded[0] { rounded[0] + 1.0 } else { rounded[0] },
583 if base[1] > rounded[1] { rounded[1] + 1.0 } else { rounded[1] },
584 ])
585 }
586 }
587 }
588
589 #[inline]
593 #[must_use]
594 pub fn fast_max(self, rhs: Self) -> Self {
595 pick! {
596 if #[cfg(target_feature="sse2")] {
597 Self { sse: max_m128d(self.sse, rhs.sse) }
598 } else if #[cfg(target_feature="simd128")] {
599 Self {
600 simd: f64x2_pmax(self.simd, rhs.simd),
601 }
602 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
603 unsafe {Self { neon: vmaxq_f64(self.neon, rhs.neon) }}
604 } else {
605 Self { arr: [
606 if self.arr[0] < rhs.arr[0] { rhs.arr[0] } else { self.arr[0] },
607 if self.arr[1] < rhs.arr[1] { rhs.arr[1] } else { self.arr[1] },
608 ]}
609 }
610 }
611 }
612
613 #[inline]
617 #[must_use]
618 pub fn max(self, rhs: Self) -> Self {
619 pick! {
620 if #[cfg(target_feature="sse2")] {
621 rhs.is_nan().blend(self, Self { sse: max_m128d(self.sse, rhs.sse) })
625 } else if #[cfg(target_feature="simd128")] {
626 Self {
633 simd: v128_bitselect(
634 rhs.simd,
635 f64x2_pmax(self.simd, rhs.simd),
636 f64x2_ne(self.simd, self.simd), )
638 }
639 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
640 unsafe {Self { neon: vmaxnmq_f64(self.neon, rhs.neon) }}
641 } else {
642 Self { arr: [
643 self.arr[0].max(rhs.arr[0]),
644 self.arr[1].max(rhs.arr[1]),
645 ]}
646 }
647 }
648 }
649
650 #[inline]
654 #[must_use]
655 pub fn fast_min(self, rhs: Self) -> Self {
656 pick! {
657 if #[cfg(target_feature="sse2")] {
658 Self { sse: min_m128d(self.sse, rhs.sse) }
659 } else if #[cfg(target_feature="simd128")] {
660 Self {
661 simd: f64x2_pmin(self.simd, rhs.simd),
662 }
663 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
664 unsafe {Self { neon: vminq_f64(self.neon, rhs.neon) }}
665 } else {
666 Self { arr: [
667 if self.arr[0] < rhs.arr[0] { self.arr[0] } else { rhs.arr[0] },
668 if self.arr[1] < rhs.arr[1] { self.arr[1] } else { rhs.arr[1] },
669 ]}
670 }
671 }
672 }
673
674 #[inline]
678 #[must_use]
679 pub fn min(self, rhs: Self) -> Self {
680 pick! {
681 if #[cfg(target_feature="sse2")] {
682 rhs.is_nan().blend(self, Self { sse: min_m128d(self.sse, rhs.sse) })
686 } else if #[cfg(target_feature="simd128")] {
687 Self {
694 simd: v128_bitselect(
695 rhs.simd,
696 f64x2_pmin(self.simd, rhs.simd),
697 f64x2_ne(self.simd, self.simd), )
699 }
700 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
701 unsafe {Self { neon: vminnmq_f64(self.neon, rhs.neon) }}
702 } else {
703 Self { arr: [
704 self.arr[0].min(rhs.arr[0]),
705 self.arr[1].min(rhs.arr[1]),
706 ]}
707 }
708 }
709 }
710
711 #[inline]
716 #[must_use]
717 pub fn clamp(self, min: Self, max: Self) -> Self {
718 let is_nan = self.is_nan() | min.is_nan() | max.is_nan();
719 let clamped = self.fast_min(max).fast_max(min);
720 is_nan.blend(Self::splat(f64::NAN), clamped)
721 }
722
723 #[inline]
730 #[must_use]
731 pub fn fast_clamp(self, min: Self, max: Self) -> Self {
732 pick! {
733 if #[cfg(target_feature="sse2")] {
734 Self { sse: min_m128d(max.sse, max_m128d(min.sse, self.sse)) }
737 } else if #[cfg(target_feature="simd128")] {
738 Self { simd: f64x2_min(f64x2_max(self.simd, min.simd), max.simd) }
739 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
740 unsafe { Self { neon: vminq_f64(vmaxq_f64(self.neon, min.neon), max.neon) } }
741 } else {
742 let mut result = self;
745 result = result.simd_lt(min).blend(min, self);
746 result = result.simd_gt(max).blend(max, self);
747 result
748 }
749 }
750 }
751
752 #[inline]
753 #[must_use]
754 pub fn midpoint(self, other: Self) -> Self {
755 (self + other) * 0.5
756 }
757
758 #[inline]
759 #[must_use]
760 pub fn is_nan(self) -> Self {
761 pick! {
762 if #[cfg(target_feature="sse2")] {
763 Self { sse: cmp_unord_mask_m128d(self.sse, self.sse) }
764 } else if #[cfg(target_feature="simd128")] {
765 Self { simd: f64x2_ne(self.simd, self.simd) }
766 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
767 unsafe {Self { neon: vreinterpretq_f64_u64(vceqq_f64(self.neon, self.neon)) }.not() }
768 } else {
769 Self { arr: [
770 if self.arr[0].is_nan() { f64::from_bits(u64::MAX) } else { 0.0 },
771 if self.arr[1].is_nan() { f64::from_bits(u64::MAX) } else { 0.0 },
772 ]}
773 }
774 }
775 }
776 #[inline]
777 #[must_use]
778 pub fn is_finite(self) -> Self {
779 let shifted_exp_mask = u64x2::from(0xFFE0000000000000);
780 let u: u64x2 = cast(self);
781 let shift_u = u << 1_u64;
782 let out = !(shift_u & shifted_exp_mask).simd_eq(shifted_exp_mask);
783 cast(out)
784 }
785 #[inline]
786 #[must_use]
787 pub fn is_inf(self) -> Self {
788 let shifted_inf = u64x2::from(0xFFE0000000000000);
789 let u: u64x2 = cast(self);
790 let shift_u = u << 1_u64;
791 let out = (shift_u).simd_eq(shifted_inf);
792 cast(out)
793 }
794
795 #[inline]
796 #[must_use]
797 pub fn round(self) -> Self {
798 pick! {
799 if #[cfg(target_feature="sse4.1")] {
800 Self { sse: round_m128d::<{round_op!(Nearest)}>(self.sse) }
801 } else if #[cfg(target_feature="simd128")] {
802 Self { simd: f64x2_nearest(self.simd) }
803 } else {
804 const SIGN_MASK: f64x2 = f64x2::splat(-0.0);
805 const MAGIC_VALUE: f64x2 = f64x2::splat(f64::from_bits(0x43300000_00000000));
806
807 let self_sign = self & SIGN_MASK;
808 let magic_value = MAGIC_VALUE | self_sign;
809 let result = self + magic_value - magic_value;
810
811 let bounds_mask = self.abs().simd_le(MAGIC_VALUE);
812 bounds_mask.abs().blend(result, self)
813 }
814 }
815 }
816
817 #[inline]
818 #[must_use]
819 pub fn fast_round_int(self) -> i64x2 {
820 pick! {
821 if #[cfg(all(target_feature="avx512dq", target_feature="avx512vl"))] {
822 #[cfg(target_arch = "x86")]
823 use core::arch::x86::_mm_cvtpd_epi64;
824 #[cfg(target_arch = "x86_64")]
825 use core::arch::x86_64::_mm_cvtpd_epi64;
826
827 cast(m128i(unsafe { _mm_cvtpd_epi64(self.sse.0) }))
829 } else {
830 self.round_int()
831 }
832 }
833 }
834
835 #[inline]
836 #[must_use]
837 pub fn round_int(self) -> i64x2 {
838 pick! {
839 if #[cfg(all(target_feature="avx512dq", target_feature="avx512vl"))] {
840 #[cfg(target_arch = "x86")]
841 use core::arch::x86::_mm_cvtpd_epi64;
842 #[cfg(target_arch = "x86_64")]
843 use core::arch::x86_64::_mm_cvtpd_epi64;
844
845 let non_nan_mask = self.simd_eq(self);
847 let non_nan = self & non_nan_mask;
848 let flip_to_max: i64x2 = cast(self.simd_ge(Self::splat(9223372036854775808.0)));
849
850 let cast: i64x2 = cast(m128i(unsafe { _mm_cvtpd_epi64(non_nan.sse.0) }));
852 flip_to_max ^ cast
853 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
854 cast(Self { neon: unsafe { vreinterpretq_f64_s64(vcvtnq_s64_f64(self.neon)) } })
855 } else {
856 let rounded: [f64; 2] = cast(self.round());
857 cast([rounded[0] as i64, rounded[1] as i64])
858 }
859 }
860 }
861
862 #[inline]
863 #[must_use]
864 pub fn trunc(self) -> Self {
865 pick! {
866 if #[cfg(target_feature="sse4.1")] {
867 Self { sse: round_m128d::<{round_op!(Zero)}>(self.sse) }
868 } else if #[cfg(target_feature="simd128")] {
869 Self { simd: f64x2_trunc(self.simd) }
870 } else {
871 let array: [f64; 2] = cast(self);
876 let result: Self = cast([
877 array[0] as i64 as f64,
878 array[1] as i64 as f64,
879 ]);
880
881 const BOUNDS_LIMIT: i64 = 18e15_f64.to_bits().cast_signed();
884 let bounds_mask: Self = cast(cast::<f64x2, i64x2>(self.abs()).simd_lt(i64x2::splat(BOUNDS_LIMIT)));
885
886 bounds_mask.abs().blend(result, self)
888 }
889 }
890 }
891
892 #[inline]
896 #[must_use]
897 pub fn fast_trunc_int(self) -> i64x2 {
898 pick! {
899 if #[cfg(all(target_feature="avx512dq", target_feature="avx512vl"))] {
900 #[cfg(target_arch = "x86")]
901 use core::arch::x86::_mm_cvttpd_epi64;
902 #[cfg(target_arch = "x86_64")]
903 use core::arch::x86_64::_mm_cvttpd_epi64;
904
905 cast(m128i(unsafe { _mm_cvttpd_epi64(self.sse.0) }))
907 } else {
908 self.trunc_int()
909 }
910 }
911 }
912
913 #[inline]
917 #[must_use]
918 pub fn trunc_int(self) -> i64x2 {
919 pick! {
920 if #[cfg(all(target_feature="avx512dq", target_feature="avx512vl"))] {
921 #[cfg(target_arch = "x86")]
922 use core::arch::x86::_mm_cvttpd_epi64;
923 #[cfg(target_arch = "x86_64")]
924 use core::arch::x86_64::_mm_cvttpd_epi64;
925
926 let non_nan_mask = self.simd_eq(self);
928 let non_nan = self & non_nan_mask;
929 let flip_to_max: i64x2 = cast(self.simd_ge(Self::splat(9223372036854775808.0)));
930
931 let cast: i64x2 = cast(m128i(unsafe { _mm_cvttpd_epi64(non_nan.sse.0) }));
933 flip_to_max ^ cast
934 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
935 cast(Self { neon: unsafe { vreinterpretq_f64_s64(vcvtq_s64_f64(self.neon)) } })
936 } else {
937 let n: [f64;2] = cast(self);
939 cast([n[0] as i64, n[1] as i64])
940 }
941 }
942 }
943
944 #[inline]
945 #[must_use]
946 pub fn fract(self) -> Self {
947 self - self.trunc()
948 }
949
950 #[inline]
975 #[must_use]
976 pub fn mul_add(self, m: Self, a: Self) -> Self {
977 pick! {
978 if #[cfg(all(target_feature="fma"))] {
979 Self { sse: fused_mul_add_m128d(self.sse, m.sse, a.sse) }
980 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
981 unsafe { Self { neon: vfmaq_f64(a.neon, self.neon, m.neon) } }
982 } else {
983 (self * m) + a
984 }
985 }
986 }
987
988 #[inline]
1014 #[must_use]
1015 pub fn mul_sub(self, m: Self, s: Self) -> Self {
1016 pick! {
1017 if #[cfg(all(target_feature="fma"))] {
1018 Self { sse: fused_mul_sub_m128d(self.sse, m.sse, s.sse) }
1019 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1020 unsafe { Self { neon: vfmaq_f64(vnegq_f64(s.neon), self.neon, m.neon) } }
1021 } else {
1022 (self * m) - s
1023 }
1024 }
1025 }
1026
1027 #[inline]
1052 #[must_use]
1053 pub fn mul_neg_add(self, m: Self, a: Self) -> Self {
1054 pick! {
1055 if #[cfg(all(target_feature="fma"))] {
1056 Self { sse: fused_mul_neg_add_m128d(self.sse, m.sse, a.sse) }
1057 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1058 unsafe { Self { neon: vfmsq_f64(a.neon, self.neon, m.neon) } }
1059 } else {
1060 a - (self * m)
1061 }
1062 }
1063 }
1064
1065 #[inline]
1091 #[must_use]
1092 pub fn mul_neg_sub(self, m: Self, s: Self) -> Self {
1093 pick! {
1094 if #[cfg(all(target_feature="fma"))] {
1095 Self { sse: fused_mul_neg_sub_m128d(self.sse, m.sse, s.sse) }
1096 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1097 unsafe { Self { neon: vnegq_f64(vfmaq_f64(s.neon, self.neon, m.neon)) } }
1098 } else {
1099 -(self * m) - s
1100 }
1101 }
1102 }
1103
1104 #[inline]
1105 #[must_use]
1106 pub fn div_euclid(self, rhs: Self) -> Self {
1107 let q = (self / rhs).trunc();
1108 (self % rhs)
1109 .simd_lt(Self::ZERO)
1110 .blend(rhs.simd_gt(Self::ZERO).blend(q - Self::ONE, q + Self::ONE), q)
1111 }
1112
1113 #[inline]
1114 #[must_use]
1115 pub fn rem_euclid(self, rhs: Self) -> Self {
1116 let r = self % rhs;
1117 r.simd_lt(Self::ZERO).blend(r + rhs.abs(), r)
1118 }
1119
1120 #[inline]
1121 #[must_use]
1122 pub fn flip_signs(self, signs: Self) -> Self {
1123 self ^ (signs & Self::from(-0.0))
1124 }
1125
1126 #[inline]
1127 #[must_use]
1128 pub fn copysign(self, sign: Self) -> Self {
1129 let magnitude_mask = Self::from(f64::from_bits(u64::MAX >> 1));
1130 (self & magnitude_mask) | (sign & Self::from(-0.0))
1131 }
1132
1133 #[inline]
1134 pub fn asin_acos(self) -> (Self, Self) {
1135 const_f64_as_f64x2!(R4asin, 2.967721961301243206100E-3);
1138 const_f64_as_f64x2!(R3asin, -5.634242780008963776856E-1);
1139 const_f64_as_f64x2!(R2asin, 6.968710824104713396794E0);
1140 const_f64_as_f64x2!(R1asin, -2.556901049652824852289E1);
1141 const_f64_as_f64x2!(R0asin, 2.853665548261061424989E1);
1142
1143 const_f64_as_f64x2!(S3asin, -2.194779531642920639778E1);
1144 const_f64_as_f64x2!(S2asin, 1.470656354026814941758E2);
1145 const_f64_as_f64x2!(S1asin, -3.838770957603691357202E2);
1146 const_f64_as_f64x2!(S0asin, 3.424398657913078477438E2);
1147
1148 const_f64_as_f64x2!(P5asin, 4.253011369004428248960E-3);
1149 const_f64_as_f64x2!(P4asin, -6.019598008014123785661E-1);
1150 const_f64_as_f64x2!(P3asin, 5.444622390564711410273E0);
1151 const_f64_as_f64x2!(P2asin, -1.626247967210700244449E1);
1152 const_f64_as_f64x2!(P1asin, 1.956261983317594739197E1);
1153 const_f64_as_f64x2!(P0asin, -8.198089802484824371615E0);
1154
1155 const_f64_as_f64x2!(Q4asin, -1.474091372988853791896E1);
1156 const_f64_as_f64x2!(Q3asin, 7.049610280856842141659E1);
1157 const_f64_as_f64x2!(Q2asin, -1.471791292232726029859E2);
1158 const_f64_as_f64x2!(Q1asin, 1.395105614657485689735E2);
1159 const_f64_as_f64x2!(Q0asin, -4.918853881490881290097E1);
1160
1161 let xa = self.abs();
1162
1163 let big = xa.simd_ge(f64x2::splat(0.625));
1164
1165 let x1 = big.blend(f64x2::splat(1.0) - xa, xa * xa);
1166
1167 let x2 = x1 * x1;
1168 let x3 = x2 * x1;
1169 let x4 = x2 * x2;
1170 let x5 = x4 * x1;
1171
1172 let do_big = big.any();
1173 let do_small = !big.all();
1174
1175 let mut rx = f64x2::default();
1176 let mut sx = f64x2::default();
1177 let mut px = f64x2::default();
1178 let mut qx = f64x2::default();
1179
1180 if do_big {
1181 rx = x3.mul_add(R3asin, x2 * R2asin)
1182 + x4.mul_add(R4asin, x1.mul_add(R1asin, R0asin));
1183 sx =
1184 x3.mul_add(S3asin, x4) + x2.mul_add(S2asin, x1.mul_add(S1asin, S0asin));
1185 }
1186 if do_small {
1187 px = x3.mul_add(P3asin, P0asin)
1188 + x4.mul_add(P4asin, x1 * P1asin)
1189 + x5.mul_add(P5asin, x2 * P2asin);
1190 qx = x4.mul_add(Q4asin, x5)
1191 + x3.mul_add(Q3asin, x1 * Q1asin)
1192 + x2.mul_add(Q2asin, Q0asin);
1193 };
1194
1195 let vx = big.blend(rx, px);
1196 let wx = big.blend(sx, qx);
1197
1198 let y1 = vx / wx * x1;
1199
1200 let mut z1 = f64x2::default();
1201 let mut z2 = f64x2::default();
1202 if do_big {
1203 let xb = (x1 + x1).sqrt();
1204 z1 = xb.mul_add(y1, xb);
1205 }
1206
1207 if do_small {
1208 z2 = xa.mul_add(y1, xa);
1209 }
1210
1211 let z3 = f64x2::FRAC_PI_2 - z1;
1213 let asin = big.blend(z3, z2);
1214 let asin = asin.flip_signs(self);
1215
1216 let z3 = self.simd_lt(f64x2::ZERO).blend(f64x2::PI - z1, z1);
1218 let z4 = f64x2::FRAC_PI_2 - z2.flip_signs(self);
1219 let acos = big.blend(z3, z4);
1220
1221 (asin, acos)
1222 }
1223
1224 #[inline]
1225 pub fn acos(self) -> Self {
1226 const_f64_as_f64x2!(R4asin, 2.967721961301243206100E-3);
1229 const_f64_as_f64x2!(R3asin, -5.634242780008963776856E-1);
1230 const_f64_as_f64x2!(R2asin, 6.968710824104713396794E0);
1231 const_f64_as_f64x2!(R1asin, -2.556901049652824852289E1);
1232 const_f64_as_f64x2!(R0asin, 2.853665548261061424989E1);
1233
1234 const_f64_as_f64x2!(S3asin, -2.194779531642920639778E1);
1235 const_f64_as_f64x2!(S2asin, 1.470656354026814941758E2);
1236 const_f64_as_f64x2!(S1asin, -3.838770957603691357202E2);
1237 const_f64_as_f64x2!(S0asin, 3.424398657913078477438E2);
1238
1239 const_f64_as_f64x2!(P5asin, 4.253011369004428248960E-3);
1240 const_f64_as_f64x2!(P4asin, -6.019598008014123785661E-1);
1241 const_f64_as_f64x2!(P3asin, 5.444622390564711410273E0);
1242 const_f64_as_f64x2!(P2asin, -1.626247967210700244449E1);
1243 const_f64_as_f64x2!(P1asin, 1.956261983317594739197E1);
1244 const_f64_as_f64x2!(P0asin, -8.198089802484824371615E0);
1245
1246 const_f64_as_f64x2!(Q4asin, -1.474091372988853791896E1);
1247 const_f64_as_f64x2!(Q3asin, 7.049610280856842141659E1);
1248 const_f64_as_f64x2!(Q2asin, -1.471791292232726029859E2);
1249 const_f64_as_f64x2!(Q1asin, 1.395105614657485689735E2);
1250 const_f64_as_f64x2!(Q0asin, -4.918853881490881290097E1);
1251
1252 let xa = self.abs();
1253
1254 let big = xa.simd_ge(f64x2::splat(0.625));
1255
1256 let x1 = big.blend(f64x2::splat(1.0) - xa, xa * xa);
1257
1258 let x2 = x1 * x1;
1259 let x3 = x2 * x1;
1260 let x4 = x2 * x2;
1261 let x5 = x4 * x1;
1262
1263 let do_big = big.any();
1264 let do_small = !big.all();
1265
1266 let mut rx = f64x2::default();
1267 let mut sx = f64x2::default();
1268 let mut px = f64x2::default();
1269 let mut qx = f64x2::default();
1270
1271 if do_big {
1272 rx = x3.mul_add(R3asin, x2 * R2asin)
1273 + x4.mul_add(R4asin, x1.mul_add(R1asin, R0asin));
1274 sx =
1275 x3.mul_add(S3asin, x4) + x2.mul_add(S2asin, x1.mul_add(S1asin, S0asin));
1276 }
1277 if do_small {
1278 px = x3.mul_add(P3asin, P0asin)
1279 + x4.mul_add(P4asin, x1 * P1asin)
1280 + x5.mul_add(P5asin, x2 * P2asin);
1281 qx = x4.mul_add(Q4asin, x5)
1282 + x3.mul_add(Q3asin, x1 * Q1asin)
1283 + x2.mul_add(Q2asin, Q0asin);
1284 };
1285
1286 let vx = big.blend(rx, px);
1287 let wx = big.blend(sx, qx);
1288
1289 let y1 = vx / wx * x1;
1290
1291 let mut z1 = f64x2::default();
1292 let mut z2 = f64x2::default();
1293 if do_big {
1294 let xb = (x1 + x1).sqrt();
1295 z1 = xb.mul_add(y1, xb);
1296 }
1297
1298 if do_small {
1299 z2 = xa.mul_add(y1, xa);
1300 }
1301
1302 let z3 = self.simd_lt(f64x2::ZERO).blend(f64x2::PI - z1, z1);
1304 let z4 = f64x2::FRAC_PI_2 - z2.flip_signs(self);
1305 let acos = big.blend(z3, z4);
1306
1307 acos
1308 }
1309
1310 #[inline]
1311 pub fn asin(self) -> Self {
1312 const_f64_as_f64x2!(R4asin, 2.967721961301243206100E-3);
1315 const_f64_as_f64x2!(R3asin, -5.634242780008963776856E-1);
1316 const_f64_as_f64x2!(R2asin, 6.968710824104713396794E0);
1317 const_f64_as_f64x2!(R1asin, -2.556901049652824852289E1);
1318 const_f64_as_f64x2!(R0asin, 2.853665548261061424989E1);
1319
1320 const_f64_as_f64x2!(S3asin, -2.194779531642920639778E1);
1321 const_f64_as_f64x2!(S2asin, 1.470656354026814941758E2);
1322 const_f64_as_f64x2!(S1asin, -3.838770957603691357202E2);
1323 const_f64_as_f64x2!(S0asin, 3.424398657913078477438E2);
1324
1325 const_f64_as_f64x2!(P5asin, 4.253011369004428248960E-3);
1326 const_f64_as_f64x2!(P4asin, -6.019598008014123785661E-1);
1327 const_f64_as_f64x2!(P3asin, 5.444622390564711410273E0);
1328 const_f64_as_f64x2!(P2asin, -1.626247967210700244449E1);
1329 const_f64_as_f64x2!(P1asin, 1.956261983317594739197E1);
1330 const_f64_as_f64x2!(P0asin, -8.198089802484824371615E0);
1331
1332 const_f64_as_f64x2!(Q4asin, -1.474091372988853791896E1);
1333 const_f64_as_f64x2!(Q3asin, 7.049610280856842141659E1);
1334 const_f64_as_f64x2!(Q2asin, -1.471791292232726029859E2);
1335 const_f64_as_f64x2!(Q1asin, 1.395105614657485689735E2);
1336 const_f64_as_f64x2!(Q0asin, -4.918853881490881290097E1);
1337
1338 let xa = self.abs();
1339
1340 let big = xa.simd_ge(f64x2::splat(0.625));
1341
1342 let x1 = big.blend(f64x2::splat(1.0) - xa, xa * xa);
1343
1344 let x2 = x1 * x1;
1345 let x3 = x2 * x1;
1346 let x4 = x2 * x2;
1347 let x5 = x4 * x1;
1348
1349 let do_big = big.any();
1350 let do_small = !big.all();
1351
1352 let mut rx = f64x2::default();
1353 let mut sx = f64x2::default();
1354 let mut px = f64x2::default();
1355 let mut qx = f64x2::default();
1356
1357 if do_big {
1358 rx = x3.mul_add(R3asin, x2 * R2asin)
1359 + x4.mul_add(R4asin, x1.mul_add(R1asin, R0asin));
1360 sx =
1361 x3.mul_add(S3asin, x4) + x2.mul_add(S2asin, x1.mul_add(S1asin, S0asin));
1362 }
1363 if do_small {
1364 px = x3.mul_add(P3asin, P0asin)
1365 + x4.mul_add(P4asin, x1 * P1asin)
1366 + x5.mul_add(P5asin, x2 * P2asin);
1367 qx = x4.mul_add(Q4asin, x5)
1368 + x3.mul_add(Q3asin, x1 * Q1asin)
1369 + x2.mul_add(Q2asin, Q0asin);
1370 };
1371
1372 let vx = big.blend(rx, px);
1373 let wx = big.blend(sx, qx);
1374
1375 let y1 = vx / wx * x1;
1376
1377 let mut z1 = f64x2::default();
1378 let mut z2 = f64x2::default();
1379 if do_big {
1380 let xb = (x1 + x1).sqrt();
1381 z1 = xb.mul_add(y1, xb);
1382 }
1383
1384 if do_small {
1385 z2 = xa.mul_add(y1, xa);
1386 }
1387
1388 let z3 = f64x2::FRAC_PI_2 - z1;
1390 let asin = big.blend(z3, z2);
1391 let asin = asin.flip_signs(self);
1392
1393 asin
1394 }
1395
1396 #[inline]
1397 pub fn atan(self) -> Self {
1398 const_f64_as_f64x2!(MORE_BITS, 6.123233995736765886130E-17);
1401 const_f64_as_f64x2!(MORE_BITS_O2, 6.123233995736765886130E-17 * 0.5);
1402 const_f64_as_f64x2!(T3PO8, core::f64::consts::SQRT_2 + 1.0);
1403
1404 const_f64_as_f64x2!(P4atan, -8.750608600031904122785E-1);
1405 const_f64_as_f64x2!(P3atan, -1.615753718733365076637E1);
1406 const_f64_as_f64x2!(P2atan, -7.500855792314704667340E1);
1407 const_f64_as_f64x2!(P1atan, -1.228866684490136173410E2);
1408 const_f64_as_f64x2!(P0atan, -6.485021904942025371773E1);
1409
1410 const_f64_as_f64x2!(Q4atan, 2.485846490142306297962E1);
1411 const_f64_as_f64x2!(Q3atan, 1.650270098316988542046E2);
1412 const_f64_as_f64x2!(Q2atan, 4.328810604912902668951E2);
1413 const_f64_as_f64x2!(Q1atan, 4.853903996359136964868E2);
1414 const_f64_as_f64x2!(Q0atan, 1.945506571482613964425E2);
1415
1416 let t = self.abs();
1417
1418 let notbig = t.simd_le(T3PO8);
1422 let notsmal = t.simd_ge(Self::splat(0.66));
1423
1424 let mut s = notbig.blend(Self::FRAC_PI_4, Self::FRAC_PI_2);
1425 s = notsmal & s;
1426 let mut fac = notbig.blend(MORE_BITS_O2, MORE_BITS);
1427 fac = notsmal & fac;
1428
1429 let mut a = notbig & t;
1433 a = notsmal.blend(a - Self::ONE, a);
1434 let mut b = notbig & Self::ONE;
1435 b = notsmal.blend(b + t, b);
1436 let z = a / b;
1437
1438 let zz = z * z;
1439
1440 let px = polynomial_4!(zz, P0atan, P1atan, P2atan, P3atan, P4atan);
1441 let qx = polynomial_5n!(zz, Q0atan, Q1atan, Q2atan, Q3atan, Q4atan);
1442
1443 let mut re = (px / qx).mul_add(z * zz, z);
1444 re += s + fac;
1445
1446 re = (self.is_sign_negative()).blend(-re, re);
1448
1449 re
1450 }
1451
1452 #[inline]
1453 pub fn atan2(self, x: Self) -> Self {
1454 const_f64_as_f64x2!(MORE_BITS, 6.123233995736765886130E-17);
1457 const_f64_as_f64x2!(MORE_BITS_O2, 6.123233995736765886130E-17 * 0.5);
1458 const_f64_as_f64x2!(T3PO8, core::f64::consts::SQRT_2 + 1.0);
1459
1460 const_f64_as_f64x2!(P4atan, -8.750608600031904122785E-1);
1461 const_f64_as_f64x2!(P3atan, -1.615753718733365076637E1);
1462 const_f64_as_f64x2!(P2atan, -7.500855792314704667340E1);
1463 const_f64_as_f64x2!(P1atan, -1.228866684490136173410E2);
1464 const_f64_as_f64x2!(P0atan, -6.485021904942025371773E1);
1465
1466 const_f64_as_f64x2!(Q4atan, 2.485846490142306297962E1);
1467 const_f64_as_f64x2!(Q3atan, 1.650270098316988542046E2);
1468 const_f64_as_f64x2!(Q2atan, 4.328810604912902668951E2);
1469 const_f64_as_f64x2!(Q1atan, 4.853903996359136964868E2);
1470 const_f64_as_f64x2!(Q0atan, 1.945506571482613964425E2);
1471
1472 let y = self;
1473
1474 let x1 = x.abs();
1476 let y1 = y.abs();
1477 let swapxy = y1.simd_gt(x1);
1478 let mut x2 = swapxy.blend(y1, x1);
1480 let mut y2 = swapxy.blend(x1, y1);
1481
1482 let both_infinite = x.is_inf() & y.is_inf();
1484 if both_infinite.any() {
1485 let minus_one = -Self::ONE;
1486 x2 = both_infinite.blend(x2 & minus_one, x2);
1487 y2 = both_infinite.blend(y2 & minus_one, y2);
1488 }
1489
1490 let t = y2 / x2;
1492
1493 let notbig = t.simd_le(T3PO8);
1497 let notsmal = t.simd_ge(Self::splat(0.66));
1498
1499 let mut s = notbig.blend(Self::FRAC_PI_4, Self::FRAC_PI_2);
1500 s = notsmal & s;
1501 let mut fac = notbig.blend(MORE_BITS_O2, MORE_BITS);
1502 fac = notsmal & fac;
1503
1504 let mut a = notbig & t;
1508 a = notsmal.blend(a - Self::ONE, a);
1509 let mut b = notbig & Self::ONE;
1510 b = notsmal.blend(b + t, b);
1511 let z = a / b;
1512
1513 let zz = z * z;
1514
1515 let px = polynomial_4!(zz, P0atan, P1atan, P2atan, P3atan, P4atan);
1516 let qx = polynomial_5n!(zz, Q0atan, Q1atan, Q2atan, Q3atan, Q4atan);
1517
1518 let mut re = (px / qx).mul_add(z * zz, z);
1519 re += s + fac;
1520
1521 re = swapxy.blend(Self::FRAC_PI_2 - re, re);
1523 re = ((x | y).simd_eq(Self::ZERO)).blend(Self::ZERO, re);
1524 re = (x.is_sign_negative()).blend(Self::PI - re, re);
1525
1526 re = (y.is_sign_negative()).blend(-re, re);
1528
1529 re
1530 }
1531
1532 #[inline]
1533 #[must_use]
1534 pub fn sin_cos(self) -> (Self, Self) {
1535 const_f64_as_f64x2!(P0sin, -1.66666666666666307295E-1);
1539 const_f64_as_f64x2!(P1sin, 8.33333333332211858878E-3);
1540 const_f64_as_f64x2!(P2sin, -1.98412698295895385996E-4);
1541 const_f64_as_f64x2!(P3sin, 2.75573136213857245213E-6);
1542 const_f64_as_f64x2!(P4sin, -2.50507477628578072866E-8);
1543 const_f64_as_f64x2!(P5sin, 1.58962301576546568060E-10);
1544
1545 const_f64_as_f64x2!(P0cos, 4.16666666666665929218E-2);
1546 const_f64_as_f64x2!(P1cos, -1.38888888888730564116E-3);
1547 const_f64_as_f64x2!(P2cos, 2.48015872888517045348E-5);
1548 const_f64_as_f64x2!(P3cos, -2.75573141792967388112E-7);
1549 const_f64_as_f64x2!(P4cos, 2.08757008419747316778E-9);
1550 const_f64_as_f64x2!(P5cos, -1.13585365213876817300E-11);
1551
1552 const_f64_as_f64x2!(DP1, 7.853981554508209228515625E-1 * 2.);
1553 const_f64_as_f64x2!(DP2, 7.94662735614792836714E-9 * 2.);
1554 const_f64_as_f64x2!(DP3, 3.06161699786838294307E-17 * 2.);
1555
1556 const_f64_as_f64x2!(TWO_OVER_PI, 2.0 / core::f64::consts::PI);
1557
1558 let xa = self.abs();
1559
1560 let y = (xa * TWO_OVER_PI).round();
1561 let q = y.round_int();
1562
1563 let x = y.mul_neg_add(DP3, y.mul_neg_add(DP2, y.mul_neg_add(DP1, xa)));
1564
1565 let x2 = x * x;
1566 let mut s = polynomial_5!(x2, P0sin, P1sin, P2sin, P3sin, P4sin, P5sin);
1567 let mut c = polynomial_5!(x2, P0cos, P1cos, P2cos, P3cos, P4cos, P5cos);
1568 s = (x * x2).mul_add(s, x);
1569 c =
1570 (x2 * x2).mul_add(c, x2.mul_neg_add(f64x2::from(0.5), f64x2::from(1.0)));
1571
1572 let swap = !((q & i64x2::from(1)).simd_eq(i64x2::from(0)));
1573
1574 let mut overflow: f64x2 = cast(q.simd_gt(i64x2::from(0x80000000000000)));
1575 overflow &= xa.is_finite();
1576 s = overflow.blend(f64x2::from(0.0), s);
1577 c = overflow.blend(f64x2::from(1.0), c);
1578
1579 let mut sin1 = cast::<_, f64x2>(swap).blend(c, s);
1581 let sign_sin: i64x2 = (q << 62) ^ cast::<_, i64x2>(self);
1582 sin1 = sin1.flip_signs(cast(sign_sin));
1583
1584 let mut cos1 = cast::<_, f64x2>(swap).blend(s, c);
1586 let sign_cos: i64x2 = ((q + i64x2::from(1)) & i64x2::from(2)) << 62;
1587 cos1 ^= cast::<_, f64x2>(sign_cos);
1588
1589 let finite = self.is_finite();
1591 let nan = Self::splat(f64::NAN);
1592 let sin_final = finite.blend(sin1, nan);
1593 let cos_final = finite.blend(cos1, nan);
1594
1595 (sin_final, cos_final)
1596 }
1597 #[inline]
1598 #[must_use]
1599 pub fn sin(self) -> Self {
1600 let (s, _) = self.sin_cos();
1601 s
1602 }
1603 #[inline]
1604 #[must_use]
1605 pub fn cos(self) -> Self {
1606 let (_, c) = self.sin_cos();
1607 c
1608 }
1609 #[inline]
1610 #[must_use]
1611 pub fn tan(self) -> Self {
1612 let (s, c) = self.sin_cos();
1613 s / c
1614 }
1615
1616 #[inline]
1618 #[must_use]
1619 pub fn sinh(self) -> Self {
1620 const_f64_as_f64x2!(P0, 1.0);
1621 const_f64_as_f64x2!(P1, 1.0 / 6.0);
1622 const_f64_as_f64x2!(P2, 1.0 / 120.0);
1623 const_f64_as_f64x2!(P3, 1.0 / 5040.0);
1624 const_f64_as_f64x2!(P4, 1.0 / 362880.0);
1625 const_f64_as_f64x2!(P5, 1.0 / 39916800.0);
1626 const_f64_as_f64x2!(P6, 1.0 / 6227020800.0);
1627 let a = self.abs();
1628 let small = a.simd_lt(f64x2::from(0.5));
1630 let t = a * a;
1631 let poly = a * polynomial_6!(t, P0, P1, P2, P3, P4, P5, P6);
1632 let exp_based = {
1633 let e = a.exp();
1634 (e - Self::ONE / e) * Self::HALF
1635 };
1636 let result = small.blend(poly, exp_based);
1637 result.flip_signs(self)
1638 }
1639
1640 #[inline]
1642 #[must_use]
1643 pub fn cosh(self) -> Self {
1644 const_f64_as_f64x2!(P0, 1.0);
1645 const_f64_as_f64x2!(P1, 1.0 / 2.0);
1646 const_f64_as_f64x2!(P2, 1.0 / 24.0);
1647 const_f64_as_f64x2!(P3, 1.0 / 720.0);
1648 const_f64_as_f64x2!(P4, 1.0 / 40320.0);
1649 const_f64_as_f64x2!(P5, 1.0 / 3628800.0);
1650 const_f64_as_f64x2!(P6, 1.0 / 479001600.0);
1651 const_f64_as_f64x2!(P7, 1.0 / 87178291200.0);
1652 let a = self.abs();
1653 let small = a.simd_lt(f64x2::from(0.5));
1655 let t = a * a;
1656 let poly = polynomial_7!(t, P0, P1, P2, P3, P4, P5, P6, P7);
1657 let exp_based = {
1658 let e = a.exp();
1659 (e + Self::ONE / e) * Self::HALF
1660 };
1661 small.blend(poly, exp_based)
1662 }
1663
1664 #[inline]
1666 #[must_use]
1667 pub fn tanh(self) -> Self {
1668 let a = self.abs();
1672 let large = a.simd_gt(f64x2::from(19.062));
1673 if large.all() {
1674 return Self::ONE.flip_signs(self);
1675 }
1676 let small = a.simd_lt(f64x2::from(5e-8));
1677 let exp_based = {
1678 let t = (Self::from(-2.0) * a).exp_m1();
1679 let pos = -t / (t + Self::from(2.0));
1680 pos.flip_signs(self)
1681 };
1682 let result = small.blend(self, exp_based);
1683 large.blend(Self::ONE.flip_signs(self), result)
1684 }
1685
1686 #[inline]
1688 #[must_use]
1689 pub fn cbrt(self) -> Self {
1690 let a = self.abs();
1691 let zero = a.simd_eq(Self::ZERO);
1692 if zero.all() {
1693 return self; }
1695 let inf = a.is_inf();
1696 let nan = self.is_nan();
1697
1698 const SUBN_SCALE: f64 = 1.8014398509481984e16;
1699 const SUBN_CBRT: f64 = 262144.0;
1700 let tiny = a.simd_lt(Self::from(f64::MIN_POSITIVE));
1701 let a = tiny.blend(a * Self::from(SUBN_SCALE), a);
1702
1703 let e = Self::exponent(a) + Self::ONE;
1704 let d = Self::fraction_2(a);
1705
1706 const_f64_as_f64x2!(C0, 2.2307275302496609725722);
1711 const_f64_as_f64x2!(C1, -3.85841935510444988821632);
1712 const_f64_as_f64x2!(C2, 6.03990368989458747961407);
1713 const_f64_as_f64x2!(C3, -5.73353060922947843636166);
1714 const_f64_as_f64x2!(C4, 2.96155103020039511818595);
1715 const_f64_as_f64x2!(C5, -0.640245898480692909870982);
1716 let mut x = polynomial_5!(d, C0, C1, C2, C3, C4, C5);
1717
1718 let x2 = x * x;
1720 let x4 = x2 * x2;
1721 x = x - d.mul_add(x4, -x) * Self::from(1.0 / 3.0);
1722
1723 let mut y = (d * x) * x;
1725 let yx = y * x;
1726 let t = Self::from(2.0 / 3.0);
1727 y = y - t * y * (yx - Self::ONE);
1728
1729 let three = Self::from(3.0);
1731 let two = Self::from(2.0);
1732 let neg = e.simd_lt(Self::ZERO);
1733 let e_adj = neg.blend(e - two, e);
1734 let k = (e_adj / three).trunc();
1735 let r = e - three * k;
1736 const_f64_as_f64x2!(CBRT2, 1.2599210498948732);
1737 const_f64_as_f64x2!(CBRT4, 1.5874010519681994);
1738 y = r.simd_eq(Self::ONE).blend(y * CBRT2, y);
1739 y = r.simd_eq(two).blend(y * CBRT4, y);
1740 y *= Self::vm_pow2n(k);
1741 y = tiny.blend(y / Self::from(SUBN_CBRT), y);
1742
1743 let result = y.flip_signs(self);
1744 let result = nan.blend(self, result);
1745 let result = zero.blend(self, result);
1746 let result = inf.blend(self, result);
1747 result
1748 }
1749
1750 #[inline]
1751 #[must_use]
1752 pub fn to_degrees(self) -> Self {
1753 const_f64_as_f64x2!(RAD_TO_DEG_RATIO, 180.0_f64 / core::f64::consts::PI);
1754 self * RAD_TO_DEG_RATIO
1755 }
1756 #[inline]
1757 #[must_use]
1758 pub fn to_radians(self) -> Self {
1759 const_f64_as_f64x2!(DEG_TO_RAD_RATIO, core::f64::consts::PI / 180.0_f64);
1760 self * DEG_TO_RAD_RATIO
1761 }
1762
1763 #[inline]
1764 #[must_use]
1765 pub fn recip(self) -> Self {
1766 Self::ONE / self
1769 }
1770
1771 #[inline]
1772 #[must_use]
1773 pub fn recip_sqrt(self) -> Self {
1774 Self::ONE / self.sqrt()
1777 }
1778
1779 #[inline]
1780 #[must_use]
1781 pub fn sqrt(self) -> Self {
1782 pick! {
1783 if #[cfg(target_feature="sse2")] {
1784 Self { sse: sqrt_m128d(self.sse) }
1785 } else if #[cfg(target_feature="simd128")] {
1786 Self { simd: f64x2_sqrt(self.simd) }
1787 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1788 unsafe {Self { neon: vsqrtq_f64(self.neon) }}
1789 } else if #[cfg(feature="std")] {
1790 Self { arr: [
1791 self.arr[0].sqrt(),
1792 self.arr[1].sqrt(),
1793 ]}
1794 } else {
1795 Self { arr: [
1796 software_sqrt(self.arr[0]),
1797 software_sqrt(self.arr[1]),
1798 ]}
1799 }
1800 }
1801 }
1802 #[inline]
1803 #[must_use]
1804 #[doc(alias("movemask", "move_mask"))]
1805 pub fn to_bitmask(self) -> u32 {
1806 pick! {
1807 if #[cfg(target_feature="sse2")] {
1808 move_mask_m128d(self.sse) as u32
1809 } else if #[cfg(target_feature="simd128")] {
1810 u64x2_bitmask(self.simd) as u32
1811 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1812 unsafe
1813 {
1814 let e = vreinterpretq_u64_f64(self.neon);
1815
1816 (vgetq_lane_u64(e,0) >> 63 | ((vgetq_lane_u64(e,1) >> 62) & 0x2)) as u32
1817 }
1818 } else {
1819 (((self.arr[0].to_bits() as i64) < 0) as u32) << 0 |
1820 (((self.arr[1].to_bits() as i64) < 0) as u32) << 1
1821 }
1822 }
1823 }
1824 #[inline]
1825 #[must_use]
1826 pub fn any(self) -> bool {
1827 pick! {
1828 if #[cfg(target_feature="simd128")] {
1829 v128_any_true(self.simd)
1830 } else {
1831 self.to_bitmask() != 0
1832 }
1833 }
1834 }
1835 #[inline]
1836 #[must_use]
1837 pub fn all(self) -> bool {
1838 pick! {
1839 if #[cfg(target_feature="simd128")] {
1840 u64x2_all_true(self.simd)
1841 } else {
1842 self.to_bitmask() == 0b11
1844 }
1845 }
1846 }
1847 #[inline]
1848 #[must_use]
1849 pub fn none(self) -> bool {
1850 !self.any()
1851 }
1852
1853 #[inline]
1854 fn vm_pow2n(self) -> Self {
1855 const_f64_as_f64x2!(pow2_52, 4503599627370496.0);
1856 const_f64_as_f64x2!(bias, 1023.0);
1857 let a = self + (bias + pow2_52);
1858 let c = cast::<_, i64x2>(a) << 52;
1859 let std_result = cast::<_, f64x2>(c);
1860
1861 let min_exp = f64x2::from(-1022.0);
1862 let is_sub = self.simd_lt(min_exp);
1863 if is_sub.any() {
1864 let valid = self.simd_ge(f64x2::from(-1074.0));
1865 let shift_f = self + f64x2::from(1074.0);
1866 let mut shift_i = shift_f.trunc_int();
1867 shift_i = cast::<_, i64x2>(valid).blend(shift_i, i64x2::ZERO);
1868 let mantissa = i64x2::ONE << shift_i;
1869 let sub_result = cast::<_, f64x2>(mantissa);
1870 let sub_result = valid.blend(sub_result, f64x2::ZERO);
1871 is_sub.blend(sub_result, std_result)
1872 } else {
1873 std_result
1874 }
1875 }
1876
1877 #[inline]
1879 #[must_use]
1880 pub fn exp(self) -> Self {
1881 const_f64_as_f64x2!(P2, 1.0 / 2.0);
1882 const_f64_as_f64x2!(P3, 1.0 / 6.0);
1883 const_f64_as_f64x2!(P4, 1.0 / 24.0);
1884 const_f64_as_f64x2!(P5, 1.0 / 120.0);
1885 const_f64_as_f64x2!(P6, 1.0 / 720.0);
1886 const_f64_as_f64x2!(P7, 1.0 / 5040.0);
1887 const_f64_as_f64x2!(P8, 1.0 / 40320.0);
1888 const_f64_as_f64x2!(P9, 1.0 / 362880.0);
1889 const_f64_as_f64x2!(P10, 1.0 / 3628800.0);
1890 const_f64_as_f64x2!(P11, 1.0 / 39916800.0);
1891 const_f64_as_f64x2!(P12, 1.0 / 479001600.0);
1892 const_f64_as_f64x2!(P13, 1.0 / 6227020800.0);
1893 const_f64_as_f64x2!(LN2D_HI, 0.693145751953125);
1897 const_f64_as_f64x2!(LN2D_LO, 1.42860682030941723212E-6);
1898 let max_x = f64x2::from(709.783);
1899 let min_x = f64x2::from(-744.79);
1900 let finite = self.is_finite();
1901 let neg_underflow = self.simd_lt(min_x) & finite;
1903 if neg_underflow.all() {
1904 return Self::ZERO;
1905 }
1906 let max_r = f64x2::from(1023.0);
1907 let r = (self * Self::LOG2_E).round();
1908 let big = r.simd_gt(max_r);
1909 let r_safe = big.blend(max_r, r);
1910 let excess = r - max_r;
1911 let excess = big.blend(excess, Self::ZERO);
1912 let scale = Self::vm_pow2n(excess);
1913 let x = r.mul_neg_add(LN2D_HI, self);
1914 let x = r.mul_neg_add(LN2D_LO, x);
1915 let z =
1916 polynomial_13!(x, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13);
1917 let n2 = Self::vm_pow2n(r_safe);
1918 let z = (z + Self::ONE) * scale * n2;
1919 let nan_mask = self.is_nan();
1920 let mut result = nan_mask.blend(Self::nan_pow(), z);
1921 let pos_overflow = self.simd_gt(max_x) & finite;
1922 result = pos_overflow.blend(Self::infinity(), result);
1923 result = neg_underflow.blend(Self::ZERO, result);
1924 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1925 result = pos_inf.blend(Self::infinity(), result);
1926 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1927 result = neg_inf.blend(Self::ZERO, result);
1928 result
1929 }
1930
1931 #[inline]
1934 #[must_use]
1935 pub fn exp_m1(self) -> Self {
1936 const_f64_as_f64x2!(P2, 1.0 / 2.0);
1937 const_f64_as_f64x2!(P3, 1.0 / 6.0);
1938 const_f64_as_f64x2!(P4, 1.0 / 24.0);
1939 const_f64_as_f64x2!(P5, 1.0 / 120.0);
1940 const_f64_as_f64x2!(P6, 1.0 / 720.0);
1941 const_f64_as_f64x2!(P7, 1.0 / 5040.0);
1942 const_f64_as_f64x2!(P8, 1.0 / 40320.0);
1943 const_f64_as_f64x2!(P9, 1.0 / 362880.0);
1944 const_f64_as_f64x2!(P10, 1.0 / 3628800.0);
1945 const_f64_as_f64x2!(P11, 1.0 / 39916800.0);
1946 const_f64_as_f64x2!(P12, 1.0 / 479001600.0);
1947 const_f64_as_f64x2!(P13, 1.0 / 6227020800.0);
1948 const_f64_as_f64x2!(LN2D_HI, 0.693145751953125);
1951 const_f64_as_f64x2!(LN2D_LO, 1.42860682030941723212E-6);
1952 if self.simd_lt(Self::from(-37.429)).all() {
1956 return Self::from(-1.0);
1957 }
1958 let max_x = Self::from(709.783);
1962 let min_x = Self::from(-744.79);
1963 let max_r = Self::from(1023.0);
1964 let r = (self * Self::LOG2_E).round();
1965 let big = r.simd_gt(max_r);
1966 let r_safe = big.blend(max_r, r);
1967 let excess = r - max_r;
1968 let excess = big.blend(excess, Self::ZERO);
1969 let scale = Self::vm_pow2n(excess);
1970 let x = r.mul_neg_add(LN2D_HI, self);
1971 let x = r.mul_neg_add(LN2D_LO, x);
1972 let z =
1973 polynomial_13!(x, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13);
1974 let n2 = Self::vm_pow2n(r_safe);
1975 let exp_val = (z + Self::ONE) * scale * n2;
1976 let r_is_zero = r.simd_eq(Self::ZERO);
1980 let z = r_is_zero.blend(z, exp_val - Self::ONE);
1981 let nan_mask = self.is_nan();
1982 let finite = self.is_finite();
1983 let mut result = nan_mask.blend(Self::nan_pow(), z);
1984 let pos_overflow = self.simd_gt(max_x) & finite;
1985 result = pos_overflow.blend(Self::infinity(), result);
1986 let neg_underflow = self.simd_lt(min_x) & finite;
1987 result = neg_underflow.blend(-Self::ONE, result);
1988 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1989 result = pos_inf.blend(Self::infinity(), result);
1990 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1991 result = neg_inf.blend(-Self::ONE, result);
1992 let is_zero = self.simd_eq(Self::ZERO);
1993 result = is_zero.blend(self, result);
1994 result
1995 }
1996
1997 #[inline]
1999 #[must_use]
2000 pub fn exp2(self) -> Self {
2001 const_f64_as_f64x2!(P2, 1.0 / 2.0);
2002 const_f64_as_f64x2!(P3, 1.0 / 6.0);
2003 const_f64_as_f64x2!(P4, 1.0 / 24.0);
2004 const_f64_as_f64x2!(P5, 1.0 / 120.0);
2005 const_f64_as_f64x2!(P6, 1.0 / 720.0);
2006 const_f64_as_f64x2!(P7, 1.0 / 5040.0);
2007 const_f64_as_f64x2!(P8, 1.0 / 40320.0);
2008 const_f64_as_f64x2!(P9, 1.0 / 362880.0);
2009 const_f64_as_f64x2!(P10, 1.0 / 3628800.0);
2010
2011 let max_x = f64x2::from(1023.9999999999999);
2014 let min_x = f64x2::from(-1074.5);
2015 let finite = self.is_finite();
2016 let neg_underflow = self.simd_lt(min_x) & finite;
2017 if neg_underflow.all() {
2018 return Self::ZERO;
2019 }
2020
2021 let round = self.round();
2022 let max_r = f64x2::from(1023.0);
2023 let big = round.simd_gt(max_r);
2024 let r_safe = big.blend(max_r, round);
2025 let excess = round - max_r;
2026 let excess = big.blend(excess, Self::ZERO);
2027 let scale = Self::vm_pow2n(excess);
2028
2029 let fract = (self - round) * Self::LN_2;
2030 let fract_partial_exp2 =
2031 polynomial_8!(fract, P2, P3, P4, P5, P6, P7, P8, P9, P10);
2032 let fract2 = fract * fract;
2033 let fract_exp2 = fract_partial_exp2.mul_add(fract2, fract) + Self::ONE;
2034
2035 let n2 = Self::vm_pow2n(r_safe);
2036 let result = fract_exp2 * scale * n2;
2037
2038 let nan_mask = self.is_nan();
2039 let mut result = nan_mask.blend(Self::nan_pow(), result);
2040 let pos_overflow = self.simd_gt(max_x) & finite;
2041 result = pos_overflow.blend(Self::infinity(), result);
2042 result = neg_underflow.blend(Self::ZERO, result);
2043 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
2044 result = pos_inf.blend(Self::infinity(), result);
2045 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
2046 result = neg_inf.blend(Self::ZERO, result);
2047 result
2048 }
2049
2050 #[inline]
2051 fn exponent(self) -> f64x2 {
2052 const_f64_as_f64x2!(pow2_52, 4503599627370496.0);
2053 const_f64_as_f64x2!(bias, 1023.0);
2054 let a = cast::<_, u64x2>(self);
2055 let b = a >> 52;
2056 let c = b | cast::<_, u64x2>(pow2_52);
2057 let d = cast::<_, f64x2>(c);
2058 let e = d - (pow2_52 + bias);
2059 e
2060 }
2061
2062 #[inline]
2063 fn fraction_2(self) -> Self {
2064 let t1 = cast::<_, u64x2>(self);
2065 let t2 = cast::<_, u64x2>(
2066 (t1 & u64x2::from(0x000FFFFFFFFFFFFF)) | u64x2::from(0x3FE0000000000000),
2067 );
2068 cast::<_, f64x2>(t2)
2069 }
2070
2071 #[inline]
2072 fn is_zero_or_subnormal(self) -> Self {
2073 let t = cast::<_, i64x2>(self);
2074 let t = t & i64x2::splat(0x7FF0000000000000);
2075 let mask = t.simd_eq(i64x2::splat(0));
2076 cast::<_, f64x2>(mask)
2077 }
2078
2079 #[inline]
2080 fn infinity() -> Self {
2081 cast::<_, f64x2>(i64x2::splat(0x7FF0000000000000))
2082 }
2083
2084 #[inline]
2085 fn nan_log() -> Self {
2086 cast::<_, f64x2>(i64x2::splat(0x7FF8000000000000 | 0x101 << 29))
2087 }
2088
2089 #[inline]
2090 fn nan_pow() -> Self {
2091 cast::<_, f64x2>(i64x2::splat(0x7FF8000000000000 | 0x101 << 29))
2092 }
2093
2094 #[inline]
2097 #[must_use]
2098 pub fn is_sign_positive(self) -> Self {
2099 pick! {
2100 if #[cfg(any(target_feature = "sse4.1", not(target_feature = "sse2")))] {
2102 const SIGN_MASK: u64x2 = u64x2::splat((-0.0_f64).to_bits());
2103
2104 let bits = cast::<f64x2, u64x2>(self);
2105 let sign = bits & SIGN_MASK;
2106 let result = sign.simd_eq(u64x2::ZERO);
2107 cast::<u64x2, f64x2>(result)
2108 } else {
2109 let bits = cast::<f64x2, u64x2>(self);
2110 let sign = bits >> 63;
2111 let sign = cast::<u64x2, f64x2>(sign);
2112 sign.simd_eq(f64x2::ZERO)
2113 }
2114 }
2115 }
2116
2117 #[inline]
2120 #[must_use]
2121 pub fn is_sign_negative(self) -> Self {
2122 pick! {
2123 if #[cfg(any(target_feature = "sse4.1", not(target_feature = "sse2")))] {
2125 const SIGN_MASK: u64x2 = u64x2::splat((-0.0_f64).to_bits());
2126
2127 let bits = cast::<f64x2, u64x2>(self);
2128 let sign = bits & SIGN_MASK;
2129 let result = sign.simd_eq(SIGN_MASK);
2130 cast::<u64x2, f64x2>(result)
2131 } else {
2132 let bits = cast::<f64x2, u64x2>(self);
2133 let sign = bits >> 63;
2134 let sign = cast::<u64x2, f64x2>(sign);
2135 sign.simd_ne(f64x2::ZERO)
2136 }
2137 }
2138 }
2139
2140 #[inline]
2142 #[must_use]
2143 pub fn reduce_add(self) -> f64 {
2144 pick! {
2145 if #[cfg(target_feature="ssse3")] {
2146 let a = add_horizontal_m128d(self.sse, self.sse);
2147 a.to_array()[0]
2148 } else if #[cfg(any(target_feature="sse2", target_feature="simd128"))] {
2149 let a: [f64;2] = cast(self);
2150 a.iter().sum()
2151 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
2152 unsafe { vgetq_lane_f64(self.neon,0) + vgetq_lane_f64(self.neon,1) }
2153 } else {
2154 self.arr.iter().sum()
2155 }
2156 }
2157 }
2158
2159 #[inline]
2161 #[must_use]
2162 pub fn reduce_mul(self) -> f64 {
2163 let arr: [f64; 2] = cast(self);
2164 arr.iter().product()
2165 }
2166
2167 #[inline]
2168 #[must_use]
2169 pub fn ln(self) -> Self {
2170 const_f64_as_f64x2!(P0, 7.70838733755885391666E0);
2171 const_f64_as_f64x2!(P1, 1.79368678507819816313E1);
2172 const_f64_as_f64x2!(P2, 1.44989225341610930846E1);
2173 const_f64_as_f64x2!(P3, 4.70579119878881725854E0);
2174 const_f64_as_f64x2!(P4, 4.97494994976747001425E-1);
2175 const_f64_as_f64x2!(P5, 1.01875663804580931796E-4);
2176
2177 const_f64_as_f64x2!(Q0, 2.31251620126765340583E1);
2178 const_f64_as_f64x2!(Q1, 7.11544750618563894466E1);
2179 const_f64_as_f64x2!(Q2, 8.29875266912776603211E1);
2180 const_f64_as_f64x2!(Q3, 4.52279145837532221105E1);
2181 const_f64_as_f64x2!(Q4, 1.12873587189167450590E1);
2182 const_f64_as_f64x2!(LN2F_HI, f64::from_bits(0x3FE62E42FEE00000));
2188 const_f64_as_f64x2!(LN2F_LO, f64::from_bits(0x3DEA39EF35793C76));
2189 const_f64_as_f64x2!(VM_SQRT2, 1.414213562373095048801);
2190 const_f64_as_f64x2!(VM_SMALLEST_NORMAL, 2.2250738585072014E-308);
2191
2192 let x1 = self;
2193 let x = Self::fraction_2(x1);
2194 let e = Self::exponent(x1);
2195 let mask = x.simd_gt(VM_SQRT2 * f64x2::HALF);
2196 let x = (!mask).blend(x + x, x);
2197 let fe = mask.blend(e + Self::ONE, e);
2198 let x = x - Self::ONE;
2199 let px = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
2200 let x2 = x * x;
2201 let px = x2 * x * px;
2202 let qx = polynomial_5n!(x, Q0, Q1, Q2, Q3, Q4);
2203 let res = px / qx;
2204 let res = fe.mul_add(LN2F_LO, res);
2205 let res = res + x2.mul_neg_add(f64x2::HALF, x);
2206 let res = fe.mul_add(LN2F_HI, res);
2207 let overflow = !self.is_finite();
2208 let underflow = x1.simd_lt(VM_SMALLEST_NORMAL);
2209 let mask = overflow | underflow;
2210 if !mask.any() {
2211 res
2212 } else {
2213 let is_zero = self.is_zero_or_subnormal();
2214 let res = underflow.blend(Self::nan_log(), res);
2215 let res = is_zero.blend(-Self::infinity(), res);
2220 let res = overflow.blend(self, res);
2221 let res = (!self.is_finite() & self.is_sign_negative())
2223 .blend(Self::nan_log(), res);
2224 res
2225 }
2226 }
2227
2228 #[inline]
2231 #[must_use]
2232 pub fn ln_1p(self) -> Self {
2233 let u = self + Self::ONE;
2241 let eq = u.simd_eq(Self::ONE);
2242 let ln_u = Self::ln(u);
2243 let correction = self * (ln_u / (u - Self::ONE));
2244 let result = eq.blend(self, correction);
2245 let over = u.is_inf();
2246 over.blend(ln_u, result)
2247 }
2248
2249 #[inline]
2250 #[must_use]
2251 pub fn log2(self) -> Self {
2252 Self::ln(self) * Self::LOG2_E
2253 }
2254 #[inline]
2255 #[must_use]
2256 pub fn log10(self) -> Self {
2257 Self::ln(self) * Self::LOG10_E
2258 }
2259
2260 #[inline]
2261 #[must_use]
2262 pub fn pow_f64x2(self, y: Self) -> Self {
2263 const_f64_as_f64x2!(ln2d_hi, 0.693145751953125);
2264 const_f64_as_f64x2!(ln2d_lo, 1.42860682030941723212E-6);
2265 const_f64_as_f64x2!(P0log, 2.0039553499201281259648E1);
2266 const_f64_as_f64x2!(P1log, 5.7112963590585538103336E1);
2267 const_f64_as_f64x2!(P2log, 6.0949667980987787057556E1);
2268 const_f64_as_f64x2!(P3log, 2.9911919328553073277375E1);
2269 const_f64_as_f64x2!(P4log, 6.5787325942061044846969E0);
2270 const_f64_as_f64x2!(P5log, 4.9854102823193375972212E-1);
2271 const_f64_as_f64x2!(P6log, 4.5270000862445199635215E-5);
2272 const_f64_as_f64x2!(Q0log, 6.0118660497603843919306E1);
2273 const_f64_as_f64x2!(Q1log, 2.1642788614495947685003E2);
2274 const_f64_as_f64x2!(Q2log, 3.0909872225312059774938E2);
2275 const_f64_as_f64x2!(Q3log, 2.2176239823732856465394E2);
2276 const_f64_as_f64x2!(Q4log, 8.3047565967967209469434E1);
2277 const_f64_as_f64x2!(Q5log, 1.5062909083469192043167E1);
2278
2279 const_f64_as_f64x2!(p2, 1.0 / 2.0); const_f64_as_f64x2!(p3, 1.0 / 6.0);
2282 const_f64_as_f64x2!(p4, 1.0 / 24.0);
2283 const_f64_as_f64x2!(p5, 1.0 / 120.0);
2284 const_f64_as_f64x2!(p6, 1.0 / 720.0);
2285 const_f64_as_f64x2!(p7, 1.0 / 5040.0);
2286 const_f64_as_f64x2!(p8, 1.0 / 40320.0);
2287 const_f64_as_f64x2!(p9, 1.0 / 362880.0);
2288 const_f64_as_f64x2!(p10, 1.0 / 3628800.0);
2289 const_f64_as_f64x2!(p11, 1.0 / 39916800.0);
2290 const_f64_as_f64x2!(p12, 1.0 / 479001600.0);
2291 const_f64_as_f64x2!(p13, 1.0 / 6227020800.0);
2292
2293 let x1 = self.abs();
2294 let x = x1.fraction_2();
2295 let mask = x.simd_gt(f64x2::SQRT_2 * f64x2::HALF);
2296 let x = (!mask).blend(x + x, x);
2297 let x = x - f64x2::ONE;
2298 let x2 = x * x;
2299 let px = polynomial_6!(x, P0log, P1log, P2log, P3log, P4log, P5log, P6log);
2300 let px = px * x * x2;
2301 let qx = polynomial_6n!(x, Q0log, Q1log, Q2log, Q3log, Q4log, Q5log);
2302 let lg1 = px / qx;
2303
2304 let ef = x1.exponent();
2305 let ef = mask.blend(ef + f64x2::ONE, ef);
2306 let e1 = (ef * y).round();
2307 let yr = ef.mul_sub(y, e1);
2308
2309 let lg = f64x2::HALF.mul_neg_add(x2, x) + lg1;
2310 let x2err = (f64x2::HALF * x).mul_sub(x, f64x2::HALF * x2);
2311 let lg_err = f64x2::HALF.mul_add(x2, lg - x) - lg1;
2312
2313 let e2 = (lg * y * f64x2::LOG2_E).round();
2314 let v = lg.mul_sub(y, e2 * ln2d_hi);
2315 let v = e2.mul_neg_add(ln2d_lo, v);
2316 let v = v - (lg_err + x2err).mul_sub(y, yr * f64x2::LN_2);
2317
2318 let x = v;
2319 let e3 = (x * f64x2::LOG2_E).round();
2320 let x = e3.mul_neg_add(f64x2::LN_2, x);
2321 let z =
2322 polynomial_13!(x, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)
2323 + f64x2::ONE;
2324 let ee = e1 + e2 + e3;
2325 let ei = cast::<_, i64x2>(ee.round_int());
2326 let ej = cast::<_, i64x2>(ei + (cast::<_, i64x2>(z) >> 52));
2327
2328 let overflow = cast::<_, f64x2>(!ej.simd_lt(i64x2::splat(0x07FF)))
2329 | ee.simd_gt(f64x2::splat(3000.0));
2330 let underflow = cast::<_, f64x2>(!ej.simd_gt(i64x2::splat(0x000)))
2331 | ee.simd_lt(f64x2::splat(-3000.0));
2332
2333 let z = cast::<_, f64x2>(cast::<_, i64x2>(z) + (ei << 52));
2335
2336 let z = if (overflow | underflow).any() {
2338 let z = underflow.blend(f64x2::ZERO, z);
2339 overflow.blend(Self::infinity(), z)
2340 } else {
2341 z
2342 };
2343
2344 let x_zero = self.is_zero_or_subnormal();
2346 let z = x_zero.blend(
2347 y.simd_lt(f64x2::ZERO).blend(
2348 Self::infinity(),
2349 y.simd_eq(f64x2::ZERO).blend(f64x2::ONE, f64x2::ZERO),
2350 ),
2351 z,
2352 );
2353
2354 let x_sign = self.is_sign_negative();
2355 let z = if x_sign.any() {
2356 let yi = y.simd_eq(y.round());
2358 let y_odd = cast::<_, i64x2>(y.round_int() << 63).round_float();
2360
2361 let z1 =
2362 yi.blend(z | y_odd, self.simd_eq(Self::ZERO).blend(z, Self::nan_pow()));
2363 x_sign.blend(z1, z)
2364 } else {
2365 z
2366 };
2367
2368 let x_finite = self.is_finite();
2369 let y_finite = y.is_finite();
2370 let e_finite = ee.is_finite();
2371
2372 if (x_finite & y_finite & (e_finite | x_zero)).all() {
2373 return z;
2374 }
2375
2376 (self.is_nan() | y.is_nan()).blend(self + y, z)
2377 }
2378
2379 #[inline]
2380 pub fn powf(self, y: f64) -> Self {
2381 Self::pow_f64x2(self, f64x2::splat(y))
2382 }
2383
2384 #[must_use]
2386 #[inline]
2387 #[allow(dead_code)]
2388 pub(crate) fn unpack_lo(self, b: Self) -> Self {
2389 pick! {
2390 if #[cfg(target_feature="sse2")] {
2391 Self { sse: unpack_low_m128d(self.sse, b.sse) }
2392 } else if #[cfg(target_feature="simd128")] {
2393 Self { simd: i64x2_shuffle::<0, 2>(self.simd, b.simd) }
2394 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
2395 Self { neon: unsafe { vzip1q_f64(self.neon, b.neon) } }
2396 } else {
2397 Self::new([self.as_array()[0], b.as_array()[0]])
2398 }
2399 }
2400 }
2401
2402 #[must_use]
2404 #[inline]
2405 #[allow(dead_code)]
2406 pub(crate) fn unpack_hi(self, b: Self) -> Self {
2407 pick! {
2408 if #[cfg(target_feature="sse2")] {
2409 Self { sse: unpack_high_m128d(self.sse, b.sse) }
2410 } else if #[cfg(target_feature="simd128")] {
2411 Self { simd: i64x2_shuffle::<1, 3>(self.simd, b.simd) }
2412 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
2413 Self { neon: unsafe { vzip2q_f64(self.neon, b.neon) } }
2414 } else {
2415 Self::new([self.as_array()[1], b.as_array()[1]])
2416 }
2417 }
2418 }
2419
2420 #[inline]
2422 pub fn transpose(data: [f64x2; 2]) -> [f64x2; 2] {
2423 pick! {
2424 if #[cfg(any(
2425 target_feature="sse2",
2426 all(target_feature="neon",target_arch="aarch64"),
2427 target_feature="simd128",
2428 ))] {
2429 [data[0].unpack_lo(data[1]), data[0].unpack_hi(data[1])]
2430 } else {
2431 let [x, y, z, w]: [f64; 4] = cast(data);
2432 cast([x, z, y, w])
2433 }
2434 }
2435 }
2436
2437 #[inline]
2438 pub fn to_array(self) -> [f64; 2] {
2439 cast(self)
2440 }
2441
2442 #[inline]
2443 pub fn as_array(&self) -> &[f64; 2] {
2444 cast_ref(self)
2445 }
2446
2447 #[inline]
2448 pub fn as_mut_array(&mut self) -> &mut [f64; 2] {
2449 cast_mut(self)
2450 }
2451
2452 #[inline]
2455 pub fn from_i32x4_lower2(v: i32x4) -> Self {
2456 pick! {
2457 if #[cfg(target_feature="sse2")] {
2458 Self { sse: convert_to_m128d_from_lower2_i32_m128i(v.sse) }
2459 } else if #[cfg(target_feature="simd128")] {
2460 Self { simd: f64x2_convert_low_i32x4(v.simd)}
2461 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
2462 Self { neon: unsafe { vcvtq_f64_s64(vmovl_s32(vget_low_s32(v.neon))) }}
2463 } else {
2464 Self { arr: [
2465 v.as_array()[0] as f64,
2466 v.as_array()[1] as f64,
2467 ]}
2468 }
2469 }
2470 }
2471}
2472
2473impl From<i32x4> for f64x2 {
2474 #[inline]
2477 fn from(v: i32x4) -> Self {
2478 Self::from_i32x4_lower2(v)
2479 }
2480}
2481
2482impl Not for f64x2 {
2483 type Output = Self;
2484 #[inline]
2485 fn not(self) -> Self {
2486 pick! {
2487 if #[cfg(target_feature="sse2")] {
2488 Self { sse: self.sse.not() }
2489 } else if #[cfg(target_feature="simd128")] {
2490 Self { simd: v128_not(self.simd) }
2491 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
2492 unsafe {Self { neon: vreinterpretq_f64_u32(vmvnq_u32(vreinterpretq_u32_f64(self.neon))) }}
2493 } else {
2494 Self { arr: [
2495 f64::from_bits(!self.arr[0].to_bits()),
2496 f64::from_bits(!self.arr[1].to_bits()),
2497 ]}
2498 }
2499 }
2500 }
2501}