From bhh @end|ng |rom x@4@||@n|  Wed Feb 20 11:11:50 2019
From: bhh @end|ng |rom x@4@||@n| (Berend Hasselman)
Date: Wed, 20 Feb 2019 11:11:50 +0100
Subject: [Rd] code for sum function
In-Reply-To: <f9be94ba-6032-f127-7d37-6ba80f9e2425@gmail.com>
References: <c1495700-e265-4ff8-1f36-e149bd4d1961@gmail.com>
 <66adfaca-27fe-4671-c73d-fd0462c36af0@gmail.com>
 <CAF8bMcZyCHPB1JcQyhwO=zx+7V2HOVALMUwHXvutjQf3Sv2S-A@mail.gmail.com>
 <f9be94ba-6032-f127-7d37-6ba80f9e2425@gmail.com>
Message-ID: <81CB2714-5031-49CB-BADC-68370AD946D0@xs4all.nl>

> 
> On 2019-02-19 2:08 p.m., William Dunlap via R-devel wrote:
>> The algorithm does make a differece.  You can use Kahan's summation
>> algorithm (https://en.wikipedia.org/wiki/Kahan_summation_algorithm) to
>> reduce the error compared to the naive summation algorithm.  E.g., in R
>> code:
>> 
>> naiveSum <-
>> function(x) {
>>   s <- 0.0
>>   for(xi in x) s <- s + xi
>>   s
>> }
>> kahanSum <- function (x)
>> {
>>   s <- 0.0
>>   c <- 0.0 # running compensation for lost low-order bits
>>   for(xi in x) {
>>      y <- xi - c
>>      t <- s + y # low-order bits of y may be lost here
>>      c <- (t - s) - y
>>      s <- t
>>   }
>>   s
>> }
>> 
>>> rSum <- vapply(c(1:20,10^(2:7)), function(n) sum(rep(1/7,n)), 0)
>>> rNaiveSum <- vapply(c(1:20,10^(2:7)), function(n) naiveSum(rep(1/7,n)), 0)
>>> rKahanSum <- vapply(c(1:20,10^(2:7)), function(n) kahanSum(rep(1/7,n)), 0)
>>> 
>>> table(rSum == rNaiveSum)
>> 
>> FALSE  TRUE
>>   21     5
>>> table(rSum == rKahanSum)
>> 
>> FALSE  TRUE
>>    3    23


If you use the vector  c(1,10^100,1,-10^100) as input then
sum, naiveSum or kahanSum will all give an incorrect answer.
All return 0 instead of 2.

From the wikipedia page we can try the pseudocode given of the modification by Neumaier.
My R version (with a small correction to avoid cancellation?) is

neumaierSum <- function (x)
{
  s <- 0.0
  z <- 0.0 # running compensation for lost low-order bits
  for(xi in x) {
     t <- s + xi
     if( abs(s) >= abs(xi) ){
         b <- (s-t)+xi #  intermediate step needed  in R otherwise cancellation
         z <- z+b      # If sum is bigger, low-order digits of xi are lost.
     } else {
         b <- (xi-t)+s #  intermediate step needed in R otherwise cancellation
         z <- z+b      # else low-order digits of sum are lost
     }
     s <- t
  }
  s+z   # correction only applied once in the very end
}

testx <-  c(1,10^100,1,-10^100)
neumaierSum(testx)

gives 2 as answer.

Berend Hasselman



[Rd] code for sum function
Berend Hasselman