-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add more summation functions #16004
Add more summation functions #16004
Changes from 4 commits
c8b3ec9
26a2eb3
d47a61f
a4b0032
474640f
ba41b4a
b2b0ab2
2854433
77d4b38
9c6c7f8
7469652
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,135 @@ func sumPairs*[T](x: openArray[T]): T = | |
let n = len(x) | ||
if n == 0: T(0) else: sumPairwise(x, 0, n) | ||
|
||
func fastTwoSum*[T: SomeFloat](a, b: T): (T, T) = | ||
## Deker's algorithm | ||
## pre-condition: |a| >= |b| | ||
## you must swap a and b if pre-condition is not satisfied | ||
## s + r = a + b exactly (s is result[0] and r is result[1]) | ||
## s is the nearest FP number of a + B | ||
result[0] = a + b | ||
result[1] = b - (result[0] - a) | ||
|
||
func twoSum*[T](a, b: T): (T, T) = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
## Møller-Knuth's algorithm. | ||
## Improve Deker's algorithm, no branch needed | ||
## More operations, but still cheap. | ||
result[0] = a + b | ||
let z = result[0] - a | ||
result[1] = (a - (result[0] - z)) + (b - z) | ||
|
||
func sum2*[T: SomeFloat](v: openArray[T]): T = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sumToSum ? |
||
## sum an array v using twoSum function | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
this enables future docgen improvements to auto-generate clickable links |
||
if len(v) == 0: | ||
return 0.0 | ||
|
||
var s = v[0] | ||
var e: float | ||
for x in v[1..^1]: | ||
let sum = twoSum(s, x) | ||
Araq marked this conversation as resolved.
Show resolved
Hide resolved
|
||
s = sum[0] | ||
e += sum[1] | ||
return s + e | ||
|
||
func shewchuckSum_add*[T: SomeFloat](v: openArray[T]): seq[T] = | ||
## Full precision sum of values in iterable. Returns the value of the | ||
## sum, rounded to the nearest representable floating-point number | ||
## using the round-half-to-even rule | ||
## | ||
## Original PR: https://github.com/nim-lang/Nim/pull/9284 | ||
## Return partials result. | ||
## Result must be summed | ||
for x in v: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i was concerned about the fact this allocates and could be inefficient but in my limited tests, 2 was the max size for result.len. |
||
var x = x | ||
var i = 0 | ||
for y in result: | ||
let sum = twoSum(x, y) | ||
lbartoletti marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let hi = sum[0] | ||
let lo = sum[1] | ||
if lo != 0.0: | ||
result[i] = lo | ||
i.inc | ||
x = hi | ||
setLen(result, i + 1) | ||
result[i] = x | ||
timotheecour marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
func shewchuckSum_total*[T: SomeFloat](partials: openArray[T]): T = | ||
var hi = 0.0 | ||
if len(partials) > 0: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cmon, simplify this. var n = partials.len
if n > 0:
... |
||
var n = len(partials) | ||
lbartoletti marked this conversation as resolved.
Show resolved
Hide resolved
|
||
dec(n) | ||
hi = partials[n] | ||
var lo = 0.0 | ||
while n > 0: | ||
var x = hi | ||
dec(n) | ||
var y = partials[n] | ||
let sum = twoSum(x, y) | ||
hi = sum[0] | ||
lo = sum[1] | ||
if lo != 0.0: | ||
break | ||
if (n > 0 and | ||
( | ||
(lo < 0.0 and partials[n - 1] < 0.0) or | ||
(lo > 0.0 and partials[n - 1] > 0.0) | ||
) | ||
): | ||
y = lo * 2.0 | ||
x = hi + y | ||
var yr = x - hi | ||
if y == yr: | ||
hi = x | ||
result = hi | ||
|
||
func shewchuckSum*[T: SomeFloat](x: openArray[T]): T = | ||
## https://docs.python.org/3/library/math.html#math.fsum | ||
## https://code.activestate.com/recipes/393090/ | ||
## www-2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps | ||
shewchuckSum_total(shewchuckSum_add(x)) | ||
|
||
func fsum*[T: SomeFloat](x: openArray[T]): T = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
## Alias of shewchuckSum function as python fsum | ||
shewchuckSum(x) | ||
|
||
func neumaierSum*[T: SomeFloat](x: openArray[T]): T = | ||
lbartoletti marked this conversation as resolved.
Show resolved
Hide resolved
|
||
## improved Kahan–Babuška algorithm | ||
## https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements | ||
var sum = 0.0 | ||
var c = 0.0 # A running compensation for lost low-order bits. | ||
for v in x: | ||
var t = sum + v | ||
# If sum is bigger, low-order digits of input[i] are lost. | ||
if abs(sum) >= abs(v): | ||
c += (sum - t) + v | ||
else: | ||
c += (v - t) + sum # Else low-order digits of sum are lost. | ||
sum = t | ||
return sum + c # Correction only applied once in the very end. | ||
|
||
func kleinSum*[T: SomeFloat](x: openArray[T]): T = | ||
## Klein variant | ||
## https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements | ||
var sum = 0.0 | ||
var cs = 0.0 | ||
var ccs = 0.0 | ||
for v in x: | ||
var t = sum + v | ||
var c = 0.0 | ||
var cc = 0.0 | ||
if abs(sum) >= abs(v): | ||
c = (sum - t) + v | ||
else: | ||
c = (v - t) + sum | ||
sum = t | ||
t = cs + c | ||
if abs(cs) >= abs(c): | ||
cc = (cs - t) + c | ||
else: | ||
cc = (c - t) + cs | ||
cs = t | ||
ccs = ccs + cc | ||
return sum + cs + ccs | ||
|
||
runnableExamples: | ||
static: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add wikipedia link
ditto elsewhere