Merge dev into main: v0.8.7 Kahan compensated summation

This commit is contained in:
Miha Kralj
2026-03-13 22:01:52 -07:00
79 changed files with 2923 additions and 2495 deletions
+34 -17
View File
@@ -34,14 +34,13 @@ public sealed class Inertia : AbstractBase
private record struct State(
double SumY,
double SumXY,
double SumYComp,
double SumXYComp,
int Count,
double LastValid);
private State _state;
private State _p_state;
private const int ResyncInterval = 1000;
private int _tickCount;
/// <summary>
/// Creates Inertia with specified period.
/// </summary>
@@ -102,29 +101,48 @@ public sealed class Inertia : AbstractBase
{
_p_state = _state;
// O(1) incremental sumXY maintenance (PineScript algorithm)
// Kahan compensated O(1) incremental maintenance
if (_buffer.Count == _buffer.Capacity)
{
double oldest = _buffer.Oldest;
_state.SumY -= oldest;
_state.SumXY -= _state.SumY;
_state.SumXY += (_period - 1) * value;
// Kahan delta for SumY
{
double delta = value - oldest;
double y = delta - _state.SumYComp;
double t = _state.SumY + y;
_state.SumYComp = (t - _state.SumY) - y;
_state.SumY = t;
}
// SumXY net delta = -SumY_new + period*value
{
double netDelta = -_state.SumY + (_period * value);
double y = netDelta - _state.SumXYComp;
double t = _state.SumXY + y;
_state.SumXYComp = (t - _state.SumXY) - y;
_state.SumXY = t;
}
}
else
{
_state.SumXY += _state.Count * value;
// Warmup: Kahan addition for SumY
{
double y = value - _state.SumYComp;
double t = _state.SumY + y;
_state.SumYComp = (t - _state.SumY) - y;
_state.SumY = t;
}
// Kahan addition for SumXY
{
double addXY = _state.Count * value;
double y = addXY - _state.SumXYComp;
double t = _state.SumXY + y;
_state.SumXYComp = (t - _state.SumXY) - y;
_state.SumXY = t;
}
_state.Count++;
}
_state.SumY += value;
_buffer.Add(value);
_tickCount++;
if (_buffer.IsFull && _tickCount >= ResyncInterval)
{
_tickCount = 0;
RecalculateSums();
}
}
else
{
@@ -201,7 +219,6 @@ public sealed class Inertia : AbstractBase
_buffer.Clear();
_state = default;
_p_state = default;
_tickCount = 0;
Last = default;
}