LibreOffice Module sc (master)  1
arraysumfunctor.hxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  */
10 
11 #pragma once
12 
13 #include <cmath>
14 #include "kahan.hxx"
15 #include "arraysumfunctor.hxx"
16 #include <formula/errorcodes.hxx>
17 
18 namespace sc::op
19 {
20 // Checkout available optimization options.
21 // Note that it turned out to be problematic to support CPU-specific code
22 // that's not guaranteed to be available on that specific platform (see
23 // git history). SSE2 is guaranteed on x86_64 and it is our baseline requirement
24 // for x86 on Windows, so SSE2 use is hardcoded on those platforms.
25 // Whenever we raise baseline to e.g. AVX, this may get
26 // replaced with AVX code (get it from git history).
27 // Do it similarly with other platforms.
28 #if defined(X86_64) || (defined(X86) && defined(_WIN32))
29 #define SC_USE_SSE2 1
30 KahanSum executeSSE2(size_t& i, size_t nSize, const double* pCurrent);
31 #else
32 #define SC_USE_SSE2 0
33 #endif
34 
39 static inline KahanSum executeUnrolled(size_t& i, size_t nSize, const double* pCurrent)
40 {
41  size_t nRealSize = nSize - i;
42  size_t nUnrolledSize = nRealSize - (nRealSize % 4);
43 
44  if (nUnrolledSize > 0)
45  {
46  KahanSum sum0 = 0.0;
47  KahanSum sum1 = 0.0;
48  KahanSum sum2 = 0.0;
49  KahanSum sum3 = 0.0;
50 
51  for (; i + 3 < nUnrolledSize; i += 4)
52  {
53  sum0 += *pCurrent++;
54  sum1 += *pCurrent++;
55  sum2 += *pCurrent++;
56  sum3 += *pCurrent++;
57  }
58  // We are using pairwise summation alongside Kahan
59  return (sum0 + sum1) + (sum2 + sum3);
60  }
61  return 0.0;
62 }
63 
70 static inline KahanSum executeFast(size_t& i, size_t nSize, const double* pCurrent)
71 {
72 #if SC_USE_SSE2
73  return executeSSE2(i, nSize, pCurrent);
74 #else
75  return executeUnrolled(i, nSize, pCurrent);
76 #endif
77 }
78 
85 inline KahanSum sumArray(const double* pArray, size_t nSize)
86 {
87  size_t i = 0;
88  const double* pCurrent = pArray;
89  KahanSum fSum = executeFast(i, nSize, pCurrent);
90 
91  // sum rest of the array
92  for (; i < nSize; ++i)
93  fSum += pArray[i];
94 
95  // If the sum is a NaN, some of the terms were empty cells, probably.
96  // Re-calculate, carefully
97  double fVal = fSum.get();
98  if (!std::isfinite(fVal))
99  {
100  FormulaError nErr = GetDoubleErrorValue(fVal);
101  if (nErr == FormulaError::NoValue)
102  {
103  fSum = 0;
104  for (i = 0; i < nSize; i++)
105  {
106  if (!std::isfinite(pArray[i]))
107  {
108  nErr = GetDoubleErrorValue(pArray[i]);
109  if (nErr != FormulaError::NoValue)
110  fSum += pArray[i]; // Let errors encoded as NaNs propagate ???
111  }
112  else
113  fSum += pArray[i];
114  }
115  }
116  }
117  return fSum;
118 }
119 
120 } // end namespace sc::op
121 
122 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
KahanSum sumArray(const double *pArray, size_t nSize)
Performs the sum of an array.
This class provides LO with Kahan summation algorithm About this algorithm: https://en.wikipedia.org/wiki/Kahan_summation_algorithm For general purpose software we assume first order error is enough.
Definition: kahan.hxx:25
KahanSum executeSSE2(size_t &i, size_t nSize, const double *pCurrent)
FormulaError GetDoubleErrorValue(double fVal)
static KahanSum executeUnrolled(size_t &i, size_t nSize, const double *pCurrent)
If no boosts available, Unrolled KahanSum.
int i
FormulaError
static KahanSum executeFast(size_t &i, size_t nSize, const double *pCurrent)
This function task is to choose the fastest method available to perform the sum.
double get() const
Returns the final sum.
Definition: kahan.hxx:211