#[derive(Clone, Copy, Debug, Default)]
pub struct KahanF32 {
pub sum: f32,
compensation: f32,
}
impl KahanF32 {
#[inline(always)]
pub fn new(initial: f32) -> Self {
Self {
sum: initial,
compensation: 0.0,
}
}
#[inline(always)]
pub fn add(&mut self, x: f32) {
let y = x - self.compensation;
let t = self.sum + y;
self.compensation = (t - self.sum) - y;
self.sum = t;
}
#[inline(always)]
pub fn value(self) -> f32 {
self.sum
}
}
#[derive(Clone, Copy, Debug)]
pub struct Kahan4F32 {
pub sum: [f32; 4],
compensation: [f32; 4],
}
impl Kahan4F32 {
#[inline(always)]
pub fn new(initial: [f32; 4]) -> Self {
Self {
sum: initial,
compensation: [0.0; 4],
}
}
#[inline(always)]
pub fn add(&mut self, x: [f32; 4]) {
for (ch, &x_ch) in x.iter().enumerate() {
let y = x_ch - self.compensation[ch];
let t = self.sum[ch] + y;
self.compensation[ch] = (t - self.sum[ch]) - y;
self.sum[ch] = t;
}
}
#[inline(always)]
pub fn add_channel(&mut self, ch: usize, x: f32) {
let y = x - self.compensation[ch];
let t = self.sum[ch] + y;
self.compensation[ch] = (t - self.sum[ch]) - y;
self.sum[ch] = t;
}
#[inline(always)]
pub fn value(self) -> [f32; 4] {
self.sum
}
}
#[inline(always)]
pub fn kahan_add(sum: f32, compensation: f32, x: f32) -> (f32, f32) {
let y = x - compensation;
let t = sum + y;
(t, (t - sum) - y)
}
#[derive(Clone, Copy, Debug, Default)]
pub struct KahanF64 {
pub sum: f64,
compensation: f64,
}
impl KahanF64 {
#[inline(always)]
pub fn new(initial: f64) -> Self {
Self {
sum: initial,
compensation: 0.0,
}
}
#[inline(always)]
pub fn add(&mut self, x: f64) {
let y = x - self.compensation;
let t = self.sum + y;
self.compensation = (t - self.sum) - y;
self.sum = t;
}
#[inline(always)]
pub fn value(self) -> f64 {
self.sum
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct NeumaierF64 {
pub sum: f64,
compensation: f64,
}
impl NeumaierF64 {
#[inline(always)]
pub fn new(initial: f64) -> Self {
Self {
sum: initial,
compensation: 0.0,
}
}
#[inline(always)]
pub fn add(&mut self, x: f64) {
let t = self.sum + x;
if self.sum.abs() >= x.abs() {
self.compensation += (self.sum - t) + x;
} else {
self.compensation += (x - t) + self.sum;
}
self.sum = t;
}
#[inline(always)]
pub fn value(self) -> f64 {
self.sum + self.compensation
}
}
#[inline(always)]
pub fn kahan_add_f64(sum: f64, compensation: f64, x: f64) -> (f64, f64) {
let y = x - compensation;
let t = sum + y;
(t, (t - sum) - y)
}
#[inline(always)]
pub fn neumaier_add_f64(sum: f64, compensation: f64, x: f64) -> (f64, f64) {
let t = sum + x;
if sum.abs() >= x.abs() {
(t, compensation + (sum - t) + x)
} else {
(t, compensation + (x - t) + sum)
}
}
#[cfg(test)]
#[path = "kahan_test.rs"]
mod kahan_test;