diff --git a/modules/img/alg/src/CMakeLists.txt b/modules/img/alg/src/CMakeLists.txt
index 11fba15d4e3ffc675692c8ad0d73bb3c1738a5b7..c181156dbfe99eb4ac8b6a4532fa359b8b161d45 100644
--- a/modules/img/alg/src/CMakeLists.txt
+++ b/modules/img/alg/src/CMakeLists.txt
@@ -25,6 +25,7 @@ power_spectrum.cc
 randomize.cc
 smooth_mask_image.cc
 stat.cc
+stat_accumulator.cc
 stat_min_max.cc
 alg_transform.cc
 alg_mirror.cc
@@ -75,6 +76,7 @@ power_spectrum.hh
 randomize.hh
 smooth_mask_image.hh
 stat.hh
+stat_accumulator.hh
 stat_min_max.hh
 threshold.hh
 transcendentals.hh
diff --git a/modules/img/alg/src/stat.cc b/modules/img/alg/src/stat.cc
index 2a9427abbaea05fdc290d0642ed6918ea6b455dd..f433cd6d69a7810a2e34ca043ad3257720cb9acc 100644
--- a/modules/img/alg/src/stat.cc
+++ b/modules/img/alg/src/stat.cc
@@ -30,6 +30,7 @@
 #include <ost/img/value_util.hh>
 
 #include "stat.hh"
