Jump to content

Kahan summation: Difference between revisions

Tcl implementations added
(GP -- partial)
(Tcl implementations added)
Line 923:
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
</pre>
 
=={{header|Tcl}}==
 
===Tcl: Floats===
 
First, using native floating point we see the same epsilon value as other languages using float64:
 
<lang Tcl># make {+ - * /} etc available as commands, for easier expressions
namespace path ::tcl::mathop
 
# find epsilon with native floating point:
proc epsilon {} {
set e 1.0
while {1 + $e != 1} {
set e [/ $e 2]
}
return $e
}
 
# kahan sum with native floats:
proc kahansum {args} {
set sum 0.0
set c 0.0
foreach i $args {
set y [- $i $c]
set t [+ $sum $y]
set c [- [- $t $sum] $y]
set sum $t
}
return $sum
}
 
puts "Native floating point:"
puts "\tEpsilon is: [set e [epsilon]]"
puts "\tAssociative sum: [expr {1.0 + $e - $e}]"
puts "\tKahan sum: [kahansum 1.0 $e -$e]"</lang>
 
<pre>Epsilon is: 1.1102230246251565e-16
Associative sum: 0.9999999999999999
Kahan sum: 1.0</pre>
 
===Tcl: Decimals===
 
{{tcllib|math::decimal}}
 
For the decimal part of the exercise we can use a the Tcllib library <tt>math::decimal</tt>. Note how similar the implementation of Kahan sum is: the only changes are <tt>fromstr</tt> and <tt>tostr</tt>.
 
The last stanza exercises the decimal package's different rounding modes, to see what happens there:
 
<lang Tcl>package require math::decimal
namespace path ::math::decimal
 
proc kahansum {args} {
set sum [fromstr 0.0]
set c [fromstr 0.0]
foreach i $args {
set i [fromstr $i]
set y [- $i $c]
set t [+ $sum $y]
set c [- [- $t $sum] $y]
set sum $t
}
return [tostr $sum]
}
 
proc asum {args} {
set sum [fromstr 0.0]
foreach a $args {
set sum [+ $sum [fromstr $a]]
}
return [tostr $sum]
}
 
setVariable precision 6
set a 10000.0
set b 3.14159
set c 2.71828
 
foreach rounding {half_even half_up half_down down up floor ceiling} {
setVariable rounding $rounding
puts "Rounding mode: $rounding"
puts "\tAssociative sum $a + $b + $c: [asum $a $b $c]"
puts "\tKahan sum $a + $b + $c: [kahansum $a $b $c]"
}</lang>
 
The results are a little surprising:
 
{{out}}
<pre>Rounding mode: half_even
Associative sum 10000.0 + 3.14159 + 2.71828: 10005.8
Kahan sum 10000.0 + 3.14159 + 2.71828: 10005.9
Rounding mode: half_up
Associative sum 10000.0 + 3.14159 + 2.71828: 10005.8
Kahan sum 10000.0 + 3.14159 + 2.71828: 10005.9
Rounding mode: half_down
Associative sum 10000.0 + 3.14159 + 2.71828: 10005.8
Kahan sum 10000.0 + 3.14159 + 2.71828: 10005.9
Rounding mode: down
Associative sum 10000.0 + 3.14159 + 2.71828: 10005.8
Kahan sum 10000.0 + 3.14159 + 2.71828: 10005.8
Rounding mode: up
Associative sum 10000.0 + 3.14159 + 2.71828: 10006.0
Kahan sum 10000.0 + 3.14159 + 2.71828: 10005.9
Rounding mode: floor
Associative sum 10000.0 + 3.14159 + 2.71828: 10005.8
Kahan sum 10000.0 + 3.14159 + 2.71828: 10005.8
Rounding mode: ceiling
Associative sum 10000.0 + 3.14159 + 2.71828: 10006.0
Kahan sum 10000.0 + 3.14159 + 2.71828: 10005.9</pre>
 
In no rounding mode are both answers correct.
With "down" and "floor" rounding, the Kahan sum is too low (10005.8), but any other rounding makes it correct (10005.9).
The Associative largest-to-smallest sum is never correct: "up" and "ceiling" rounding make it too high, while the rest make it low.
 
=={{header|zkl}}==
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.