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"
16 #include <tools/cpuid.hxx>
17 #include <formula/errorcodes.hxx>
18 
19 namespace sc::op
20 {
21 /* Checkout available optimization options */
22 const bool hasAVX = cpuid::hasAVX();
23 const bool hasSSE2 = cpuid::hasSSE2();
24 
29 static inline KahanSum executeUnrolled(size_t& i, size_t nSize, const double* pCurrent)
30 {
31  size_t nRealSize = nSize - i;
32  size_t nUnrolledSize = nRealSize - (nRealSize % 4);
33 
34  if (nUnrolledSize > 0)
35  {
36  KahanSum sum0 = 0.0;
37  KahanSum sum1 = 0.0;
38  KahanSum sum2 = 0.0;
39  KahanSum sum3 = 0.0;
40 
41  for (; i + 3 < nUnrolledSize; i += 4)
42  {
43  sum0 += *pCurrent++;
44  sum1 += *pCurrent++;
45  sum2 += *pCurrent++;
46  sum3 += *pCurrent++;
47  }
48  // We are using pairwise summation alongside Kahan
49  return (sum0 + sum1) + (sum2 + sum3);
50  }
51  return 0.0;
52 }
53 
60 static inline KahanSum executeFast(size_t& i, size_t nSize, const double* pCurrent)
61 {
62  if (hasAVX512F)
63  return executeAVX512F(i, nSize, pCurrent);
64  if (hasAVX)
65  return executeAVX(i, nSize, pCurrent);
66  if (hasSSE2)
67  return executeSSE2(i, nSize, pCurrent);
68  return executeUnrolled(i, nSize, pCurrent);
69 }
70 
77 inline KahanSum sumArray(const double* pArray, size_t nSize)
78 {
79  size_t i = 0;
80  const double* pCurrent = pArray;
81  KahanSum fSum = executeFast(i, nSize, pCurrent);
82 
83  // sum rest of the array
84  for (; i < nSize; ++i)
85  fSum += pArray[i];
86 
87  // If the sum is a NaN, some of the terms were empty cells, probably.
88  // Re-calculate, carefully
89  double fVal = fSum.get();
90  if (!std::isfinite(fVal))
91  {
92  FormulaError nErr = GetDoubleErrorValue(fVal);
93  if (nErr == FormulaError::NoValue)
94  {
95  fSum = 0;
96  for (i = 0; i < nSize; i++)
97  {
98  if (!std::isfinite(pArray[i]))
99  {
100  nErr = GetDoubleErrorValue(pArray[i]);
101  if (nErr != FormulaError::NoValue)
102  fSum += pArray[i]; // Let errors encoded as NaNs propagate ???
103  }
104  else
105  fSum += pArray[i];
106  }
107  }
108  }
109  return fSum;
110 }
111 
112 } // end namespace sc::op
113 
114 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
KahanSum sumArray(const double *pArray, size_t nSize)
Performs the sum of an array.
const bool hasAVX512F
bool hasSSE2()
KahanSumSimple executeSSE2(size_t &i, size_t nSize, const double *pCurrent)
Execute Kahan sum with SSE2.
KahanSumSimple executeAVX(size_t &i, size_t nSize, const double *pCurrent)
Execute Kahan sum with AVX.
Definition: arraysumAVX.cxx:55
constexpr double get() const
Returns the final sum.
Definition: kahan.hxx:207
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:23
FormulaError GetDoubleErrorValue(double fVal)
static KahanSum executeUnrolled(size_t &i, size_t nSize, const double *pCurrent)
If no boosts available, Unrolled KahanSum.
KahanSumSimple executeAVX512F(size_t &i, size_t nSize, const double *pCurrent)
Execute Kahan sum with AVX512.
int i
FormulaError
const bool hasSSE2
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.
bool hasAVX()
const bool hasAVX