use super::HasZero;
pub trait Scalar:
Copy
+ Default
+ PartialEq
+ PartialOrd
+ std::fmt::Debug
+ std::fmt::Display
+ std::ops::Add<Output = Self>
+ std::ops::AddAssign
+ std::ops::Mul<Output = Self>
+ std::ops::MulAssign
+ std::ops::Div<Output = Self>
+ std::ops::DivAssign
+ std::ops::Sub<Output = Self>
+ std::ops::SubAssign
+ std::ops::Neg<Output = Self>
+ num_traits::Zero
+ num_traits::One
+ num_traits::Inv
+ num_traits::Signed
+ From<f32>
+ 'static
{
const PI: Self;
const EPS: Self;
const ZERO: Self;
const ONE: Self;
const TWO: Self;
const THREE: Self;
const FOUR: Self;
const FIVE: Self;
const TEN: Self;
const HALF: Self;
const PHI: Self;
const INFINITY: Self;
const NEG_INFINITY: Self;
fn is_positive(self) -> bool;
fn is_negative(self) -> bool;
fn to_f64(self) -> f64;
fn from_usize(value: usize) -> Self;
fn abs(self) -> Self {
if self.is_positive() {
self
} else {
-self
}
}
fn acos(self) -> Self;
fn sin(&self) -> Self;
fn cos(&self) -> Self;
fn tan(&self) -> Self;
fn cot(&self) -> Self;
fn atan2(&self, x: Self) -> Self;
fn max(&self, b: Self) -> Self;
fn min(&self, b: Self) -> Self;
fn sqrt(self) -> Self;
fn is_finite(self) -> bool;
fn is_nan(self) -> bool;
fn lerp(&self, other: Self, t: Self) -> Self {
*self + (other - *self) * t
}
fn det3(
a: Self,
b: Self,
c: Self,
d: Self,
e: Self,
f: Self,
g: Self,
h: Self,
i: Self,
) -> Self {
a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g)
}
fn stable_sum<I: Iterator<Item = Self>>(values: I) -> Self {
neumaier_summation(values).0
}
fn stable_mean<I: Iterator<Item = Self>>(values: I) -> Self {
let (sum, n) = neumaier_summation(values);
sum / Self::from_usize(n)
}
fn clamp(self, min: Self, max: Self) -> Self {
if self < min {
min
} else if self > max {
max
} else {
self
}
}
fn is_about(&self, other: Self, epsilon: Self) -> bool {
(*self - other).abs() < epsilon
}
}
pub trait ScalarIteratorExt<S: Scalar>: Iterator<Item = S> {
fn stable_sum(self) -> Self::Item
where
Self: Sized,
Self::Item: std::ops::Add<Output = Self::Item>,
{
Scalar::stable_sum(self)
}
fn stable_mean(self) -> Self::Item
where
Self: Sized,
Self::Item: std::ops::Add<Output = Self::Item>,
{
Scalar::stable_mean(self)
}
}
impl<I: Iterator<Item = S>, S: Scalar> ScalarIteratorExt<S> for I {}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct OrderedFloats<S: Scalar> {
value: S,
}
impl<S: Scalar> OrderedFloats<S> {
pub fn new(value: S) -> Self {
OrderedFloats { value }
}
}
impl<S: Scalar> std::cmp::Eq for OrderedFloats<S> {}
impl<S: Scalar> std::cmp::Ord for OrderedFloats<S> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.value
.partial_cmp(&other.value)
.unwrap_or(std::cmp::Ordering::Equal)
}
}
pub fn neumaier_summation<S: Scalar, I: Iterator<Item = S>>(iter: I) -> (S, usize) {
let mut sum = S::ZERO;
let mut c = S::ZERO;
let mut count = 0;
for value in iter {
count += 1;
let t = sum + value;
if sum.abs() >= value.abs() {
c += (sum - t) + value;
} else {
c += (value - t) + sum;
}
sum = t;
}
(sum + c, count)
}
pub fn kahan_summation<
X: std::ops::Add<Output = X> + std::ops::Sub<Output = X> + Copy + HasZero,
I: Iterator<Item = X>,
>(
iter: I,
) -> (X, usize) {
let mut sum = X::zero();
let mut c = X::zero();
let mut count = 0;
for value in iter {
count += 1;
let y = value - c;
let t = sum + y;
c = (t - sum) - y;
sum = t;
}
(sum, count)
}