mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-17 01:58:06 +00:00
Merge dev into main: v0.8.7 Kahan compensated summation
This commit is contained in:
+28
-28
@@ -10,6 +10,7 @@ namespace QuanTAlib;
|
||||
/// Computes the linear regression slope over a rolling window, then accumulates
|
||||
/// it via discrete integration (running sum) to reconstruct a smoothed price-level
|
||||
/// signal. The integration step introduces a natural momentum quality.
|
||||
/// Kahan compensated summation prevents floating-point drift without periodic resync.
|
||||
///
|
||||
/// Algorithm: slope via O(1) incremental linreg, then ILRS += slope.
|
||||
/// Initialized to first price value.
|
||||
@@ -32,16 +33,14 @@ public sealed class Ilrs : AbstractBase
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
private record struct State(
|
||||
double SumY, double SumXY,
|
||||
double SumYComp, double SumXYComp,
|
||||
double Integral, double LastVal,
|
||||
double LastValidValue, bool Initialized);
|
||||
private State _s;
|
||||
private State _ps;
|
||||
|
||||
private int _tickCount;
|
||||
private bool _isNew;
|
||||
|
||||
private const int ResyncInterval = 1000;
|
||||
|
||||
public override bool IsHot => _buffer.IsFull;
|
||||
public bool IsNew => _isNew;
|
||||
|
||||
@@ -175,18 +174,39 @@ public sealed class Ilrs : AbstractBase
|
||||
double oldest = _buffer.Oldest;
|
||||
double prevSumY = _s.SumY;
|
||||
|
||||
// O(1) update for SumXY (reversed-x convention)
|
||||
_s.SumXY = Math.FusedMultiplyAdd(-_period, oldest, _s.SumXY + prevSumY);
|
||||
_s.SumY = _s.SumY - oldest + val;
|
||||
// Kahan compensated update for SumXY: sumXY += (prevSumY - period * oldest)
|
||||
double deltaXY = Math.FusedMultiplyAdd(-_period, oldest, prevSumY);
|
||||
double yXY = deltaXY - _s.SumXYComp;
|
||||
double tXY = _s.SumXY + yXY;
|
||||
_s.SumXYComp = (tXY - _s.SumXY) - yXY;
|
||||
_s.SumXY = tXY;
|
||||
|
||||
// Kahan compensated update for SumY: sumY += (val - oldest)
|
||||
double deltaY = val - oldest;
|
||||
double yY = deltaY - _s.SumYComp;
|
||||
double tY = _s.SumY + yY;
|
||||
_s.SumYComp = (tY - _s.SumY) - yY;
|
||||
_s.SumY = tY;
|
||||
|
||||
_buffer.Add(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_buffer.Count > 0)
|
||||
{
|
||||
_s.SumXY += _s.SumY;
|
||||
// Kahan compensated addition for SumXY: sumXY += sumY
|
||||
double yXY = _s.SumY - _s.SumXYComp;
|
||||
double tXY = _s.SumXY + yXY;
|
||||
_s.SumXYComp = (tXY - _s.SumXY) - yXY;
|
||||
_s.SumXY = tXY;
|
||||
}
|
||||
_s.SumY += val;
|
||||
|
||||
// Kahan compensated addition for SumY
|
||||
double yY = val - _s.SumYComp;
|
||||
double tY = _s.SumY + yY;
|
||||
_s.SumYComp = (tY - _s.SumY) - yY;
|
||||
_s.SumY = tY;
|
||||
|
||||
_buffer.Add(val);
|
||||
}
|
||||
|
||||
@@ -201,13 +221,6 @@ public sealed class Ilrs : AbstractBase
|
||||
// Integrate: ILRS += slope
|
||||
_s.Integral += ComputeSlope(_s);
|
||||
}
|
||||
|
||||
_tickCount++;
|
||||
if (_buffer.IsFull && _tickCount >= ResyncInterval)
|
||||
{
|
||||
_tickCount = 0;
|
||||
Resync();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -239,18 +252,6 @@ public sealed class Ilrs : AbstractBase
|
||||
return -Math.FusedMultiplyAdd(n, state.SumXY, -sx * state.SumY) / denom;
|
||||
}
|
||||
|
||||
private void Resync()
|
||||
{
|
||||
_s.SumY = _buffer.Sum;
|
||||
_s.SumXY = 0;
|
||||
var span = _buffer.GetSpan();
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
int x = span.Length - 1 - i;
|
||||
_s.SumXY = Math.FusedMultiplyAdd(x, span[i], _s.SumXY);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Prime(ReadOnlySpan<double> source, TimeSpan? step = null)
|
||||
{
|
||||
foreach (var value in source)
|
||||
@@ -401,7 +402,6 @@ public sealed class Ilrs : AbstractBase
|
||||
_s.LastValidValue = double.NaN;
|
||||
_ps = default;
|
||||
Last = default;
|
||||
_tickCount = 0;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
|
||||
Reference in New Issue
Block a user