MathX.cs 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. // based on https://raw.githubusercontent.com/AnthonyLloyd/CsCheck/master/Tests/MathX.cs
  2. namespace Jint.Native.Math;
  3. internal static class MathX
  4. {
  5. private static double TwoSum(double a, double b, out double lo)
  6. {
  7. var hi = a + b;
  8. lo = hi - b;
  9. lo = lo - hi + b + (a - lo);
  10. return hi;
  11. }
  12. /// <summary>Shewchuk summation</summary>
  13. internal static double FSum(this List<double> values)
  14. {
  15. if (values.Count < 3) return values.Count == 2 ? values[0] + values[1] : values.Count == 1 ? values[0] : 0.0;
  16. Span<double> partials = stackalloc double[16];
  17. var hi = TwoSum(values[0], values[1], out var lo);
  18. int count = 0;
  19. for (int i = 2; i < values.Count; i++)
  20. {
  21. var v = TwoSum(values[i], lo, out lo);
  22. int c = 0;
  23. for (int j = 0; j < count; j++)
  24. {
  25. v = TwoSum(v, partials[j], out var p);
  26. if (p != 0.0)
  27. partials[c++] = p;
  28. }
  29. hi = TwoSum(hi, v, out v);
  30. if (v != 0.0)
  31. {
  32. if (c == partials.Length)
  33. {
  34. var newPartials = new double[partials.Length * 2];
  35. partials.CopyTo(newPartials);
  36. partials = newPartials;
  37. }
  38. partials[c++] = v;
  39. }
  40. count = c;
  41. }
  42. if (count != 0)
  43. {
  44. if (lo == 0) // lo has a good chance of being zero
  45. {
  46. lo = partials[0];
  47. if (count == 1) return lo + hi;
  48. partials = partials.Slice(1, count - 1);
  49. }
  50. else
  51. partials = partials.Slice(0, count);
  52. foreach (var p in partials)
  53. lo += p;
  54. }
  55. return lo + hi;
  56. }
  57. }