[Xts-commits] r797 - pkg/xts/src

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Mon Nov 18 16:02:24 CET 2013


Author: bodanker
Date: 2013-11-18 16:02:23 +0100 (Mon, 18 Nov 2013)
New Revision: 797

Modified:
   pkg/xts/src/rollfun.c
Log:
- adapt roll_sum to use Kahan summation correction; thanks to Ivan Popivanov


Modified: pkg/xts/src/rollfun.c
===================================================================
--- pkg/xts/src/rollfun.c	2013-11-02 15:45:40 UTC (rev 796)
+++ pkg/xts/src/rollfun.c	2013-11-18 15:02:23 UTC (rev 797)
@@ -23,9 +23,20 @@
 #include <Rinternals.h>
 #include "xts.h"
 
+/* http://en.wikipedia.org/wiki/Kahan_summation_algorithm
+ * sum += x, and updates the accumulated error "c" */
+void kahan_sum(long double x, long double * c, long double * sum)
+{
+  /* Author: Ivan Popivanov */
+   long double y = x - *c;
+   long double t = *sum + y;
+   *c = ( t - *sum ) - y;
+   *sum = t;
+}
+
 SEXP roll_sum (SEXP x, SEXP n)
 {
-  /* Author: Joshua Ulrich */
+  /* Author: Joshua Ulrich, with contributions from Ivan Popivanov */
   int i, P=0, nrs;
   nrs = nrows(x);
 
@@ -38,7 +49,6 @@
   int *int_result=NULL, *int_x=NULL;
   int int_sum = 0;
   double *real_result=NULL, *real_x=NULL;
-  double real_sum = 0.0;
 
   /* check for non-leading NAs and get first non-NA location */
   SEXP first;
@@ -47,6 +57,8 @@
   if(int_n + int_first > nrs)
     error("not enough non-NA values");
 
+  long double sum = 0.0;
+  long double comp = 0.0;
   switch(TYPEOF(x)) {
     case REALSXP:
       real_result = REAL(result);
@@ -56,12 +68,14 @@
       for(i=0; i<int_n+int_first; i++) {
         real_result[i] = NA_REAL;
         if(i >= int_first)
-          real_sum += real_x[i];
+          kahan_sum(real_x[i], &comp, &sum);
       }
-      real_result[ int_n + int_first - 1 ] = real_sum;
+      real_result[ int_n + int_first - 1 ] = (double)sum;
       /* loop over all other values */
       for(i=int_n+int_first; i<nrs; i++) {
-        real_result[i] = real_result[i-1] + real_x[i] - real_x[i-int_n];
+        kahan_sum(-real_x[i-int_n], &comp, &sum);
+        kahan_sum( real_x[i],       &comp, &sum);
+        real_result[i] = (double)sum;
       }
       break;
     case INTSXP: /* how can we check for overflow? */



More information about the Xts-commits mailing list