sums.nim 2.3 KB

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