sums.nim 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2019 b3liever
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. ## Accurate summation functions.
  9. runnableExamples:
  10. import std/math
  11. template `~=`(x, y: float): bool = abs(x - y) < 1e-4
  12. let
  13. n = 1_000_000
  14. first = 1e10
  15. small = 0.1
  16. var data = @[first]
  17. for _ in 1 .. n:
  18. data.add(small)
  19. let result = first + small * n.float
  20. doAssert abs(sum(data) - result) > 0.3
  21. doAssert sumKbn(data) ~= result
  22. doAssert sumPairs(data) ~= result
  23. ## See also
  24. ## ========
  25. ## * `math module <math.html>`_ for a standard `sum proc <math.html#sum,openArray[T]>`_
  26. func sumKbn*[T](x: openArray[T]): T =
  27. ## Kahan-Babuška-Neumaier summation: O(1) error growth, at the expense
  28. ## of a considerable increase in computational cost.
  29. ##
  30. ## See:
  31. ## * https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements
  32. if len(x) == 0: return
  33. var sum = x[0]
  34. var c = T(0)
  35. for i in 1 ..< len(x):
  36. let xi = x[i]
  37. let t = sum + xi
  38. if abs(sum) >= abs(xi):
  39. c += (sum - t) + xi
  40. else:
  41. c += (xi - t) + sum
  42. sum = t
  43. result = sum + c
  44. func sumPairwise[T](x: openArray[T], i0, n: int): T =
  45. if n < 128:
  46. result = x[i0]
  47. for i in i0 + 1 ..< i0 + n:
  48. result += x[i]
  49. else:
  50. let n2 = n div 2
  51. result = sumPairwise(x, i0, n2) + sumPairwise(x, i0 + n2, n - n2)
  52. func sumPairs*[T](x: openArray[T]): T =
  53. ## Pairwise (cascade) summation of `x[i0:i0+n-1]`, with O(log n) error growth
  54. ## (vs O(n) for a simple loop) with negligible performance cost if
  55. ## the base case is large enough.
  56. ##
  57. ## See, e.g.:
  58. ## * https://en.wikipedia.org/wiki/Pairwise_summation
  59. ## * Higham, Nicholas J. (1993), "The accuracy of floating point
  60. ## summation", SIAM Journal on Scientific Computing 14 (4): 783–799.
  61. ##
  62. ## In fact, the root-mean-square error growth, assuming random roundoff
  63. ## errors, is only O(sqrt(log n)), which is nearly indistinguishable from O(1)
  64. ## in practice. See:
  65. ## * Manfred Tasche and Hansmartin Zeuner, Handbook of
  66. ## Analytic-Computational Methods in Applied Mathematics (2000).
  67. let n = len(x)
  68. if n == 0: T(0) else: sumPairwise(x, 0, n)