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"
17
18namespace 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
30KahanSum executeSSE2(size_t& i, size_t nSize, const double* pCurrent);
31#else
32#define SC_USE_SSE2 0
33#endif
34
39static 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
70static 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
85inline 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 {
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: */
This class provides LO with Kahan summation algorithm About this algorithm: https://en....
Definition: kahan.hxx:26
double get() const
Returns the final sum.
Definition: kahan.hxx:211
FormulaError
FormulaError GetDoubleErrorValue(double fVal)
int i
static KahanSum executeUnrolled(size_t &i, size_t nSize, const double *pCurrent)
If no boosts available, Unrolled KahanSum.
KahanSum executeSSE2(size_t &i, size_t nSize, const double *pCurrent)
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.
KahanSum sumArray(const double *pArray, size_t nSize)
Performs the sum of an array.