+#include "stat_accumulator.hh"
 
 namespace ost { namespace img { namespace alg {
 
@@ -58,14 +59,12 @@ void StatBase::VisitState(const ImageStateImpl<T,D>& isi)
     return;
   }
 
-  Real sum2=0.0;
   Vec3 sumcenter(0.0,0.0,0.0);
-  Real current_n=1.0;
-  Real m2=0.0,m3=0.0,m4=0.0;
   ValIndex minindex(std::numeric_limits<Real>::max(),Point(0,0,0));
   ValIndex maxindex(-std::numeric_limits<Real>::max(),Point(0,0,0));
   min_ = std::numeric_limits<Real>::max();
   max_ = -std::numeric_limits<Real>::max();
+  StatAccumulator acc;
 
   int wi=isi.GetSize()[0];
   int he=isi.GetSize()[1];
@@ -74,23 +73,11 @@ void StatBase::VisitState(const ImageStateImpl<T,D>& isi)
     for(int j=0;j<he;++j) {
       for(int k=0;k<de;++k) {
         Real val=Val2Val<T,Real>(isi.Value(Index(i,j,k)));
-        Real delta = val - mean_;
-        Real delta_n = delta / current_n;
-        Real delta_n2 = delta_n * delta_n;
-        Real term = delta * delta_n * (current_n-1);
-
-        mean_ += delta_n;
-        m4 += term * delta_n2 * (current_n*current_n - 3*current_n + 3) + 6 * delta_n2 * m2 - 4 * delta_n * m3;
-        m3 += term * delta_n * (current_n - 2) - 3 * delta_n * m2;
-        m2 += term;
-
         ValIndex vi(val,Point(i,j,k));
         minindex=std::min<ValIndex>(vi,minindex);
         maxindex=std::max<ValIndex>(vi,maxindex);
         sumcenter+=Vec3(i,j,k)*val;
-        sum_+=val;
-        sum2+=val*val;
-        current_n+=1;
+        acc(val);
       }
     }
   }
@@ -98,16 +85,13 @@ void StatBase::VisitState(const ImageStateImpl<T,D>& isi)
   max_=maxindex.first;
   minpos_=minindex.second+isi.GetExtent().GetStart();
   maxpos_=maxindex.second+isi.GetExtent().GetStart();  
-  var_=m2/n;
-  std_dev_=sqrt(var_);
-  rms_=sqrt(sum2/n);
-  if(m2<1e20){
-    skewness_=0.0;
-    kurtosis_= 0.0;
-  }else{
-    skewness_=m3/sqrt(m2*m2*m2);
-    kurtosis_= (n*m4) / (m2*m2) - 3.0;
-  }
+  var_=acc.GetVariance();
+  std_dev_=acc.GetStandardDeviation();
+  rms_=acc.GetRootMeanSquare();
+  skewness_=acc.GetSkewness();
+  kurtosis_= acc.GetKurtosis();
+  sum_=acc.GetSum();
+  mean_=acc.GetMean();
   if(sum_!=0.0){
     center_of_mass_=sumcenter/sum_+isi.GetExtent().GetStart().ToVec3();
   }else{
@@ -135,49 +119,32 @@ void StatBase::VisitFunction(const Function& fnc)
     return;
   }
 
-  Real sum2=0.0;
   Vec3 sumcenter(0.0,0.0,0.0);
-  Real current_n=1.0;
-  Real m2=0.0,m3=0.0,m4=0.0;
   ValIndex minindex(std::numeric_limits<Real>::max(),Point(0,0,0));
   ValIndex maxindex(-std::numeric_limits<Real>::max(),Point(0,0,0));
   min_ = std::numeric_limits<Real>::max();
   max_ = -std::numeric_limits<Real>::max();
+  StatAccumulator acc;
 
   for(ExtentIterator it(fnc.GetExtent());!it.AtEnd(); ++it) {
     Real val=fnc.GetReal(it);
-    Real delta = val - mean_;
-    Real delta_n = delta / current_n;
-    Real delta_n2 = delta_n * delta_n;
-    Real term = delta * delta_n * (current_n-1);
-
-    mean_ += delta_n;
-    m4 += term * delta_n2 * (current_n*current_n - 3*current_n + 3) + 6 * delta_n2 * m2 - 4 * delta_n * m3;
-    m3 += term * delta_n * (current_n - 2) - 3 * delta_n * m2;
-    m2 += term;
-
     ValIndex vi(val,it);
     minindex=std::min<ValIndex>(vi,minindex);
     maxindex=std::max<ValIndex>(vi,maxindex);
     sumcenter+=Point(it).ToVec3()*val;
-    sum_+=val;
-    sum2+=val*val;
-    current_n+=1;
+    acc(val);
   }
   min_=minindex.first;
   max_=maxindex.first;
   minpos_=minindex.second;
-  maxpos_=maxindex.second;  
-  var_=m2/n;
-  std_dev_=sqrt(var_);
-  rms_=sqrt(sum2/n);
-  if(m2<1e20){
-    skewness_=0.0;
-    kurtosis_= 0.0;
-  }else{
-    skewness_=m3/sqrt(m2*m2*m2);
-    kurtosis_= (n*m4) / (m2*m2) - 3.0;
-  }
+  maxpos_=maxindex.second;
+  var_=acc.GetVariance();
+  std_dev_=acc.GetStandardDeviation();
+  rms_=acc.GetRootMeanSquare();
+  skewness_=acc.GetSkewness();
+  kurtosis_= acc.GetKurtosis();
+  sum_=acc.GetSum();
+  mean_=acc.GetMean();
   if(sum_!=0.0){
     center_of_mass_=sumcenter/sum_;
   }else{
diff --git a/modules/img/alg/src/stat_accumulator.cc b/modules/img/alg/src/stat_accumulator.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c4641d5504cafa83cfb788dec0ad21b59cead46e
--- /dev/null
+++ b/modules/img/alg/src/stat_accumulator.cc
@@ -0,0 +1,141 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+
+#include "stat_accumulator.hh"
+
+namespace ost { namespace img { namespace alg {
+
+StatAccumulator::StatAccumulator():
+  mean_(0.0),
+  sum_(0.0),
+  sum2_(0.0),
+  m2_(0.0),
+  m3_(0.0),
+  m4_(0.0),
+  n_(1)
+
+{
+}
+
+void StatAccumulator::operator()(Real val)
+{
+  Real delta = val - mean_;
+  Real delta_n = delta / n_;
+  Real delta_n2 = delta_n * delta_n;
+  Real term = delta * delta_n * (n_-1);
+
+  mean_ += delta_n;
+  m4_ += term * delta_n2 * (n_*n_ - 3*n_ + 3) + 6 * delta_n2 * m2_ - 4 * delta_n * m3_;
+  m3_ += term * delta_n * (n_ - 2) - 3 * delta_n * m2_;
+  m2_ += term;
+  sum_+=val;
+  sum2_+=val*val;
+  n_+=1;
+}
+
+StatAccumulator StatAccumulator::operator+(const StatAccumulator& acc2) const
+{
+  StatAccumulator acc(acc2);
+  acc+=*this;
+  return acc;
+}
+
+StatAccumulator& StatAccumulator::operator+=(const StatAccumulator& acc)
+{
+  if(acc.n_==1){
+    return *this;
+  }
+  if(n_==1){
+    mean_=acc.mean_;
+    sum_=acc.sum_;
+    sum2_=acc.sum2_;
+    m2_=acc.m2_;
+    m3_=acc.m3_;
+    m4_=acc.m4_;
+    n_=acc.n_;
+    return *this;
+  }
+  Real na=n_-1;
+  Real nb=acc.n_-1;
+  Real nanb=na*nb;
+  Real delta = acc.mean_ - mean_;
+  Real delta_n = delta / (na+nb);
+  Real delta_n2 = delta_n * delta_n;
+
+  mean_ += nb*delta_n;
+  m4_+=acc.m4_+delta*delta_n*delta_n2*nanb*(na*na-nanb+nb*nb)+6.0*delta_n2*(na*na*acc.m2_+nb*nb*m2_)+4.0*delta_n*(na*acc.m3_-nb*m3_);
+  m3_+=acc.m3_+delta*delta_n2*nanb*(na-nb)+3.0*delta_n*(na*acc.m2_-nb*m2_);
+  m2_ += acc.m2_+delta*delta_n*nanb;
+  sum_+=acc.sum_;
+  sum2_+=acc.sum2_;
+  n_+=nb;
+  return *this;
+}
+
+Real StatAccumulator::GetMean() const
+{
+  return mean_;
+}
+
+Real StatAccumulator::GetSum() const
+{
+  return sum_;
+}
+
+Real StatAccumulator::GetVariance() const
+{
+  if(n_==1.0){
+    return 0.0;
+  }
+  return m2_/(n_-1);
+}
+
+Real StatAccumulator::GetStandardDeviation() const
+{
+  return sqrt(GetVariance());
+}
+
+Real StatAccumulator::GetRootMeanSquare() const
+{
+  if(n_==1.0){
+    return 0.0;
+  }
+  return sqrt(sum2_/(n_-1));
+}
+
+Real StatAccumulator::GetSkewness() const
+{
+  if(m2_<1e-20){
+    return 0.0;
+  }else{
+    return m3_/sqrt(m2_*m2_*m2_);
+  }
+}
+
+Real StatAccumulator::GetKurtosis() const
+{
+  if(m2_<1e-20){
+    return 0.0;
+  }else{
+    return ((n_-1)*m4_) / (m2_*m2_);
+  }
+}
+
+}}} //ns
diff --git a/modules/img/alg/src/stat_accumulator.hh b/modules/img/alg/src/stat_accumulator.hh
new file mode 100644
index 0000000000000000000000000000000000000000..3cb5f06eb3c9882aa1481b637de626e11322d567
--- /dev/null
+++ b/modules/img/alg/src/stat_accumulator.hh
@@ -0,0 +1,55 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+#ifndef OST_STAT_ACCUMULATOR_HH
+#define OST_STAT_ACCUMULATOR_HH
+
+#include <ost/base.hh>
+#include <ost/img/alg/module_config.hh>
+
+namespace ost { namespace img { namespace alg {
+
+class DLLEXPORT_IMG_ALG StatAccumulator
+{
+public:
+  StatAccumulator();
+  void operator()(Real val);
+  StatAccumulator operator+(const StatAccumulator& acc) const;
+  StatAccumulator& operator+=(const StatAccumulator& acc);
+
+  Real GetMean() const ;
+  Real GetSum() const ;
+  Real GetVariance() const;
+  Real GetStandardDeviation() const ;
+  Real GetRootMeanSquare() const;
+  Real GetSkewness() const ;
+  Real GetKurtosis() const;
+
+private:
+  Real mean_;
+  Real sum_;
+  Real sum2_;
+  Real m2_;
+  Real m3_;
+  Real m4_;
+  Real n_;
+};
+
+}}} //ns
+#endif // OST_STAT_ACCUMULATOR_HH
diff --git a/modules/img/alg/tests/test_stat.cc b/modules/img/alg/tests/test_stat.cc
index 3f5e6d2ed6a3a1114f59458361021b7f9a0ccdad..592d00c9a907d591be0999790490471af88ce4da 100644
--- a/modules/img/alg/tests/test_stat.cc
+++ b/modules/img/alg/tests/test_stat.cc
@@ -29,6 +29,7 @@
 #include <ost/img/image.hh>
 
 #include <ost/img/alg/stat.hh>
+#include <ost/img/alg/stat_accumulator.hh>
 
 namespace test_stat {
 
@@ -51,7 +52,40 @@ void test() {
   im.Apply(stat);
   BOOST_CHECK_CLOSE(stat.GetMean(),Real(5.0),Real(0.0001));
   BOOST_CHECK_CLOSE(stat.GetStandardDeviation(),Real(2.58198889747),Real(0.0001));
-  
+  BOOST_CHECK_CLOSE(stat.GetSkewness()+0.5,Real(0.5),Real(0.0001));
+  BOOST_CHECK_CLOSE(stat.GetKurtosis(),Real(1.77),Real(0.0001));
+
+  // check for rounding errors
+  im+=10000.0;
+  im.Apply(stat);
+  BOOST_CHECK_CLOSE(stat.GetMean(),Real(10005.0),Real(0.0001));
+  BOOST_CHECK_CLOSE(stat.GetStandardDeviation(),Real(2.58198889747),Real(0.01));
+  BOOST_CHECK_CLOSE(stat.GetSkewness()+0.5,Real(0.5),Real(0.01));
+  BOOST_CHECK_CLOSE(stat.GetKurtosis(),Real(1.77),Real(0.01));
+
+
+  StatAccumulator acc;
+  for(int u=0;u<3;++u) {
+    for(int v=0;v<3;++v) {
+      acc(val[u][v]);
+    }
+  }
+  BOOST_CHECK_CLOSE(acc.GetMean(),Real(5.0),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc.GetStandardDeviation(),Real(2.58198889747),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc.GetSkewness()+0.5,Real(0.5),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc.GetKurtosis(),Real(1.77),Real(0.0001));
+
+  StatAccumulator acc1,acc2,acc3;
+  for(int u=0;u<3;++u) {
+    acc1(val[u][0]);
+    acc2(val[u][1]);
+    acc3(val[u][2]);
+  }
+  StatAccumulator acc_c=acc1+acc2+acc3;
+  BOOST_CHECK_CLOSE(acc_c.GetMean(),Real(5.0),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc_c.GetStandardDeviation(),Real(2.58198889747),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc_c.GetSkewness()+0.5,Real(0.5),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc_c.GetKurtosis(),Real(1.77),Real(0.0001));
 }
 
 } // namespace