1#![doc = include_str!("../README.md")]
2#![no_std]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![allow(unused_braces)]
5
6use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign};
7
8use num_traits::{NumAssignOps, NumOps};
9use thermite::Swizzle;
10use thermite::element::SignedElement;
11use thermite::generic_array::GenericArray;
12use thermite::register::SwizzleIndices;
13use thermite::tribool::{self, Tribool};
14use thermite::vector::{NewConst, NewVector, SplatConst, SplatVector, VectorValue, const_splat};
15use thermite::{LargeInt, mask::GenericSelectable, prelude::*};
16
17use thermite::vector::ops::{AddSubExt, AddSubExtMasked, MulAddAssignExt, MulAddExt, Square, SquareMasked};
18
19pub mod consts;
38pub mod math;
39
40#[cfg(feature = "special")]
41pub mod special;
42pub mod specialized;
43
44pub trait ScalarValue:
55 Copy + NumOps + NumAssignOps + MulAddExt<Output = Self> + Neg<Output = Self> + consts::SplitFloatConsts<Self>
56{
57 const SPLITTER: Self;
59
60 const SPLIT_THRESH: Self;
68
69 const SPLIT_DOWN: Self;
71
72 const SPLIT_UP: Self;
74
75 const SCALAR_ZERO: Self;
77
78 const SCALAR_ONE: Self;
80
81 const MAX_ERFINV_SERIES: Self;
85
86 const ERF_CF_SPLIT: Self;
106
107 fn scalar_trunc(self) -> Self;
111
112 type CompensatedConstInt<const N: LargeInt>: SplatConst<Compensated<Self>>;
119
120 type CompensatedConstRatio<const N: LargeInt, const D: LargeInt>: SplatConst<Compensated<Self>>;
124
125 #[inline(always)]
126 fn two_sum(a: Self, b: Self) -> (Self, Self) {
127 let s = a + b;
128 let v = s - a;
129 let e = (a - (s - v)) + (b - v);
130 (s, e)
131 }
132
133 #[inline(always)]
134 fn two_diff(a: Self, b: Self) -> (Self, Self) {
135 let s = a - b;
136 let v = s - a;
137 let e = (a - (s - v)) - (b + v);
138 (s, e)
139 }
140
141 #[inline(always)]
156 fn veltkamp_split(a: Self) -> (Self, Self) {
157 let c = a * Self::SPLITTER;
158 let hi = c - (c - a);
159 (hi, a - hi)
160 }
161
162 fn rebalance_for_split(a: Self, b: Self) -> (Self, Self);
195
196 #[inline(always)]
197 fn two_prod(a: Self, b: Self) -> (Self, Self) {
198 if matches!(Self::HAS_NATIVE_FMA, tribool::True) {
200 let p = a * b;
201 let e = a.mul_sub(b, p);
202
203 return (p, e);
204 }
205
206 let (sa, sb) = Self::rebalance_for_split(a, b);
209 let (a_hi, a_lo) = Self::veltkamp_split(sa);
210 let (b_hi, b_lo) = Self::veltkamp_split(sb);
211
212 let p = a * b;
214
215 let err = ((a_hi * b_hi - p) + a_hi * b_lo + a_lo * b_hi) + a_lo * b_lo;
216
217 (p, err)
218 }
219
220 #[inline(always)]
221 fn square(a: Self) -> (Self, Self) {
222 if matches!(Self::HAS_NATIVE_FMA, tribool::True) {
224 let p = a * a;
225 let e = a.mul_sub(a, p);
226
227 return (p, e);
228 }
229
230 let (a_hi, a_lo) = Self::veltkamp_split(a);
234
235 let p = a * a;
237
238 let d = a_hi * a_lo;
239 let err = ((a_hi * a_hi - p) + d + d) + a_lo * a_lo;
240
241 (p, err)
242 }
243
244 #[inline(always)]
253 fn two_quot(a: Self, b: Self) -> (Self, Self) {
254 let q = a / b;
255
256 if matches!(Self::HAS_NATIVE_FMA, tribool::True) {
257 return (q, q.nmul_add(b, a));
258 }
259
260 let (p, e) = Self::two_prod(q, b);
261
262 (q, (a - p) - e)
263 }
264}
265
266impl ScalarValue for f32 {
267 const SPLITTER: Self = ((1u64 << 12) + 1) as f32; const SPLIT_THRESH: Self = 4.153_837_5e34; const SPLIT_DOWN: Self = 1.220_703_1e-4; const SPLIT_UP: Self = 8192.0; const SCALAR_ZERO: Self = 0.0;
272 const SCALAR_ONE: Self = 1.0;
273 const MAX_ERFINV_SERIES: Self = 0.75;
274 const ERF_CF_SPLIT: Self = 2.0;
277
278 #[inline(always)]
279 #[allow(
280 clippy::manual_range_contains,
281 reason = "RangeInclusive::contains is false for NaN, so the negated form would send NaN down the rebalance path; the explicit comparison leaves it on the fast path"
282 )]
283 fn rebalance_for_split(a: Self, b: Self) -> (Self, Self) {
284 const THRESH: f32 = <f32 as ScalarValue>::SPLIT_THRESH;
285 const DOWN: f32 = <f32 as ScalarValue>::SPLIT_DOWN;
286 const UP: f32 = <f32 as ScalarValue>::SPLIT_UP;
287
288 if a > THRESH || a < -THRESH {
289 (a * DOWN, b * UP)
290 } else if b > THRESH || b < -THRESH {
291 (a * UP, b * DOWN)
292 } else {
293 (a, b)
294 }
295 }
296
297 #[inline(always)]
298 fn scalar_trunc(self) -> Self {
299 FloatElement::trunc(self)
300 }
301
302 type CompensatedConstInt<const N: LargeInt> = F32CompensatedIntConst<N>;
303 type CompensatedConstRatio<const N: LargeInt, const D: LargeInt> = F32CompensatedRatioConst<N, D>;
304}
305
306impl ScalarValue for f64 {
307 const SPLITTER: Self = ((1u64 << 27) + 1) as f64; const SPLIT_THRESH: Self = 6.69692879491417e299; const SPLIT_DOWN: Self = 3.725_290_298_461_914e-9; const SPLIT_UP: Self = 268435456.0; const SCALAR_ZERO: Self = 0.0;
312 const SCALAR_ONE: Self = 1.0;
313 const MAX_ERFINV_SERIES: Self = 0.545;
314 const ERF_CF_SPLIT: Self = 1.5;
315
316 #[inline(always)]
317 #[allow(
318 clippy::manual_range_contains,
319 reason = "RangeInclusive::contains is false for NaN, so the negated form would send NaN down the rebalance path; the explicit comparison leaves it on the fast path"
320 )]
321 fn rebalance_for_split(a: Self, b: Self) -> (Self, Self) {
322 const THRESH: f64 = <f64 as ScalarValue>::SPLIT_THRESH;
323 const DOWN: f64 = <f64 as ScalarValue>::SPLIT_DOWN;
324 const UP: f64 = <f64 as ScalarValue>::SPLIT_UP;
325
326 if a > THRESH || a < -THRESH {
327 (a * DOWN, b * UP)
328 } else if b > THRESH || b < -THRESH {
329 (a * UP, b * DOWN)
330 } else {
331 (a, b)
332 }
333 }
334
335 #[inline(always)]
336 fn scalar_trunc(self) -> Self {
337 FloatElement::trunc(self)
338 }
339
340 type CompensatedConstInt<const N: LargeInt> = F64CompensatedIntConst<N>;
341 type CompensatedConstRatio<const N: LargeInt, const D: LargeInt> = F64CompensatedRatioConst<N, D>;
342}
343
344struct SplitterValue<E>(core::marker::PhantomData<E>);
351
352impl<E: ScalarValue> SplatConst<E> for SplitterValue<E> {
353 const VALUE: E = <E as ScalarValue>::SPLITTER;
354}
355
356const _: () = {
365 assert!(<f32 as ScalarValue>::SPLIT_DOWN * <f32 as ScalarValue>::SPLIT_UP == 1.0);
367 assert!(<f64 as ScalarValue>::SPLIT_DOWN * <f64 as ScalarValue>::SPLIT_UP == 1.0);
368
369 assert!(<f32 as ScalarValue>::SPLIT_DOWN.to_bits() & ((1 << 23) - 1) == 0);
372 assert!(<f64 as ScalarValue>::SPLIT_DOWN.to_bits() & ((1 << 52) - 1) == 0);
373 assert!(<f32 as ScalarValue>::SPLIT_UP.to_bits() & ((1 << 23) - 1) == 0);
374 assert!(<f64 as ScalarValue>::SPLIT_UP.to_bits() & ((1 << 52) - 1) == 0);
375
376 assert!(<f32 as ScalarValue>::SPLIT_THRESH * <f32 as ScalarValue>::SPLITTER < f32::MAX);
379 assert!(<f64 as ScalarValue>::SPLIT_THRESH * <f64 as ScalarValue>::SPLITTER < f64::MAX);
380 assert!(f32::MAX * <f32 as ScalarValue>::SPLIT_DOWN * <f32 as ScalarValue>::SPLITTER < f32::MAX);
381 assert!(f64::MAX * <f64 as ScalarValue>::SPLIT_DOWN * <f64 as ScalarValue>::SPLITTER < f64::MAX);
382};
383
384struct SplitThreshValue<E>(core::marker::PhantomData<E>);
386
387impl<E: ScalarValue> SplatConst<E> for SplitThreshValue<E> {
388 const VALUE: E = <E as ScalarValue>::SPLIT_THRESH;
389}
390
391struct SplitDownValue<E>(core::marker::PhantomData<E>);
393
394impl<E: ScalarValue> SplatConst<E> for SplitDownValue<E> {
395 const VALUE: E = <E as ScalarValue>::SPLIT_DOWN;
396}
397
398struct SplitUpValue<E>(core::marker::PhantomData<E>);
400
401impl<E: ScalarValue> SplatConst<E> for SplitUpValue<E> {
402 const VALUE: E = <E as ScalarValue>::SPLIT_UP;
403}
404
405struct MaxErfinvSeriesValue<E>(core::marker::PhantomData<E>);
407
408impl<E: ScalarValue> SplatConst<E> for MaxErfinvSeriesValue<E> {
409 const VALUE: E = <E as ScalarValue>::MAX_ERFINV_SERIES;
410}
411
412struct ErfCfSplitValue<E>(core::marker::PhantomData<E>);
414
415impl<E: ScalarValue> SplatConst<E> for ErfCfSplitValue<E> {
416 const VALUE: E = <E as ScalarValue>::ERF_CF_SPLIT;
417}
418
419#[cold]
425#[inline(never)]
426fn rebalance_split_cold<R: thermite::register::FloatRegister>(a: Vector<R>, b: Vector<R>) -> (Vector<R>, Vector<R>)
427where
428 R::Element: ScalarValue,
429{
430 let thresh = <Vector<R> as ScalarValue>::SPLIT_THRESH;
431 let down = <Vector<R> as ScalarValue>::SPLIT_DOWN;
432 let up = <Vector<R> as ScalarValue>::SPLIT_UP;
433 let one = <Vector<R> as ScalarValue>::SCALAR_ONE;
434
435 let big_a = a.abs().cmp_gt(thresh);
436 let big_b = b.abs().cmp_gt(thresh);
437
438 let sa = big_a.select(down, big_b.select(up, one));
439 let sb = big_a.select(up, big_b.select(down, one));
440
441 (a * sa, b * sb)
442}
443
444impl<R: thermite::register::FloatRegister> ScalarValue for Vector<R>
445where
446 R::Element: ScalarValue,
447{
448 const SPLITTER: Self = const_splat::<Self, SplitterValue<R::Element>>();
449 const SPLIT_THRESH: Self = const_splat::<Self, SplitThreshValue<R::Element>>();
450 const SPLIT_DOWN: Self = const_splat::<Self, SplitDownValue<R::Element>>();
451 const SPLIT_UP: Self = const_splat::<Self, SplitUpValue<R::Element>>();
452 const SCALAR_ZERO: Self = Self::ZERO;
453 const SCALAR_ONE: Self = Self::ONE;
454 const MAX_ERFINV_SERIES: Self = const_splat::<Self, MaxErfinvSeriesValue<R::Element>>();
455 const ERF_CF_SPLIT: Self = const_splat::<Self, ErfCfSplitValue<R::Element>>();
456
457 #[inline(always)]
464 fn two_sum(a: Self, b: Self) -> (Self, Self) {
465 <Self as FloatVectorWithBits>::two_sum(a, b)
466 }
467
468 #[inline(always)]
469 fn two_diff(a: Self, b: Self) -> (Self, Self) {
470 <Self as FloatVectorWithBits>::two_diff(a, b)
471 }
472
473 #[inline(always)]
474 fn two_prod(a: Self, b: Self) -> (Self, Self) {
475 <Self as FloatVectorWithBits>::two_prod(a, b)
476 }
477
478 #[inline(always)]
479 fn square(a: Self) -> (Self, Self) {
480 <Self as FloatVectorWithBits>::two_square(a)
481 }
482
483 #[inline(always)]
484 fn two_quot(a: Self, b: Self) -> (Self, Self) {
485 <Self as FloatVectorWithBits>::two_quot(a, b)
486 }
487
488 #[inline(always)]
498 fn rebalance_for_split(a: Self, b: Self) -> (Self, Self) {
499 if a.abs().max(b.abs()).cmp_gt(Self::SPLIT_THRESH).any() {
501 rebalance_split_cold(a, b)
502 } else {
503 (a, b)
504 }
505 }
506
507 #[inline(always)]
508 fn scalar_trunc(self) -> Self {
509 self.trunc()
510 }
511
512 type CompensatedConstInt<const N: LargeInt> =
513 CompensatedVectorConst<<R::Element as ScalarValue>::CompensatedConstInt<N>>;
514
515 type CompensatedConstRatio<const N: LargeInt, const D: LargeInt> =
516 CompensatedVectorConst<<R::Element as ScalarValue>::CompensatedConstRatio<N, D>>;
517}
518
519pub trait CompensatedFloatVector:
556 ScalarValue + FloatVector<Element: ScalarValue> + CastVector<Self> + SwizzleVector
557{
558}
559impl<V> CompensatedFloatVector for V where
560 V: ScalarValue + FloatVector<Element: ScalarValue> + CastVector<V> + SwizzleVector
561{
562}
563
564impl<V: CompensatedFloatVector> Swizzle<V::Lanes> for Compensated<V> {
568 #[inline(always)]
569 fn swizzle_const<I: SwizzleIndices<V::Lanes>>(self, other: Self) -> Self {
570 Self {
571 value: self.value.swizzle_const::<I>(other.value),
572 error: self.error.swizzle_const::<I>(other.error),
573 }
574 }
575
576 #[inline(always)]
577 fn permutev_const<I: SwizzleIndices<V::Lanes>>(self) -> Self {
578 Self {
579 value: self.value.permutev_const::<I>(),
580 error: self.error.permutev_const::<I>(),
581 }
582 }
583}
584
585#[rustfmt::skip]
586impl<E: ScalarValue + Element> Element for Compensated<E> {
587 type Signed = <E as Element>::Signed;
588 type Unsigned = <E as Element>::Unsigned;
589
590 const ONE: Self = Self { value: E::ONE, error: E::ZERO };
591 const ZERO: Self = Self { value: E::ZERO, error: E::ZERO };
592
593 const ORDER_MAX: Self = Self { value: E::ORDER_MAX, error: E::ZERO };
596 const ORDER_MIN: Self = Self { value: E::ORDER_MIN, error: E::ZERO };
597 const HAS_UNORDERED: bool = E::HAS_UNORDERED;
598 const IS_FLOAT: bool = E::IS_FLOAT;
599
600 fn from_i8(value: i8) -> Self { Self { value: E::from_i8(value), error: E::ZERO } }
601 fn from_u8(value: u8) -> Self { Self { value: E::from_u8(value), error: E::ZERO } }
602 fn from_u16(value: u16) -> Self { Self { value: E::from_u16(value), error: E::ZERO } }
603}
604
605#[rustfmt::skip]
606impl<E: ScalarValue + SignedElement> SignedElement for Compensated<E> {
607 #[inline(always)]
608 fn abs(self) -> Self {
609 if self.value() < E::ZERO {
610 -self
611 } else {
612 self
613 }
614 }
615
616 #[inline(always)]
617 fn signum(self) -> Self {
618 Self::new(self.value().signum())
619 }
620}
621
622use core::marker::PhantomData;
623
624const fn two_sum_f64(a: f64, b: f64) -> (f64, f64) {
626 let s = a + b;
627 let v = s - a;
628 let e = (a - (s - v)) + (b - v);
629 (s, e)
630}
631
632const fn two_product_f64(a: f64, b: f64) -> (f64, f64) {
642 let p = a * b;
643 let c = f64::SPLITTER * a;
644 let a_hi = c - (c - a);
645 let a_lo = a - a_hi;
646 let c = f64::SPLITTER * b;
647 let b_hi = c - (c - b);
648 let b_lo = b - b_hi;
649 let e = ((a_hi * b_hi - p) + a_hi * b_lo + a_lo * b_hi) + a_lo * b_lo;
650 (p, e)
651}
652
653#[doc(hidden)]
656pub struct F32CompensatedIntConst<const N: LargeInt>;
657#[doc(hidden)]
658pub struct F32CompensatedRatioConst<const N: LargeInt, const D: LargeInt>;
659
660impl<const N: LargeInt> SplatConst<Compensated<f32>> for F32CompensatedIntConst<N> {
661 const VALUE: Compensated<f32> = {
662 let value = N as f32;
663 let error = (N as f64 - value as f64) as f32;
664 Compensated { value, error }
665 };
666}
667
668impl<const N: LargeInt, const D: LargeInt> SplatConst<Compensated<f32>> for F32CompensatedRatioConst<N, D> {
669 const VALUE: Compensated<f32> = {
670 assert!(D != 0, "CompensatedRatioConst: denominator must not be zero");
671 let (q, r) = (N / D, N % D);
672 let hi64 = (q as f64) + (r as f64) / (D as f64);
673 let value = hi64 as f32;
674 let error = (hi64 - value as f64) as f32;
675 Compensated { value, error }
676 };
677}
678
679#[doc(hidden)]
682pub struct F64CompensatedIntConst<const N: LargeInt>;
683#[doc(hidden)]
684pub struct F64CompensatedRatioConst<const N: LargeInt, const D: LargeInt>;
685
686impl<const N: LargeInt> SplatConst<Compensated<f64>> for F64CompensatedIntConst<N> {
687 const VALUE: Compensated<f64> = {
688 let value = N as f64;
691 let error = (N - value as LargeInt) as f64;
692 Compensated { value, error }
693 };
694}
695
696impl<const N: LargeInt, const D: LargeInt> SplatConst<Compensated<f64>> for F64CompensatedRatioConst<N, D> {
697 const VALUE: Compensated<f64> = {
698 assert!(D != 0, "CompensatedRatioConst: denominator must not be zero");
699 let (q, r) = (N / D, N % D);
700 let q_f64 = q as f64;
701 let r_f64 = r as f64;
702 let d_f64 = D as f64;
703
704 let frac = r_f64 / d_f64;
706
707 let (value, e_add) = two_sum_f64(q_f64, frac);
710
711 let (prod, e_prod) = two_product_f64(frac, d_f64);
714
715 let (diff, e_diff) = two_sum_f64(r_f64, -prod);
718 let frac_err = (diff + (e_diff - e_prod)) / d_f64;
719
720 let error = frac_err + e_add;
723
724 Compensated { value, error }
725 };
726}
727
728#[doc(hidden)]
732pub struct CompensatedVectorConst<Inner>(PhantomData<Inner>);
733
734#[doc(hidden)]
737pub struct CompensatedNewImpl;
738
739struct CompensatedValueConst<C, V>(PhantomData<(C, V)>);
740struct CompensatedErrorConst<C, V>(PhantomData<(C, V)>);
741
742impl<C, V: CompensatedFloatVector> NewConst<V::Element, V::Lanes> for CompensatedValueConst<C, V>
743where
744 C: NewConst<Compensated<V::Element>, V::Lanes>,
745{
746 const VALUES: GenericArray<V::Element, V::Lanes> = const {
747 let c_vals = C::VALUES;
748 let src = c_vals.as_slice();
749 let mut out: GenericArray<V::Element, V::Lanes> = unsafe { core::mem::zeroed() };
750 let dst = out.as_mut_slice();
751 let mut i = 0;
752 while i < V::LANES {
753 dst[i] = src[i].value;
754 i += 1;
755 }
756 core::mem::forget(c_vals);
757 out
758 };
759}
760
761impl<C, V: CompensatedFloatVector> NewConst<V::Element, V::Lanes> for CompensatedErrorConst<C, V>
762where
763 C: NewConst<Compensated<V::Element>, V::Lanes>,
764{
765 const VALUES: GenericArray<V::Element, V::Lanes> = const {
766 let c_vals = C::VALUES;
767 let src = c_vals.as_slice();
768 let mut out: GenericArray<V::Element, V::Lanes> = unsafe { core::mem::zeroed() };
769 let dst = out.as_mut_slice();
770 let mut i = 0;
771 while i < V::LANES {
772 dst[i] = src[i].error;
773 i += 1;
774 }
775 core::mem::forget(c_vals);
776 out
777 };
778}
779
780impl<T, V: CompensatedFloatVector> VectorValue<T, Compensated<V>> for CompensatedNewImpl
781where
782 T: NewConst<Compensated<V::Element>, V::Lanes>,
783{
784 const VALUE: Compensated<V> = Compensated {
785 value: <<V as NewVector<V::Element, V::Lanes>>::New<CompensatedValueConst<T, V>> as VectorValue<
786 CompensatedValueConst<T, V>,
787 V,
788 >>::VALUE,
789 error: <<V as NewVector<V::Element, V::Lanes>>::New<CompensatedErrorConst<T, V>> as VectorValue<
790 CompensatedErrorConst<T, V>,
791 V,
792 >>::VALUE,
793 };
794}
795
796impl<V: CompensatedFloatVector> NewVector<Compensated<V::Element>, V::Lanes> for Compensated<V> {
797 type New<T: NewConst<Compensated<V::Element>, V::Lanes>> = CompensatedNewImpl;
798}
799
800impl<V, Inner> SplatConst<Compensated<V>> for CompensatedVectorConst<Inner>
801where
802 V: CompensatedFloatVector,
803 Inner: SplatConst<Compensated<V::Element>>,
804{
805 const VALUE: Compensated<V> = <Compensated<V> as VectorValue<Inner, Compensated<V>>>::VALUE;
806}
807
808#[rustfmt::skip]
809impl<E: ScalarValue + FloatElement> FloatElement for Compensated<E> {
810 #[inline(always)]
811 fn sqrt(this: Self) -> Self {
812 let s = E::sqrt(this.value);
813
814 let (p, e) = E::square(s);
815
816 let (d_value, _) = E::two_diff(this.value, p);
819 let (d_error, _) = E::two_diff(this.error, e);
820 let remainder = d_value + d_error;
821
822 let corr = remainder / (s + s);
824
825 Self::renormalized(s, corr)
826 }
827
828 #[inline(always)] fn floor(this: Self) -> Self { Self::new(E::floor(this.value())) }
829 #[inline(always)] fn ceil(this: Self) -> Self { Self::new(E::ceil(this.value())) }
830 #[inline(always)] fn round(this: Self) -> Self { Self::new(E::round(this.value())) }
831 #[inline(always)] fn trunc(this: Self) -> Self { Self::new(E::trunc(this.value())) }
832
833 #[inline(always)] fn next_up(this: Self) -> Self { Self::renormalized(this.value, E::next_up(this.error)) }
835 #[inline(always)] fn next_down(this: Self) -> Self { Self::renormalized(this.value, E::next_down(this.error)) }
836
837 #[inline(always)]
839 fn try_from_int(value: LargeInt) -> Option<Self> {
840 E::try_from_int(value).map(|v| Self::new(v))
841 }
842
843 #[inline(always)]
844 fn try_from_ratio(n: LargeInt, d: LargeInt) -> Option<Self> {
845 if d == 0 {
846 return None;
847 }
848
849 let df = <E as FloatElement>::try_from_int(d)?;
850
851 if let Some(n) = <E as FloatElement>::try_from_int(n) {
853 return Some(Self::from_fraction(n, df));
854 }
855
856 let (q, r) = (n / d, n % d);
857
858 let mut result = Self::try_from_int(q)?;
859
860 if r != 0 {
861 let rf = <E as FloatElement>::try_from_int(r)?;
862
863 result += Self::from_fraction(rf, df);
864 }
865
866 Some(result)
867 }
868
869 const HAS_INFINITY: bool = E::HAS_INFINITY;
870 const HAS_SIGNED_ZERO: bool = E::HAS_SIGNED_ZERO;
871 const HAS_SUBNORMALS: bool = E::HAS_SUBNORMALS;
872
873 type ConstInt<const N: thermite::LargeInt> = E::CompensatedConstInt<N>;
874
875 type ConstRatio<const N: thermite::LargeInt, const D: thermite::LargeInt> = E::CompensatedConstRatio<N, D>;
876}
877
878#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)]
888#[repr(C)]
889pub struct Compensated<V> {
890 pub value: V,
891 pub error: V,
892}
893
894impl<V: ScalarValue> thermite::const_default::ConstDefault for Compensated<V> {
895 const DEFAULT: Self = Compensated {
896 value: V::SCALAR_ZERO,
897 error: V::SCALAR_ZERO,
898 };
899}
900
901impl<V: ScalarValue> Compensated<V> {
902 #[inline(always)]
904 pub const fn new(value: V) -> Self {
905 Self {
906 value,
907 error: V::SCALAR_ZERO,
908 }
909 }
910
911 #[inline(always)]
916 pub fn value(self) -> V {
917 V::two_sum(self.value, self.error).0
918 }
919
920 #[inline(always)]
922 pub const fn uncompensated(self) -> V {
923 self.value
924 }
925
926 #[inline(always)]
928 pub const fn error(self) -> V {
929 self.error
930 }
931
932 #[inline(always)]
939 pub(crate) fn renormalized(value: V, error: V) -> Self {
940 let (sum, err) = V::two_sum(value, error);
941 Self { value: sum, error: err }
942 }
943
944 #[inline(always)]
945 pub fn normalize(self) -> Self {
946 Self::renormalized(self.value, self.error)
947 }
948}
949
950impl<V: CompensatedFloatVector> Compensated<V> {
951 pub fn splat_value(value: V::Element) -> Self {
952 Self {
953 value: V::splat(value),
954 error: V::ZERO,
955 }
956 }
957}
958
959const ALLOW_UNNORMALIZED: bool = true;
961
962impl<V: ScalarValue> Compensated<V> {
963 #[inline(always)]
968 pub fn accumulate_unnormalized(&mut self, rhs: Self) {
969 if ALLOW_UNNORMALIZED {
970 let (s, e) = V::two_sum(self.value, rhs.value);
971 self.value = s;
972 let (t, _) = V::two_sum(e, rhs.error);
974 let (t, _) = V::two_sum(self.error, t);
975 self.error = t;
976 } else {
977 *self += rhs;
978 }
979 }
980
981 #[inline(always)]
986 pub fn reduce_unnormalized(&mut self, rhs: Self) {
987 if ALLOW_UNNORMALIZED {
988 let (s, e) = V::two_diff(self.value, rhs.value);
989 self.value = s;
990 let (d, _) = V::two_diff(self.error, rhs.error);
992 let (t, _) = V::two_sum(e, d);
993 self.error = t;
994 } else {
995 *self -= rhs;
996 }
997 }
998}
999
1000#[rustfmt::skip]
1001impl<V: ScalarValue> Neg for Compensated<V> {
1002 type Output = Self;
1003
1004 #[inline(always)]
1005 fn neg(self) -> Self::Output {
1006 Self { value: -self.value, error: -self.error }
1007 }
1008}
1009
1010impl<V: ScalarValue> Add<Self> for Compensated<V> {
1011 type Output = Self;
1012
1013 #[inline(always)]
1014 fn add(self, rhs: Self) -> Self::Output {
1015 let (s, e) = V::two_sum(self.value, rhs.value);
1016
1017 let (t, _) = V::two_sum(e, self.error);
1019 let (t, _) = V::two_sum(t, rhs.error);
1020
1021 Self::renormalized(s, t)
1022 }
1023}
1024
1025impl<V: ScalarValue> Add<V> for Compensated<V> {
1026 type Output = Self;
1027
1028 #[inline(always)]
1029 fn add(self, rhs: V) -> Self::Output {
1030 let (s, e) = V::two_sum(self.value, rhs);
1031 let (t, _) = V::two_sum(e, self.error);
1032 Self::renormalized(s, t)
1033 }
1034}
1035
1036impl<V: ScalarValue> Sub<Self> for Compensated<V> {
1037 type Output = Self;
1038
1039 #[inline(always)]
1040 fn sub(self, rhs: Self) -> Self::Output {
1041 let (s, e) = V::two_diff(self.value, rhs.value);
1042
1043 let (d, _) = V::two_diff(self.error, rhs.error);
1048
1049 Self::renormalized(s, e + d)
1050 }
1051}
1052
1053#[allow(clippy::suspicious_arithmetic_impl)]
1054impl<V: ScalarValue> Sub<V> for Compensated<V> {
1055 type Output = Self;
1056
1057 #[inline(always)]
1058 fn sub(self, rhs: V) -> Self::Output {
1059 let (s, e) = V::two_diff(self.value, rhs);
1060 let (t, _) = V::two_sum(e, self.error);
1061 Self::renormalized(s, t)
1062 }
1063}
1064
1065impl<V: ScalarValue> Square for Compensated<V> {
1066 type Output = Self;
1067
1068 #[inline(always)]
1069 fn square(self) -> Self {
1070 let (p, e) = V::square(self.value);
1071
1072 let d = V::two_prod(self.error, self.value).0;
1075 let (dd, _) = V::two_sum(d, d);
1076 let (t, _) = V::two_sum(dd, e);
1077
1078 Self::renormalized(p, t)
1079 }
1080}
1081
1082impl<V: CompensatedFloatVector> SquareMasked<V::Mask> for Compensated<V> {
1083 #[inline(always)]
1084 fn square_c(self, mask: V::Mask) -> Self::Output {
1085 mask.select(self.square(), self)
1086 }
1087
1088 #[inline(always)]
1089 fn square_m(self, src: Self, mask: V::Mask) -> Self::Output {
1090 mask.select(self.square(), src)
1091 }
1092
1093 #[inline(always)]
1094 fn square_z(self, mask: V::Mask) -> Self::Output {
1095 mask.select(self.square(), Self::ZERO)
1096 }
1097}
1098
1099impl<V: ScalarValue> Mul<Self> for Compensated<V> {
1100 type Output = Self;
1101
1102 #[inline(always)]
1103 fn mul(self, rhs: Self) -> Self::Output {
1104 let (p, e) = V::two_prod(self.value, rhs.value);
1105
1106 let e = self.error.mul_adde(rhs.value, self.value.mul_adde(rhs.error, e));
1107
1108 Self::renormalized(p, e)
1109 }
1110}
1111
1112impl<V: ScalarValue> Mul<V> for Compensated<V> {
1113 type Output = Self;
1114
1115 #[inline(always)]
1116 fn mul(self, rhs: V) -> Self {
1117 let (p, e1) = V::two_prod(self.value, rhs);
1119 Self::renormalized(p, self.error.mul_adde(rhs, e1))
1121 }
1122}
1123
1124impl<V: ScalarValue> Div<Self> for Compensated<V> {
1125 type Output = Self;
1126
1127 #[inline(always)]
1128 fn div(self, rhs: Self) -> Self {
1129 let q1 = V::two_quot(self.value, rhs.value).0;
1130
1131 let (p_hi, p_lo) = V::two_prod(q1, rhs.value);
1132
1133 let (r, _) = V::two_sum(
1139 division_remainder(self.value, p_hi, p_lo),
1140 q1.nmul_adde(rhs.error, self.error),
1141 );
1142
1143 Self::renormalized(q1, r / rhs.value)
1144 }
1145}
1146
1147impl<V: ScalarValue> Compensated<V> {
1148 pub fn div_scalar(num: V, denom: Self) -> Self {
1149 let q1 = V::two_quot(num, denom.value).0;
1150
1151 let (p_hi, p_lo) = V::two_prod(q1, denom.value);
1152
1153 let (r, _) = V::two_diff(division_remainder(num, p_hi, p_lo), V::two_prod(q1, denom.error).0);
1156
1157 Compensated::renormalized(q1, r / denom.value)
1158 }
1159}
1160
1161impl<V: ScalarValue> Compensated<V> {
1162 #[inline(always)]
1165 pub fn from_fraction(numerator: V, denominator: V) -> Self {
1166 let q1 = V::two_quot(numerator, denominator).0;
1167
1168 let (p_hi, p_lo) = V::two_prod(q1, denominator);
1169
1170 let r = division_remainder(numerator, p_hi, p_lo);
1172
1173 Self::renormalized(q1, r / denominator)
1174 }
1175}
1176
1177impl Compensated<f32> {
1178 #[inline(always)]
1181 pub const fn from_f64(v: f64) -> Self {
1182 let v_f32 = v as f32;
1183 let err = v - (v_f32 as f64);
1184 Self {
1185 value: v_f32,
1186 error: err as f32,
1187 }
1188 }
1189}
1190
1191#[inline(always)]
1202fn division_remainder<V: ScalarValue>(x: V, p_hi: V, p_lo: V) -> V {
1203 let (t, _) = V::two_diff(x, p_hi);
1204 let (t, _) = V::two_diff(t, p_lo);
1205 t
1206}
1207
1208impl<V: ScalarValue> Div<V> for Compensated<V> {
1209 type Output = Self;
1210
1211 #[inline(always)]
1212 fn div(self, rhs: V) -> Self {
1213 let q1 = V::two_quot(self.value, rhs).0;
1215
1216 let (p_hi, p_lo) = V::two_prod(q1, rhs);
1217
1218 let (r, _) = V::two_sum(division_remainder(self.value, p_hi, p_lo), self.error);
1223
1224 Self::renormalized(q1, r / rhs)
1225 }
1226}
1227
1228impl<V: ScalarValue> Rem<Self> for Compensated<V> {
1229 type Output = Self;
1230
1231 #[inline(always)]
1232 fn rem(self, rhs: Self) -> Self {
1233 let q = self / rhs;
1234 let n = Compensated::new(-q.value.scalar_trunc());
1235 rhs.mul_add(n, self)
1236 }
1237}
1238
1239impl<V: ScalarValue> Rem<V> for Compensated<V> {
1240 type Output = Self;
1241
1242 #[inline(always)]
1243 fn rem(self, rhs: V) -> Self {
1244 let q = self / rhs;
1245 let n = Compensated::new(-q.value.scalar_trunc());
1246 MulAddExt::mul_add(n, rhs, self)
1247 }
1248}
1249
1250#[rustfmt::skip]
1251impl<V: ScalarValue> MulAddExt<Self, Self> for Compensated<V> {
1252 type Output = Self;
1253
1254 const HAS_NATIVE_FMA: Tribool = tribool::True;
1257
1258 #[inline(always)]
1259 fn mul_add(self, b: Self, c: Self) -> Self {
1260 let (p, e_prod_base) = V::two_prod(self.value, b.value);
1261 let (s, e_sum) = V::two_sum(p, c.value);
1262
1263 let e_prod = self.error.mul_adde(b.value, self.value.mul_adde(b.error, V::two_sum(e_prod_base, e_sum).0));
1264
1265 Self::renormalized(s, V::two_sum(e_prod, c.error).0)
1266 }
1267
1268 #[inline(always)]
1269 fn mul_sub(self, b: Self, c: Self) -> Self::Output {
1270 let (p, e_prod_base) = V::two_prod(self.value, b.value);
1271 let (s, e_diff) = V::two_diff(p, c.value);
1272
1273 let e_prod = self.error.mul_adde(b.value, self.value.mul_adde(b.error, V::two_sum(e_prod_base, e_diff).0));
1274
1275 Self::renormalized(s, V::two_diff(e_prod, c.error).0)
1278 }
1279
1280 #[inline(always)] fn nmul_add(self, a: Self, b: Self) -> Self::Output { self.mul_add(-a, b) }
1281 #[inline(always)] fn nmul_sub(self, a: Self, b: Self) -> Self::Output { self.mul_sub(-a, b) }
1282 #[inline(always)] fn mul_adde(self, a: Self, b: Self) -> Self::Output { self.mul_add(a, b) }
1283 #[inline(always)] fn mul_sube(self, a: Self, b: Self) -> Self::Output { self.mul_sub(a, b) }
1284 #[inline(always)] fn nmul_adde(self, a: Self, b: Self) -> Self::Output { self.nmul_add(a, b) }
1285 #[inline(always)] fn nmul_sube(self, a: Self, b: Self) -> Self::Output { self.nmul_sub(a, b) }
1286}
1287
1288#[rustfmt::skip]
1289impl<V: ScalarValue> MulAddExt<V, Self> for Compensated<V> {
1290 type Output = Self;
1291
1292 const HAS_NATIVE_FMA: Tribool = tribool::True;
1293
1294 #[inline(always)]
1295 fn mul_add(self, b: V, c: Self) -> Self::Output {
1296 let (p, e_prod_base) = V::two_prod(self.value, b);
1297 let (s, e_sum) = V::two_sum(p, c.value);
1298
1299 let e_prod = self.error.mul_adde(b, V::two_sum(e_prod_base, e_sum).0);
1300
1301 Self::renormalized(s, V::two_sum(e_prod, c.error).0)
1302 }
1303
1304 #[inline(always)]
1305 fn mul_sub(self, b: V, c: Self) -> Self::Output {
1306 let (p, e_prod_base) = V::two_prod(self.value, b);
1307 let (s, e_diff) = V::two_diff(p, c.value);
1308
1309 let e_prod = self.error.mul_adde(b, V::two_sum(e_prod_base, e_diff).0);
1310
1311 Self::renormalized(s, V::two_diff(e_prod, c.error).0)
1312 }
1313
1314 #[inline(always)] fn nmul_add(self, a: V, b: Self) -> Self::Output { self.mul_add(-a, b) }
1315 #[inline(always)] fn nmul_sub(self, a: V, b: Self) -> Self::Output { self.mul_sub(-a, b) }
1316 #[inline(always)] fn mul_adde(self, a: V, b: Self) -> Self::Output { self.mul_add(a, b) }
1317 #[inline(always)] fn mul_sube(self, a: V, b: Self) -> Self::Output { self.mul_sub(a, b) }
1318 #[inline(always)] fn nmul_adde(self, a: V, b: Self) -> Self::Output { self.nmul_add(a, b) }
1319 #[inline(always)] fn nmul_sube(self, a: V, b: Self) -> Self::Output { self.nmul_sub(a, b) }
1320}
1321
1322#[rustfmt::skip]
1323impl<V: ScalarValue> MulAddExt<Self, V> for Compensated<V> {
1324 type Output = Self;
1325
1326 const HAS_NATIVE_FMA: Tribool = tribool::True;
1327
1328 #[inline(always)]
1329 fn mul_add(self, a: Self, b: V) -> Self::Output {
1330 let (p, e_prod_base) = V::two_prod(self.value, a.value);
1331 let (s, e_sum) = V::two_sum(p, b);
1332
1333 let e_prod = self.error.mul_adde(a.value, self.value.mul_adde(a.error, V::two_sum(e_prod_base, e_sum).0));
1337
1338 Self::renormalized(s, e_prod)
1339 }
1340
1341 #[inline(always)]
1342 fn mul_sub(self, b: Self, c: V) -> Self::Output {
1343 let (p, e_prod_base) = V::two_prod(self.value, b.value);
1344 let (s, e_diff) = V::two_diff(p, c);
1345
1346 let e_prod = self.error.mul_adde(b.value, self.value.mul_adde(b.error, V::two_sum(e_prod_base, e_diff).0));
1347
1348 Self::renormalized(s, e_prod)
1349 }
1350
1351 #[inline(always)] fn nmul_add(self, a: Self, b: V) -> Self::Output { self.mul_add(-a, b) }
1352 #[inline(always)] fn nmul_sub(self, a: Self, b: V) -> Self::Output { self.mul_sub(-a, b) }
1353 #[inline(always)] fn mul_adde(self, a: Self, b: V) -> Self::Output { self.mul_add(a, b) }
1354 #[inline(always)] fn mul_sube(self, a: Self, b: V) -> Self::Output { self.mul_sub(a, b) }
1355 #[inline(always)] fn nmul_adde(self, a: Self, b: V) -> Self::Output { self.nmul_add(a, b) }
1356 #[inline(always)] fn nmul_sube(self, a: Self, b: V) -> Self::Output { self.nmul_sub(a, b) }
1357}
1358
1359impl<V: Copy, T> AddAssign<T> for Compensated<V>
1360where
1361 Self: Add<T, Output = Self>,
1362{
1363 #[inline(always)]
1364 fn add_assign(&mut self, rhs: T) {
1365 *self = *self + rhs;
1366 }
1367}
1368
1369impl<V: Copy, T> SubAssign<T> for Compensated<V>
1370where
1371 Self: Sub<T, Output = Self>,
1372{
1373 #[inline(always)]
1374 fn sub_assign(&mut self, rhs: T) {
1375 *self = *self - rhs;
1376 }
1377}
1378
1379impl<V: Copy, T> MulAssign<T> for Compensated<V>
1380where
1381 Self: Mul<T, Output = Self>,
1382{
1383 #[inline(always)]
1384 fn mul_assign(&mut self, rhs: T) {
1385 *self = *self * rhs;
1386 }
1387}
1388
1389impl<V: Copy, T> DivAssign<T> for Compensated<V>
1390where
1391 Self: Div<T, Output = Self>,
1392{
1393 #[inline(always)]
1394 fn div_assign(&mut self, rhs: T) {
1395 *self = *self / rhs;
1396 }
1397}
1398
1399impl<V: Copy, T> RemAssign<T> for Compensated<V>
1400where
1401 Self: Rem<T, Output = Self>,
1402{
1403 #[inline(always)]
1404 fn rem_assign(&mut self, rhs: T) {
1405 *self = *self % rhs;
1406 }
1407}
1408
1409#[rustfmt::skip]
1410impl<V: Copy, A, B> MulAddAssignExt<A, B> for Compensated<V>
1411where
1412 Self: MulAddExt<A, B, Output = Self>,
1413{
1414 #[inline(always)] fn mul_add_assign(&mut self, a: A, b: B) { *self = self.mul_add(a, b); }
1415 #[inline(always)] fn mul_sub_assign(&mut self, a: A, b: B) { *self = self.mul_sub(a, b); }
1416 #[inline(always)] fn nmul_add_assign(&mut self, a: A, b: B) { *self = self.nmul_add(a, b); }
1417 #[inline(always)] fn nmul_sub_assign(&mut self, a: A, b: B) { *self = self.nmul_sub(a, b); }
1418 #[inline(always)] fn mul_adde_assign(&mut self, a: A, b: B) { *self = self.mul_adde(a, b); }
1419 #[inline(always)] fn mul_sube_assign(&mut self, a: A, b: B) { *self = self.mul_sube(a, b); }
1420 #[inline(always)] fn nmul_adde_assign(&mut self, a: A, b: B) { *self = self.nmul_adde(a, b); }
1421 #[inline(always)] fn nmul_sube_assign(&mut self, a: A, b: B) { *self = self.nmul_sube(a, b); }
1422}
1423
1424macro_rules! impl_masked {
1425 (MUL_ADD: $($method:ident),*) => {paste::paste! {
1426 impl<V: CompensatedFloatVector, A, B> thermite::vector::ops::MulAddExtMasked<V::Mask, A, B> for Compensated<V>
1427 where
1428 Compensated<V>: MulAddExt<A, B, Output = Self>,
1429 {
1430 $(
1431 #[inline(always)]
1432 fn [<$method _c>](self, mask: V::Mask, a: A, b: B) -> Self {
1433 mask.select(self.[<$method>](a, b), self)
1434 }
1435
1436 #[inline(always)]
1437 fn [<$method _m>](self, src: Self, mask: V::Mask, a: A, b: B) -> Self {
1438 mask.select(self.[<$method>](a, b), src)
1439 }
1440
1441 #[inline(always)]
1442 fn [<$method _z>](self, mask: V::Mask, a: A, b: B) -> Self {
1443 mask.select(self.[<$method>](a, b), Self::EMPTY)
1444 }
1445 )*
1446 }
1447
1448 impl<V: CompensatedFloatVector, A, B> thermite::vector::ops::MulAddAssignExtMasked<V::Mask, A, B> for Compensated<V>
1449 where
1450 Compensated<V>: MulAddExt<A, B, Output = Self>,
1451 {
1452 $(
1453 #[inline(always)]
1454 fn [<$method _assign_c>](&mut self, mask: V::Mask, a: A, b: B) {
1455 *self = mask.select(self.[<$method>](a, b), *self);
1456 }
1457
1458 #[inline(always)]
1459 fn [<$method _assign_m>](&mut self, src: Self, mask: V::Mask, a: A, b: B) {
1460 *self = mask.select(self.[<$method>](a, b), src);
1461 }
1462
1463 #[inline(always)]
1464 fn [<$method _assign_z>](&mut self, mask: V::Mask, a: A, b: B) {
1465 *self = mask.select(self.[<$method>](a, b), Self::EMPTY);
1466 }
1467 )*
1468 }
1469 }};
1470
1471 ($trait:ident::$method:ident) => {paste::paste! {
1472 impl<V: CompensatedFloatVector, Rhs> thermite::vector::ops::[<$trait Masked>]<V::Mask, Rhs> for Compensated<V>
1473 where
1474 Compensated<V>: $trait<Rhs, Output = Self>,
1475 {
1476 #[inline(always)]
1477 fn [<$method _c>](self, mask: V::Mask, rhs: Rhs) -> Self {
1478 mask.select(self.$method(rhs), self)
1479 }
1480
1481 #[inline(always)]
1482 fn [<$method _m>](self, src: Self, mask: V::Mask, rhs: Rhs) -> Self {
1483 mask.select(self.$method(rhs), src)
1484 }
1485
1486 #[inline(always)]
1487 fn [<$method _z>](self, mask: V::Mask, rhs: Rhs) -> Self {
1488 mask.select(self.$method(rhs), Self::EMPTY)
1489 }
1490 }
1491
1492 impl<V: CompensatedFloatVector, Rhs> thermite::vector::ops::[<$trait AssignMasked>]<V::Mask, Rhs> for Compensated<V>
1493 where
1494 Compensated<V>: $trait<Rhs, Output = Self>,
1495 {
1496 #[inline(always)]
1497 fn [<$method _assign_c>](&mut self, mask: V::Mask, rhs: Rhs) {
1498 *self = mask.select(self.$method(rhs), *self);
1499 }
1500
1501 #[inline(always)]
1502 fn [<$method _assign_m>](&mut self, src: Self, mask: V::Mask, rhs: Rhs) {
1503 *self = mask.select(self.$method(rhs), src);
1504 }
1505
1506 #[inline(always)]
1507 fn [<$method _assign_z>](&mut self, mask: V::Mask, rhs: Rhs) {
1508 *self = mask.select(self.$method(rhs), Self::EMPTY);
1509 }
1510 }
1511 }};
1512}
1513
1514impl_masked!(MUL_ADD: mul_add, mul_sub, nmul_add, nmul_sub, mul_adde, mul_sube, nmul_adde, nmul_sube);
1515impl_masked!(Add::add);
1516impl_masked!(Sub::sub);
1517impl_masked!(Mul::mul);
1518impl_masked!(Div::div);
1519impl_masked!(Rem::rem);
1520
1521#[inline(always)]
1532fn neg_even_compensated<V: CompensatedFloatVector>(x: Compensated<V>) -> Compensated<V> {
1533 Compensated {
1535 value: V::ZERO.addsub(x.value),
1536 error: V::ZERO.addsub(x.error),
1537 }
1538}
1539
1540impl<V: CompensatedFloatVector> AddSubExt for Compensated<V> {
1541 type Output = Self;
1542
1543 #[inline(always)]
1544 fn addsub(self, b: Self) -> Self {
1545 self + neg_even_compensated(b)
1546 }
1547 #[inline(always)]
1548 fn fmaddsub(self, b: Self, c: Self) -> Self {
1549 self.mul_adde(b, neg_even_compensated(c))
1550 }
1551 #[inline(always)]
1552 fn fmsubadd(self, b: Self, c: Self) -> Self {
1553 self.mul_sube(b, neg_even_compensated(c))
1554 }
1555}
1556
1557impl<V: CompensatedFloatVector> AddSubExtMasked<V::Mask> for Compensated<V> {
1558 #[inline(always)]
1559 fn addsub_c(self, mask: V::Mask, b: Self) -> Self {
1560 mask.select(self.addsub(b), self)
1561 }
1562 #[inline(always)]
1563 fn addsub_m(self, src: Self, mask: V::Mask, b: Self) -> Self {
1564 mask.select(self.addsub(b), src)
1565 }
1566 #[inline(always)]
1567 fn addsub_z(self, mask: V::Mask, b: Self) -> Self {
1568 mask.select(self.addsub(b), Self::EMPTY)
1569 }
1570
1571 #[inline(always)]
1572 fn fmaddsub_c(self, mask: V::Mask, b: Self, c: Self) -> Self {
1573 mask.select(self.fmaddsub(b, c), self)
1574 }
1575 #[inline(always)]
1576 fn fmaddsub_m(self, src: Self, mask: V::Mask, b: Self, c: Self) -> Self {
1577 mask.select(self.fmaddsub(b, c), src)
1578 }
1579 #[inline(always)]
1580 fn fmaddsub_z(self, mask: V::Mask, b: Self, c: Self) -> Self {
1581 mask.select(self.fmaddsub(b, c), Self::EMPTY)
1582 }
1583
1584 #[inline(always)]
1585 fn fmsubadd_c(self, mask: V::Mask, b: Self, c: Self) -> Self {
1586 mask.select(self.fmsubadd(b, c), self)
1587 }
1588 #[inline(always)]
1589 fn fmsubadd_m(self, src: Self, mask: V::Mask, b: Self, c: Self) -> Self {
1590 mask.select(self.fmsubadd(b, c), src)
1591 }
1592 #[inline(always)]
1593 fn fmsubadd_z(self, mask: V::Mask, b: Self, c: Self) -> Self {
1594 mask.select(self.fmsubadd(b, c), Self::EMPTY)
1595 }
1596}
1597
1598macro_rules! compensated_masked {
1603 (unary: $($m:ident),* $(,)?) => { paste::paste! {
1604 $(
1605 #[inline(always)] fn [<$m _c>](self, mask: Self::Mask) -> Self { mask.select(self.$m(), self) }
1606 #[inline(always)] fn [<$m _m>](self, src: Self, mask: Self::Mask) -> Self { mask.select(self.$m(), src) }
1607 #[inline(always)] fn [<$m _z>](self, mask: Self::Mask) -> Self { mask.select(self.$m(), Self::EMPTY) }
1608 )*
1609 }};
1610 (binary: $($m:ident),* $(,)?) => { paste::paste! {
1611 $(
1612 #[inline(always)] fn [<$m _c>](self, mask: Self::Mask, rhs: Self) -> Self { mask.select(self.$m(rhs), self) }
1613 #[inline(always)] fn [<$m _m>](self, src: Self, mask: Self::Mask, rhs: Self) -> Self { mask.select(self.$m(rhs), src) }
1614 #[inline(always)] fn [<$m _z>](self, mask: Self::Mask, rhs: Self) -> Self { mask.select(self.$m(rhs), Self::EMPTY) }
1615 )*
1616 }};
1617}
1618
1619impl<V: CompensatedFloatVector> GenericSelectable for Compensated<V> {
1620 type SelectableMask = <V as GenericSelectable>::SelectableMask;
1621
1622 #[inline(always)]
1623 fn select<M>(mask: M, t: Self, f: Self) -> Self
1624 where
1625 Self::SelectableMask: CastMask<M>,
1626 {
1627 let mask = <Self::SelectableMask as CastMask<M>>::mask_from(mask);
1628
1629 Self {
1630 value: mask.select(t.value, f.value),
1631 error: mask.select(t.error, f.error),
1632 }
1633 }
1634}
1635
1636impl<V: thermite::simd::HasIsa> thermite::simd::HasIsa for Compensated<V> {
1637 type Native = V::Native;
1638
1639 const ISA: thermite::isa::InstructionSet = V::ISA;
1640}
1641
1642impl<V: CompensatedFloatVector> SplatVector<Compensated<V::Element>> for Compensated<V> {
1643 type Splat<T: SplatConst<Compensated<V::Element>>> = Self;
1644}
1645
1646#[rustfmt::skip]
1647impl<V: CompensatedFloatVector, E: SplatConst<Compensated<V::Element>>> VectorValue<E, Compensated<V>> for Compensated<V> {
1648 const VALUE: Compensated<V> = const {
1649 struct Value<V: CompensatedFloatVector, E: SplatConst<Compensated<V::Element>>>(core::marker::PhantomData<(V, E)>);
1650 struct Error<V: CompensatedFloatVector, E: SplatConst<Compensated<V::Element>>>(core::marker::PhantomData<(V, E)>);
1651
1652 impl<V: CompensatedFloatVector, E: SplatConst<Compensated<V::Element>>> SplatConst<V::Element> for Value<V, E> {
1653 const VALUE: V::Element = <E as SplatConst<Compensated<V::Element>>>::VALUE.value;
1654 }
1655
1656 impl<V: CompensatedFloatVector, E: SplatConst<Compensated<V::Element>>> SplatConst<V::Element> for Error<V, E> {
1657 const VALUE: V::Element = <E as SplatConst<Compensated<V::Element>>>::VALUE.error;
1658 }
1659
1660 Compensated {
1661 value: thermite::vector::const_splat::<V, Value<V, E>>(),
1662 error: thermite::vector::const_splat::<V, Error<V, E>>(),
1663 }
1664 };
1665}
1666
1667#[rustfmt::skip]
1668impl<V: CompensatedFloatVector> thermite::sort::SortKey<Self> for Compensated<V> {
1672 #[inline(always)]
1673 fn key_lt(a: Self, b: Self) -> V::Mask {
1674 a.cmp_lt(b)
1675 }
1676}
1677
1678#[inline(always)]
1682fn sort_lanes_scalar<V: NumericVector, O: thermite::sort::SortOrder>(v: V) -> V
1683where
1684 V::Element: PartialOrd,
1685{
1686 let mut out = v;
1687 let mut i = 1;
1688 while i < V::LANES {
1689 let key = out.extractv(i);
1690 let mut j = i;
1691 while j > 0 {
1692 let prev = out.extractv(j - 1);
1693 let misplaced = if O::IS_ASCENDING { prev > key } else { prev < key };
1694 if !misplaced {
1695 break;
1696 }
1697 out = out.insertv(j, prev);
1698 j -= 1;
1699 }
1700 out = out.insertv(j, key);
1701 i += 1;
1702 }
1703 out
1704}
1705
1706impl<V: CompensatedFloatVector> Interleave for Compensated<V> {
1707 #[inline(always)]
1708 fn interleave(self, other: Self) -> (Self, Self) {
1709 let (value_lo, value_hi) = self.value.interleave(other.value);
1710 let (error_lo, error_hi) = self.error.interleave(other.error);
1711
1712 (
1713 Self {
1714 value: value_lo,
1715 error: error_lo,
1716 },
1717 Self {
1718 value: value_hi,
1719 error: error_hi,
1720 },
1721 )
1722 }
1723
1724 #[inline(always)]
1725 fn deinterleave(self, other: Self) -> (Self, Self) {
1726 let (value_lo, value_hi) = self.value.deinterleave(other.value);
1727 let (error_lo, error_hi) = self.error.deinterleave(other.error);
1728
1729 (
1730 Self {
1731 value: value_lo,
1732 error: error_lo,
1733 },
1734 Self {
1735 value: value_hi,
1736 error: error_hi,
1737 },
1738 )
1739 }
1740}
1741
1742#[rustfmt::skip]
1743impl<V: CompensatedFloatVector> GenericVector for Compensated<V> {
1744 #[inline(always)]
1747 #[track_caller]
1748 fn _loop_hint() {
1749 V::_loop_hint()
1750 }
1751
1752 #[inline(always)]
1753 #[track_caller]
1754 fn _enter(name: &'static str) -> u32 {
1755 V::_enter_tagged("Compensated", name)
1756 }
1757
1758 #[inline(always)]
1759 #[track_caller]
1760 fn _enter_tagged(tag: &'static str, name: &'static str) -> u32 {
1761 V::_enter_tagged(tag, name)
1762 }
1763
1764 #[inline(always)]
1765 #[track_caller]
1766 fn _exit(token: u32) {
1767 V::_exit(token)
1768 }
1769
1770 #[inline(always)]
1771 #[track_caller]
1772 fn _region_arg(mut self, token: u32) -> Self {
1773 self.value = self.value._region_arg(token);
1774 self.error = self.error._region_arg(token);
1775 self
1776 }
1777
1778 #[inline(always)]
1779 #[track_caller]
1780 fn _region_result(mut self, token: u32) -> Self {
1781 self.value = self.value._region_result(token);
1782 self.error = self.error._region_result(token);
1783 self
1784 }
1785
1786 #[inline(always)]
1787 #[track_caller]
1788 fn _region_imm(token: u32, imm: core::fmt::Arguments) {
1789 V::_region_imm(token, imm)
1790 }
1791
1792 type Element = Compensated<V::Element>;
1793
1794 const EMPTY: Self = Self::new(V::ZERO);
1795 const LANES: usize = V::LANES;
1796
1797 type Lanes = V::Lanes;
1798
1799 type Unsigned = V::Unsigned;
1800 type Signed = V::Signed;
1801
1802 type Mask = V::Mask;
1803
1804 #[inline(always)]
1807 fn permutev(self, indices: Self::Unsigned) -> Self {
1808 Self {
1809 value: self.value.permutev(indices),
1810 error: self.error.permutev(indices),
1811 }
1812 }
1813
1814 #[inline(always)]
1815 fn swizzle(self, other: Self, indices: Self::Unsigned) -> Self {
1816 Self {
1817 value: self.value.swizzle(other.value, indices),
1818 error: self.error.swizzle(other.error, indices),
1819 }
1820 }
1821
1822 #[inline(always)]
1823 fn new<const N: usize>(value: [Self::Element; N]) -> Self
1824 where
1825 thermite::generic_array::typenum::Const<N>: thermite::generic_array::IntoArrayLength<ArrayLength = Self::Lanes>
1826 {
1827 Compensated {
1828 value: V::new(value.map(|c| c.value)),
1829 error: V::new(value.map(|c| c.error)),
1830 }
1831 }
1832
1833 #[inline(always)]
1834 fn into_array(self) -> GenericArray<Self::Element, Self::Lanes> {
1835 let mut arr = GenericArray::default();
1836
1837 for i in 0..Self::LANES {
1838 arr[i] = Compensated {
1839 value: self.value.extractv(i),
1840 error: self.error.extractv(i),
1841 };
1842 }
1843
1844 arr
1845 }
1846
1847 #[inline(always)]
1848 fn splat(value: Self::Element) -> Self {
1849 Self {
1850 value: V::splat(value.value),
1851 error: V::splat(value.error),
1852 }
1853 }
1854
1855 #[inline(always)]
1856 fn single(value: Self::Element) -> Self {
1857 Self::new(V::single(value.value))
1858 }
1859
1860 #[inline(always)]
1861 unsafe fn load(ptr: *const Self::Element) -> Self {
1862 let ptr = ptr as *const V::Element;
1863 let a = unsafe { V::load(ptr) };
1864 let b = unsafe { V::load(ptr.add(V::LANES)) };
1865 let (value, error) = a.deinterleave(b);
1866 Self { value, error }
1867 }
1868
1869 #[inline(always)]
1870 fn interleave_by<const GROUP: usize>(self, other: Self) -> (Self, Self) {
1871 let (value_lo, value_hi) = self.value.interleave_by::<GROUP>(other.value);
1872 let (error_lo, error_hi) = self.error.interleave_by::<GROUP>(other.error);
1873 (Self { value: value_lo, error: error_lo }, Self { value: value_hi, error: error_hi })
1874 }
1875
1876 #[inline(always)]
1877 fn deinterleave_by<const GROUP: usize>(self, other: Self) -> (Self, Self) {
1878 let (value_lo, value_hi) = self.value.deinterleave_by::<GROUP>(other.value);
1879 let (error_lo, error_hi) = self.error.deinterleave_by::<GROUP>(other.error);
1880 (Self { value: value_lo, error: error_lo }, Self { value: value_hi, error: error_hi })
1881 }
1882
1883 #[inline(always)]
1884 fn interleave_radix<const N: usize>(inputs: [Self; N]) -> [Self; N] {
1885 let (mut value, mut error) = ([V::EMPTY; N], [V::EMPTY; N]);
1886 for i in 0..N {
1887 value[i] = inputs[i].value;
1888 error[i] = inputs[i].error;
1889 }
1890 let value = V::interleave_radix::<N>(value);
1891 let error = V::interleave_radix::<N>(error);
1892 let mut out = [Self::EMPTY; N];
1893 for i in 0..N {
1894 out[i] = Self { value: value[i], error: error[i] };
1895 }
1896 out
1897 }
1898
1899 #[inline(always)]
1900 fn deinterleave_radix<const N: usize>(inputs: [Self; N]) -> [Self; N] {
1901 let (mut value, mut error) = ([V::EMPTY; N], [V::EMPTY; N]);
1902 for i in 0..N {
1903 value[i] = inputs[i].value;
1904 error[i] = inputs[i].error;
1905 }
1906 let value = V::deinterleave_radix::<N>(value);
1907 let error = V::deinterleave_radix::<N>(error);
1908 let mut out = [Self::EMPTY; N];
1909 for i in 0..N {
1910 out[i] = Self { value: value[i], error: error[i] };
1911 }
1912 out
1913 }
1914
1915 #[inline(always)]
1916 fn deinterleave_radix_by<const N: usize, const GROUP: usize>(inputs: [Self; N]) -> [Self; N] {
1917 let (mut value, mut error) = ([V::EMPTY; N], [V::EMPTY; N]);
1918 for i in 0..N {
1919 value[i] = inputs[i].value;
1920 error[i] = inputs[i].error;
1921 }
1922 let value = V::deinterleave_radix_by::<N, GROUP>(value);
1923 let error = V::deinterleave_radix_by::<N, GROUP>(error);
1924 let mut out = [Self::EMPTY; N];
1925 for i in 0..N {
1926 out[i] = Self { value: value[i], error: error[i] };
1927 }
1928 out
1929 }
1930
1931 #[inline(always)]
1932 fn interleave_radix_by<const N: usize, const GROUP: usize>(inputs: [Self; N]) -> [Self; N] {
1933 let (mut value, mut error) = ([V::EMPTY; N], [V::EMPTY; N]);
1934 for i in 0..N {
1935 value[i] = inputs[i].value;
1936 error[i] = inputs[i].error;
1937 }
1938 let value = V::interleave_radix_by::<N, GROUP>(value);
1939 let error = V::interleave_radix_by::<N, GROUP>(error);
1940 let mut out = [Self::EMPTY; N];
1941 for i in 0..N {
1942 out[i] = Self { value: value[i], error: error[i] };
1943 }
1944 out
1945 }
1946
1947 #[inline(always)]
1955 unsafe fn load_deinterleaved<const M: usize>(ptr: *const Self::Element) -> [Self; M] {
1956 let groups = unsafe { V::load_deinterleaved_grouped::<M, 1>(ptr as *const V::Element) };
1957
1958 let mut out = [<Compensated<V> as GenericVector>::EMPTY; M];
1959 let mut j = 0;
1960 while j < M {
1961 out[j] = Compensated { value: groups[j].head, error: groups[j].tail[0] };
1962 j += 1;
1963 }
1964 out
1965 }
1966
1967 #[inline(always)]
1969 unsafe fn store_interleaved<const M: usize>(ptr: *mut Self::Element, values: [Self; M]) {
1970 let mut groups = [StreamGroup { head: V::ZERO, tail: [V::ZERO; 1] }; M];
1971 let mut j = 0;
1972 while j < M {
1973 groups[j] = StreamGroup { head: values[j].value, tail: [values[j].error] };
1974 j += 1;
1975 }
1976 unsafe { V::store_interleaved_grouped::<M, 1>(ptr as *mut V::Element, groups) }
1977 }
1978
1979 #[inline(always)]
1980 unsafe fn load_m(src: Self, mask: Self::Mask, ptr: *const Self::Element) -> Self {
1981 let ptr = ptr as *const V::Element;
1982 let (a_mask, b_mask) = mask.interleave(mask);
1985 let (src_a, src_b) = src.value.interleave(src.error);
1986 let a = unsafe { V::load_m(src_a, a_mask, ptr) };
1987 let b = unsafe { V::load_m(src_b, b_mask, ptr.add(V::LANES)) };
1988 let (value, error) = a.deinterleave(b);
1989 Self { value, error }
1990 }
1991
1992 #[inline(always)]
1993 unsafe fn load_z(mask: Self::Mask, ptr: *const Self::Element) -> Self {
1994 let ptr = ptr as *const V::Element;
1995 let (a_mask, b_mask) = mask.interleave(mask);
1997 let a = unsafe { V::load_z(a_mask, ptr) };
1998 let b = unsafe { V::load_z(b_mask, ptr.add(V::LANES)) };
1999 let (value, error) = a.deinterleave(b);
2000 Self { value, error }
2001 }
2002
2003 #[inline(always)]
2004 unsafe fn load_unaligned(ptr: *const Self::Element) -> Self {
2005 let ptr = ptr as *const V::Element;
2006 let a = unsafe { V::load_unaligned(ptr) };
2007 let b = unsafe { V::load_unaligned(ptr.add(V::LANES)) };
2008 let (value, error) = a.deinterleave(b);
2009 Self { value, error }
2010 }
2011
2012 #[inline(always)]
2013 unsafe fn load_streaming(ptr: *const Self::Element) -> Self {
2014 let ptr = ptr as *const V::Element;
2015 let a = unsafe { V::load_streaming(ptr) };
2016 let b = unsafe { V::load_streaming(ptr.add(V::LANES)) };
2017 let (value, error) = a.deinterleave(b);
2018 Self { value, error }
2019 }
2020
2021 #[inline(always)]
2022 unsafe fn store(self, ptr: *mut Self::Element) {
2023 let ptr = ptr as *mut V::Element;
2024 let (a, b) = self.value.interleave(self.error);
2025 unsafe {
2026 a.store(ptr);
2027 b.store(ptr.add(V::LANES));
2028 }
2029 }
2030
2031 #[inline(always)]
2032 unsafe fn store_masked(self, mask: Self::Mask, ptr: *mut Self::Element) {
2033 let ptr = ptr as *mut V::Element;
2034 let (a_mask, b_mask) = mask.interleave(mask);
2036 let (a, b) = self.value.interleave(self.error);
2037 unsafe {
2038 a.store_masked(a_mask, ptr);
2039 b.store_masked(b_mask, ptr.add(V::LANES));
2040 }
2041 }
2042
2043 #[inline(always)]
2044 unsafe fn store_unaligned(self, ptr: *mut Self::Element) {
2045 let ptr = ptr as *mut V::Element;
2046 let (a, b) = self.value.interleave(self.error);
2047 unsafe {
2048 a.store_unaligned(ptr);
2049 b.store_unaligned(ptr.add(V::LANES));
2050 }
2051 }
2052
2053 #[inline(always)]
2054 unsafe fn store_streaming(self, ptr: *mut Self::Element) {
2055 let ptr = ptr as *mut V::Element;
2056 let (a, b) = self.value.interleave(self.error);
2057 unsafe {
2058 a.store_streaming(ptr);
2059 b.store_streaming(ptr.add(V::LANES));
2060 }
2061 }
2062
2063 #[inline(always)]
2064 unsafe fn lookup_unchecked(values: &[Self::Element], indices: Self::Unsigned) -> Self {
2065 if values.len() > Self::LANES * 2 {
2066 let mut res = Self::EMPTY;
2068
2069 for i in 0..Self::LANES {
2070 let Ok(idx) = indices.extractv(i).try_into() else {
2071 panic!("Index out of bounds for usize");
2072 };
2073
2074 res = res.insertv(i, values[idx]);
2075 }
2076
2077 return res;
2078 }
2079
2080 let values = unsafe {
2081 core::slice::from_raw_parts(values.as_ptr() as *const V::Element, values.len() * 2)
2082 };
2083
2084 let value_idx = indices << 1;
2085 let error_idx = value_idx + Self::Unsigned::ONE;
2086
2087 let value = unsafe { V::lookup_unchecked(values, value_idx) };
2088 let error = unsafe { V::lookup_unchecked(values, error_idx) };
2089
2090 Self { value, error }
2091 }
2092
2093 #[inline(always)]
2094 fn broadcast<const I: usize>(self) -> Self {
2095 Self {
2096 value: V::broadcast::<I>(self.value),
2097 error: V::broadcast::<I>(self.error),
2098 }
2099 }
2100
2101 #[inline(always)]
2102 fn broadcastv(self, idx: usize) -> Self {
2103 Self {
2104 value: V::broadcastv(self.value, idx),
2105 error: V::broadcastv(self.error, idx),
2106 }
2107 }
2108
2109 #[inline(always)]
2110 fn extract<const I: usize>(self) -> Self::Element {
2111 let value = V::extract::<I>(self.value);
2112 let error = V::extract::<I>(self.error);
2113
2114 Compensated { value, error }
2115 }
2116
2117 #[inline(always)]
2118 fn extractv(self, idx: usize) -> Self::Element {
2119 let value = V::extractv(self.value, idx);
2120 let error = V::extractv(self.error, idx);
2121
2122 Compensated { value, error }
2123 }
2124
2125 #[inline(always)]
2126 fn insert<const I: usize>(self, value: Self::Element) -> Self {
2127 let Compensated { value, error } = value;
2128
2129 Self {
2130 value: V::insert::<I>(self.value, value),
2131 error: V::insert::<I>(self.error, error),
2132 }
2133 }
2134
2135 #[inline(always)]
2136 fn insertv(self, idx: usize, value: Self::Element) -> Self {
2137 let Compensated { value, error } = value;
2138
2139 Self {
2140 value: V::insertv(self.value, idx, value),
2141 error: V::insertv(self.error, idx, error),
2142 }
2143 }
2144
2145 #[inline(always)]
2146 fn reverse(self) -> Self {
2147 Self {
2148 value: self.value.reverse(),
2149 error: self.error.reverse(),
2150 }
2151 }
2152
2153 #[inline(always)]
2154 fn swap_bytes(self) -> Self {
2155 Self {
2156 value: self.value.swap_bytes(),
2157 error: self.error.swap_bytes(),
2158 }
2159 }
2160
2161 #[inline(always)]
2162 fn zz(self, mask: Self::Mask) -> Self {
2163 Self {
2164 value: self.value.zz(mask),
2165 error: self.error.zz(mask),
2166 }
2167 }
2168
2169 #[inline(always)]
2170 fn nz(self, mask: Self::Mask) -> Self {
2171 Self {
2172 value: self.value.nz(mask),
2173 error: self.error.nz(mask),
2174 }
2175 }
2176
2177 #[inline(always)]
2178 fn compress(self, mask: Self::Mask) -> Self {
2179 Self {
2180 value: self.value.compress(mask),
2181 error: self.error.compress(mask),
2182 }
2183 }
2184
2185 #[inline(always)]
2186 fn compress_z(self, mask: Self::Mask) -> Self {
2187 Self {
2188 value: self.value.compress_z(mask),
2189 error: self.error.compress_z(mask),
2190 }
2191 }
2192
2193 #[inline(always)]
2198 fn compress_m(self, src: Self, mask: Self::Mask) -> Self {
2199 Self {
2200 value: self.value.compress_m(src.value, mask),
2201 error: self.error.compress_m(src.error, mask),
2202 }
2203 }
2204
2205 #[inline(always)]
2206 fn expand(self, mask: Self::Mask) -> Self {
2207 Self {
2208 value: self.value.expand(mask),
2209 error: self.error.expand(mask),
2210 }
2211 }
2212
2213 #[inline(always)]
2214 fn expand_z(self, mask: Self::Mask) -> Self {
2215 Self {
2216 value: self.value.expand_z(mask),
2217 error: self.error.expand_z(mask),
2218 }
2219 }
2220
2221 #[inline(always)]
2222 fn expand_m(self, src: Self, mask: Self::Mask) -> Self {
2223 Self {
2224 value: self.value.expand_m(src.value, mask),
2225 error: self.error.expand_m(src.error, mask),
2226 }
2227 }
2228
2229 #[inline(always)]
2230 fn align<const OFFSET: usize>(self, other: Self) -> Self {
2231 Self {
2232 value: self.value.align::<OFFSET>(other.value),
2233 error: self.error.align::<OFFSET>(other.error),
2234 }
2235 }
2236
2237 const HAS_NATIVE_ALIGN: bool = V::HAS_NATIVE_ALIGN;
2239
2240
2241 fn map<F>(mut self, f: F) -> Self
2242 where
2243 F: Fn(Self::Element) -> Self::Element,
2244 {
2245 for i in 0..Self::LANES {
2246 self = self.insertv(i, f(self.extractv(i)));
2247 }
2248
2249 self
2250 }
2251
2252 fn fold<F>(self, mut init: Self::Element, f: F) -> Self::Element
2253 where
2254 F: Fn(Self::Element, Self::Element) -> Self::Element,
2255 {
2256 for i in 0..Self::LANES {
2257 init = f(init, self.extractv(i));
2258 }
2259
2260 init
2261 }
2262
2263 fn reduce<F>(self, f: F) -> Self::Element
2264 where
2265 F: Fn(Self::Element, Self::Element) -> Self::Element,
2266 {
2267 let mut result = self.extractv(0);
2268
2269 for i in 1..Self::LANES {
2270 result = f(result, self.extractv(i));
2271 }
2272
2273 result
2274 }
2275
2276 #[inline(always)] fn splat_m(src: Self, mask: Self::Mask, value: Self::Element) -> Self { mask.select(Self::splat(value), src) }
2277 #[inline(always)] fn splat_z(mask: Self::Mask, value: Self::Element) -> Self { mask.select(Self::splat(value), Self::EMPTY) }
2278 #[inline(always)] fn broadcast_c<const I: usize>(self, mask: Self::Mask) -> Self { mask.select(self.broadcast::<I>(), self) }
2279 #[inline(always)] fn broadcast_m<const I: usize>(self, src: Self, mask: Self::Mask) -> Self { mask.select(self.broadcast::<I>(), src) }
2280 #[inline(always)] fn broadcast_z<const I: usize>(self, mask: Self::Mask) -> Self { mask.select(self.broadcast::<I>(), Self::EMPTY) }
2281 #[inline(always)] fn broadcastv_c(self, mask: Self::Mask, idx: usize) -> Self { mask.select(self.broadcastv(idx), self) }
2282 #[inline(always)] fn broadcastv_m(self, src: Self, mask: Self::Mask, idx: usize) -> Self { mask.select(self.broadcastv(idx), src) }
2283 #[inline(always)] fn broadcastv_z(self, mask: Self::Mask, idx: usize) -> Self { mask.select(self.broadcastv(idx), Self::EMPTY) }
2284 #[inline(always)] fn reverse_c(self, mask: Self::Mask) -> Self { mask.select(self.reverse(), self) }
2285 #[inline(always)] fn reverse_m(self, src: Self, mask: Self::Mask) -> Self { mask.select(self.reverse(), src) }
2286 #[inline(always)] fn reverse_z(self, mask: Self::Mask) -> Self { mask.select(self.reverse(), Self::EMPTY) }
2287 #[inline(always)] fn swap_bytes_c(self, mask: Self::Mask) -> Self { mask.select(self.swap_bytes(), self) }
2288 #[inline(always)] fn swap_bytes_m(self, src: Self, mask: Self::Mask) -> Self { mask.select(self.swap_bytes(), src) }
2289 #[inline(always)] fn swap_bytes_z(self, mask: Self::Mask) -> Self { mask.select(self.swap_bytes(), Self::EMPTY) }
2290}
2291
2292#[rustfmt::skip]
2293impl<V: CompensatedFloatVector> PartialOrdVector for Compensated<V> {
2294 #[inline(always)]
2295 fn cmp_eq(self, other: Self) -> Self::Mask {
2296 self.value.cmp_eq(other.value) & self.error.cmp_eq(other.error)
2298 }
2299
2300 #[inline(always)]
2301 fn cmp_ne(self, other: Self) -> Self::Mask {
2302 self.value.cmp_ne(other.value) | self.error.cmp_ne(other.error)
2304 }
2305
2306 #[inline(always)]
2307 fn cmp_lt(self, other: Self) -> Self::Mask {
2308 let val_lt = self.value.cmp_lt(other.value);
2309 let val_eq = self.value.cmp_eq(other.value);
2310 let err_lt = self.error.cmp_lt(other.error);
2311
2312 GenericMask::ternlog::<{ thermite::ternlog_imm!(A | (B & C)) }>(val_lt, val_eq, err_lt)
2314 }
2315
2316 #[inline(always)]
2317 fn cmp_gt(self, other: Self) -> Self::Mask {
2318 let val_gt = self.value.cmp_gt(other.value);
2319 let val_eq = self.value.cmp_eq(other.value);
2320 let err_gt = self.error.cmp_gt(other.error);
2321
2322 GenericMask::ternlog::<{ thermite::ternlog_imm!(A | (B & C)) }>(val_gt, val_eq, err_gt)
2324 }
2325
2326 #[inline(always)]
2327 fn cmp_le(self, other: Self) -> Self::Mask {
2328 let val_lt = self.value.cmp_lt(other.value);
2329 let val_eq = self.value.cmp_eq(other.value);
2330 let err_le = self.error.cmp_le(other.error);
2331
2332 GenericMask::ternlog::<{ thermite::ternlog_imm!(A | (B & C)) }>(val_lt, val_eq, err_le)
2334 }
2335
2336 #[inline(always)]
2337 fn cmp_ge(self, other: Self) -> Self::Mask {
2338 let val_gt = self.value.cmp_gt(other.value);
2339 let val_eq = self.value.cmp_eq(other.value);
2340 let err_ge = self.error.cmp_ge(other.error);
2341
2342 GenericMask::ternlog::<{ thermite::ternlog_imm!(A | (B & C)) }>(val_gt, val_eq, err_ge)
2344 }
2345}
2346
2347impl<V: ScalarValue> core::iter::Sum for Compensated<V> {
2348 #[inline]
2349 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
2350 let mut iter = iter.into_iter();
2351
2352 let Some(mut total) = iter.next() else {
2353 return Compensated::new(V::SCALAR_ZERO);
2354 };
2355
2356 for v in iter {
2357 total += v;
2358 }
2359
2360 total
2361 }
2362}
2363
2364impl<V: ScalarValue> core::iter::Product for Compensated<V> {
2365 #[inline]
2366 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
2367 let mut iter = iter.into_iter();
2368
2369 let Some(mut total) = iter.next() else {
2370 return Compensated::new(V::SCALAR_ONE); };
2372
2373 for v in iter {
2374 total *= v;
2375 }
2376
2377 total
2378 }
2379}
2380
2381#[rustfmt::skip]
2384impl<V: CompensatedFloatVector> num_traits::Bounded for Compensated<V> {
2385 #[inline(always)] fn min_value() -> Self { Self { value: V::MIN, error: V::MIN } }
2386 #[inline(always)] fn max_value() -> Self { Self { value: V::MAX, error: V::MAX } }
2387}
2388
2389impl<V: CompensatedFloatVector> NumericVector for Compensated<V> {
2390 #[inline(always)]
2394 fn to_signed_integer(self) -> Self::Signed {
2395 self.value().to_signed_integer()
2396 }
2397
2398 #[inline(always)]
2399 fn from_signed_integer(v: Self::Signed) -> Self {
2400 Self::new(V::from_signed_integer(v))
2401 }
2402
2403 #[inline(always)]
2404 fn to_unsigned_integer(self) -> Self::Unsigned {
2405 self.value().to_unsigned_integer()
2406 }
2407
2408 #[inline(always)]
2409 fn from_unsigned_integer(v: Self::Unsigned) -> Self {
2410 Self::new(V::from_unsigned_integer(v))
2411 }
2412
2413 const ZERO: Self = Self::new(V::ZERO);
2414 const ONE: Self = Self::new(V::ONE);
2415 const TWO: Self = Self::new(V::TWO);
2416
2417 const MIN: Self = Self {
2418 value: V::MIN,
2419 error: V::MIN,
2420 };
2421
2422 const MAX: Self = Self {
2423 value: V::MAX,
2424 error: V::MAX,
2425 };
2426
2427 #[inline(always)]
2433 fn sort_by<O: thermite::sort::SortOrder>(self) -> Self {
2434 if const { Self::LANES <= 16 && Self::LANES.is_power_of_two() } {
2435 thermite::sort::sort_lanes_by_key::<Self, O, Self>(self)
2436 } else {
2437 sort_lanes_scalar::<Self, O>(self)
2438 }
2439 }
2440
2441 #[inline(always)]
2442 fn bitonic_clean_by<O: thermite::sort::SortOrder>(self) -> Self {
2443 if const { Self::LANES <= 16 && Self::LANES.is_power_of_two() } {
2444 thermite::sort::bitonic_clean_lanes_by_key::<Self, O, Self>(self)
2445 } else {
2446 sort_lanes_scalar::<Self, O>(self)
2448 }
2449 }
2450
2451 #[inline(always)]
2452 fn is_zero(self) -> Self::Mask {
2453 self.value().is_zero()
2454 }
2455
2456 #[inline(always)]
2457 fn is_all_zero(self) -> bool {
2458 self.value().is_all_zero()
2461 }
2462
2463 #[inline(always)]
2464 fn min(self, other: Self) -> Self {
2465 self.cmp_lt(other).select(self, other)
2466 }
2467
2468 #[inline(always)]
2469 fn max(self, other: Self) -> Self {
2470 self.cmp_gt(other).select(self, other)
2471 }
2472
2473 #[inline(always)]
2474 fn clamp(self, min: Self, max: Self) -> Self {
2475 let x = self.value();
2476 let min_value = min.value();
2477 let max_value = max.value();
2478
2479 let is_lt = x.cmp_lt(min_value);
2480 let is_gt = x.cmp_gt(max_value);
2481
2482 let value = is_lt.select(min.value, is_gt.select(max.value, self.value));
2483 let error = is_lt.select(min.error, is_gt.select(max.error, self.error));
2484
2485 Self { value, error }
2486 }
2487
2488 #[inline(always)]
2489 fn min_element(self) -> Self::Element {
2490 let mut min_elem = self.extractv(0);
2491 let mut min_value = min_elem.value();
2492
2493 for i in 1..Self::LANES {
2494 let elem = self.extractv(i);
2495 let value = elem.value();
2496
2497 if value < min_value {
2498 min_elem = elem;
2499 min_value = value;
2500 }
2501 }
2502
2503 min_elem
2504 }
2505
2506 #[inline(always)]
2507 fn max_element(self) -> Self::Element {
2508 let mut max_elem = self.extractv(0);
2509 let mut max_value = max_elem.value();
2510
2511 for i in 1..Self::LANES {
2512 let elem = self.extractv(i);
2513 let value = elem.value();
2514
2515 if value > max_value {
2516 max_elem = elem;
2517 max_value = value;
2518 }
2519 }
2520
2521 max_elem
2522 }
2523
2524 fn sum_elements(self) -> Self::Element {
2525 self.reduce(|a, b| a + b)
2526 }
2527
2528 fn prod_elements(self) -> Self::Element {
2529 self.reduce(|a, b| a * b)
2530 }
2531
2532 #[inline(always)]
2542 fn prefix_sum(self) -> Self {
2543 thermite::scan_ladder!(forward, self, Self::ZERO, core::ops::Add::add)
2544 }
2545
2546 #[inline(always)]
2547 fn reverse_prefix_sum(self) -> Self {
2548 thermite::scan_ladder!(reverse, self, Self::ZERO, core::ops::Add::add)
2549 }
2550
2551 #[inline(always)]
2554 fn prefix_min(self) -> Self {
2555 thermite::scan_ladder!(forward, self, self.broadcast::<0>(), Self::min)
2556 }
2557
2558 #[inline(always)]
2559 fn prefix_max(self) -> Self {
2560 thermite::scan_ladder!(forward, self, self.broadcast::<0>(), Self::max)
2561 }
2562
2563 #[inline(always)]
2564 fn reverse_prefix_min(self) -> Self {
2565 thermite::scan_ladder!(reverse, self, Self::splat(self.last_element()), Self::min)
2566 }
2567
2568 #[inline(always)]
2569 fn reverse_prefix_max(self) -> Self {
2570 thermite::scan_ladder!(reverse, self, Self::splat(self.last_element()), Self::max)
2571 }
2572
2573 #[inline(always)]
2574 fn offset() -> Self {
2575 Self::new(V::offset())
2576 }
2577
2578 #[inline(always)]
2579 fn indexed() -> Self {
2580 Self::new(V::indexed())
2581 }
2582
2583 compensated_masked!(binary: min, max);
2584
2585 #[inline(always)]
2588 fn scale(self, factor: Self::Element) -> Self {
2589 self * Self::splat(factor)
2590 }
2591
2592 #[inline(always)]
2593 fn scale_c(self, mask: Self::Mask, factor: Self::Element) -> Self {
2594 mask.select(self.scale(factor), self)
2595 }
2596
2597 #[inline(always)]
2598 fn scale_m(self, src: Self, mask: Self::Mask, factor: Self::Element) -> Self {
2599 mask.select(self.scale(factor), src)
2600 }
2601
2602 #[inline(always)]
2603 fn scale_z(self, mask: Self::Mask, factor: Self::Element) -> Self {
2604 mask.select(self.scale(factor), Self::EMPTY)
2605 }
2606
2607 #[inline(always)]
2611 fn pairwise_sum(lo: Self, hi: Self) -> Self {
2612 let (even, odd) = lo.deinterleave(hi);
2613 even + odd
2614 }
2615
2616 #[inline(always)]
2619 fn relaxed_pairwise_sum(lo: Self, hi: Self) -> Self {
2620 Self::pairwise_sum(lo, hi)
2621 }
2622
2623 fn min_max_element(self) -> (Self::Element, Self::Element) {
2624 (self.min_element(), self.max_element())
2625 }
2626
2627 #[inline(always)]
2629 fn arg_minmax(self) -> (usize, usize) {
2630 self.value().arg_minmax()
2631 }
2632}
2633
2634impl<V: CompensatedFloatVector> thermite::vector::ops::NegMasked<V::Mask> for Compensated<V> {
2635 #[inline(always)]
2636 fn neg_c(mut self, mask: V::Mask) -> Self {
2637 self.value = self.value.neg_c(mask);
2638 self.error = self.error.neg_c(mask);
2639
2640 self
2641 }
2642
2643 #[inline(always)]
2644 fn neg_m(mut self, src: Self, mask: V::Mask) -> Self {
2645 self.value = self.value.neg_m(src.value, mask);
2646 self.error = self.error.neg_m(src.error, mask);
2647
2648 self
2649 }
2650
2651 #[inline(always)]
2652 fn neg_z(mut self, mask: V::Mask) -> Self {
2653 self.value = self.value.neg_z(mask);
2654 self.error = self.error.neg_z(mask);
2655
2656 self
2657 }
2658}
2659
2660impl<V: CompensatedFloatVector> SignedVector for Compensated<V> {
2661 const NEG_ONE: Self = Self::new(V::NEG_ONE);
2662 const MIN_POSITIVE: Self = Self::new(V::MIN_POSITIVE);
2663
2664 #[inline(always)]
2665 fn abs(self) -> Self {
2666 self.neg_c(self.value().cmp_lt(V::ZERO))
2667 }
2668
2669 #[inline(always)]
2670 fn signum(self) -> Self {
2671 Self::new(self.value().signum())
2672 }
2673
2674 #[inline(always)]
2675 fn is_positive(self) -> Self::Mask {
2676 self.value().is_positive()
2677 }
2678
2679 #[inline(always)]
2680 fn is_negative(self) -> Self::Mask {
2681 self.value().is_negative()
2682 }
2683
2684 #[inline(always)]
2685 fn select_negative(self, if_neg: Self, if_pos: Self) -> Self {
2686 self.is_negative().select(if_neg, if_pos)
2687 }
2688
2689 #[inline(always)]
2690 fn copysign(self, sign: Self) -> Self {
2691 let self_is_neg = self.is_negative();
2692 let sign_is_neg = sign.is_negative();
2693
2694 self.neg_c(self_is_neg ^ sign_is_neg)
2695 }
2696
2697 #[inline(always)]
2701 fn abs_c(self, mask: Self::Mask) -> Self {
2702 self.neg_c(mask & self.value().cmp_lt(V::ZERO))
2703 }
2704
2705 #[inline(always)]
2706 fn abs_m(self, src: Self, mask: Self::Mask) -> Self {
2707 mask.select(self.abs(), src)
2708 }
2709
2710 #[inline(always)]
2711 fn abs_z(self, mask: Self::Mask) -> Self {
2712 mask.select(self.abs(), Self::EMPTY)
2713 }
2714
2715 #[inline(always)]
2716 fn copysign_c(self, mask: Self::Mask, sign: Self) -> Self {
2717 self.neg_c(mask & (self.is_negative() ^ sign.is_negative()))
2718 }
2719
2720 #[inline(always)]
2721 fn copysign_m(self, src: Self, mask: Self::Mask, sign: Self) -> Self {
2722 mask.select(self.copysign(sign), src)
2723 }
2724
2725 #[inline(always)]
2726 fn copysign_z(self, mask: Self::Mask, sign: Self) -> Self {
2727 mask.select(self.copysign(sign), Self::EMPTY)
2728 }
2729}
2730
2731impl<FROM, TO> CastVector<Compensated<FROM>> for Compensated<TO>
2734where
2735 FROM: CompensatedFloatVector + CastVector<TO>,
2736 TO: CompensatedFloatVector + CastVector<FROM>,
2737{
2738 fn cast_into(self) -> Compensated<FROM> {
2739 Compensated::<FROM>::cast_from(self)
2740 }
2741
2742 fn cast_from(from: Compensated<FROM>) -> Self {
2743 let from_size = size_of::<FROM::Element>();
2744 let to_size = size_of::<TO::Element>();
2745
2746 if from_size > to_size {
2749 let value = TO::cast_from(from.value);
2754
2755 let (delta, _) = FROM::two_diff(from.value, FROM::cast_from(value));
2760 let (delta, _) = FROM::two_sum(delta, from.error);
2761
2762 Self {
2763 value,
2764 error: TO::cast_from(delta),
2766 }
2767 } else if from_size < to_size {
2768 let v_hi = TO::cast_from(from.value);
2773 let e_hi = TO::cast_from(from.error);
2774
2775 Self {
2778 value: TO::two_sum(v_hi, e_hi).0,
2779 error: TO::ZERO,
2780 }
2781 } else {
2782 Self {
2786 value: TO::cast_from(from.value),
2787 error: TO::cast_from(from.error),
2788 }
2789 }
2790 }
2791}
2792
2793#[rustfmt::skip]
2794impl<V: CompensatedFloatVector> FloatVector for Compensated<V> {
2795 const HALF: Self = Self::new(<V as FloatVector>::HALF);
2796 const NEG_ZERO: Self = Self::new(<V as FloatVector>::NEG_ZERO);
2797 const INFINITY: Self = Self::new(<V as FloatVector>::INFINITY);
2798 const NEG_INFINITY: Self = Self::new(<V as FloatVector>::NEG_INFINITY);
2799 const NAN: Self = Self::new(<V as FloatVector>::NAN);
2800
2801 const EPSILON: Self = Compensated {
2802 value: V::ZERO,
2803 error: <V as FloatVector>::EPSILON, };
2805
2806 type ExtendedPrecision = Self;
2810
2811 #[inline(always)] fn is_infinite(self) -> Self::Mask { self.value().is_infinite() }
2813 #[inline(always)] fn is_finite(self) -> Self::Mask { self.value().is_finite() }
2814 #[inline(always)] fn is_nan(self) -> Self::Mask { self.value.is_nan() | self.error.is_nan() }
2815 #[inline(always)] fn is_zero_or_subnormal(self) -> Self::Mask { self.value().is_zero_or_subnormal() }
2816 #[inline(always)] fn is_normal(self) -> Self::Mask { self.value().is_normal() }
2817 #[inline(always)] fn is_subnormal(self) -> Self::Mask { self.value.is_subnormal() | self.error.is_subnormal() }
2818
2819 const HAS_APPROX_RCP: bool = false;
2820 const HAS_APPROX_RSQRT: bool = false;
2821
2822 #[inline(always)]
2823 fn sqrt(self) -> Self {
2824 let s = V::sqrt(self.value);
2825
2826 let (p, e) = ScalarValue::square(s);
2827
2828 let (d_value, _) = V::two_diff(self.value, p);
2832 let (d_error, _) = V::two_diff(self.error, e);
2833 let (remainder, _) = V::two_sum(d_value, d_error);
2834
2835 let corr = remainder / (s + s);
2837
2838 Self::renormalized(s, corr)
2839 }
2840
2841 #[inline(always)] fn rsqrt(self) -> Self { Self::div_scalar(V::ONE, self.sqrt()) }
2842 #[inline(always)] fn rcp(self) -> Self { Self::div_scalar(V::ONE, self) }
2843
2844 #[inline(always)] fn floor(self) -> Self { Self::new(self.value().floor()) }
2845 #[inline(always)] fn ceil(self) -> Self { Self::new(self.value().ceil()) }
2846 #[inline(always)] fn round(self) -> Self { Self::new(self.value().round()) }
2847 #[inline(always)] fn trunc(self) -> Self { Self::new(self.value().trunc()) }
2848 #[inline(always)] fn fract(self) -> Self { self - self.trunc() }
2849
2850 #[inline(always)]
2851 fn mul_sign(self, sign: Self) -> Self {
2852 let sign = sign.value();
2853
2854 Self {
2855 value: self.value.mul_sign(sign),
2856 error: self.error.mul_sign(sign),
2857 }
2858 }
2859
2860 #[inline(always)] fn signed_zero(self) -> Self { Self::new(self.value().signed_zero()) }
2861
2862 #[inline(always)] fn next_up(self) -> Self { Self::renormalized(self.value, self.error.next_up()) }
2863 #[inline(always)] fn next_down(self) -> Self { Self::renormalized(self.value, self.error.next_down()) }
2864
2865 unsafe fn block_autovectorization(&mut self) {
2866 unsafe {
2867 self.value.block_autovectorization();
2868 self.error.block_autovectorization();
2869 }
2870 }
2871
2872 compensated_masked!(unary: sqrt, rsqrt, rcp, floor, ceil, round, trunc, fract, signed_zero, next_up, next_down);
2873 compensated_masked!(binary: mul_sign);
2874
2875 #[inline(always)]
2878 fn mix(self, a: Self, b: Self) -> Self {
2879 a + (b - a) * self
2880 }
2881}
2882
2883use core::fmt;
2884
2885impl<V: PrettyPrintScalar> fmt::Display for Compensated<V> {
2886 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2887 <V as PrettyPrintScalar>::fmt(self.value, self.error, f)
2888 }
2889}
2890
2891trait PrettyPrintScalar: ScalarValue {
2892 fn fmt(value: Self, error: Self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
2893}
2894
2895impl PrettyPrintScalar for f32 {
2896 fn fmt(value: Self, error: Self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2897 if error == 0.0 {
2898 write!(f, "{value}")
2899 } else {
2900 write!(f, "{}", (value as f64) + (error as f64))
2901 }
2902 }
2903}
2904
2905impl PrettyPrintScalar for f64 {
2906 fn fmt(mut value: Self, mut error: Self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2907 if error == 0.0 {
2908 return write!(f, "{value}");
2909 };
2910
2911 if value < 0.0 {
2912 write!(f, "-")?;
2913
2914 value = -value;
2915 error = -error;
2916 }
2917
2918 let c = Compensated { value, error };
2919
2920 let int_part = Compensated::new(FloatElement::trunc(c.value()));
2921 let mut frac_part = c - int_part;
2922
2923 write!(f, "{}", int_part.value as u64)?;
2924
2925 if frac_part.value() == 0.0 {
2926 return Ok(());
2927 }
2928
2929 f.write_str(".")?;
2930
2931 let p = f.precision().unwrap_or(17); for _ in 0..p {
2934 frac_part *= 10.0;
2935
2936 let digit = FloatElement::trunc(frac_part.value());
2937
2938 write!(f, "{}", digit as u64)?;
2939
2940 frac_part -= Compensated::new(digit);
2941
2942 if frac_part.value == 0.0 && frac_part.error == 0.0 {
2943 break;
2944 }
2945 }
2946
2947 Ok(())
2948 }
2949}