// based on https://raw.githubusercontent.com/AnthonyLloyd/CsCheck/master/Tests/MathX.cs
namespace Jint.Native.Math;
internal static class MathX
{
private static double TwoSum(double a, double b, out double lo)
{
var hi = a + b;
lo = hi - b;
lo = lo - hi + b + (a - lo);
return hi;
}
/// Shewchuk summation
internal static double FSum(this List values)
{
if (values.Count < 3) return values.Count == 2 ? values[0] + values[1] : values.Count == 1 ? values[0] : 0.0;
Span partials = stackalloc double[16];
var hi = TwoSum(values[0], values[1], out var lo);
int count = 0;
for (int i = 2; i < values.Count; i++)
{
var v = TwoSum(values[i], lo, out lo);
int c = 0;
for (int j = 0; j < count; j++)
{
v = TwoSum(v, partials[j], out var p);
if (p != 0.0)
partials[c++] = p;
}
hi = TwoSum(hi, v, out v);
if (v != 0.0)
{
if (c == partials.Length)
{
var newPartials = new double[partials.Length * 2];
partials.CopyTo(newPartials);
partials = newPartials;
}
partials[c++] = v;
}
count = c;
}
if (count != 0)
{
if (lo == 0) // lo has a good chance of being zero
{
lo = partials[0];
if (count == 1) return lo + hi;
partials = partials.Slice(1, count - 1);
}
else
partials = partials.Slice(0, count);
foreach (var p in partials)
lo += p;
}
return lo + hi;
}
}