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 #ifndef INCLUDED_SC_SOURCE_CORE_INC_ARRAYSUMFUNCTOR_HXX
12 #define INCLUDED_SC_SOURCE_CORE_INC_ARRAYSUMFUNCTOR_HXX
13 
14 #include <cstdint>
15 #include <rtl/math.hxx>
16 
17 #include <tools/simd.hxx>
18 #include <tools/cpuid.hxx>
19 
20 namespace sc
21 {
22 
24 {
25 private:
26  const double* mpArray;
27  size_t mnSize;
28 
29 public:
30  ArraySumFunctor(const double* pArray, size_t nSize)
31  : mpArray(pArray)
32  , mnSize(nSize)
33  {
34  }
35 
36  double operator() ()
37  {
38  const static bool hasSSE2 = cpuid::hasSSE2();
39 
40  double fSum = 0.0;
41  size_t i = 0;
42  const double* pCurrent = mpArray;
43 
44  if (hasSSE2)
45  {
46  while ( i < mnSize && !simd::isAligned<double, 16>(pCurrent))
47  {
48  fSum += *pCurrent++;
49  i++;
50  }
51  if( i < mnSize )
52  {
53  fSum += executeSSE2(i, pCurrent);
54  }
55  }
56  else
57  fSum += executeUnrolled(i, pCurrent);
58 
59  // sum rest of the array
60 
61  for (; i < mnSize; ++i)
62  fSum += mpArray[i];
63 
64  // If the sum is a NaN, some of the terms were empty cells, probably.
65  // Re-calculate, carefully
66  if (!std::isfinite(fSum))
67  {
68  sal_uInt32 nErr = reinterpret_cast< sal_math_Double * >(&fSum)->nan_parts.fraction_lo;
69  if (nErr & 0xffff0000)
70  {
71  fSum = 0;
72  for (i = 0; i < mnSize; i++)
73  {
74  if (!std::isfinite(mpArray[i]))
75  {
76  nErr = reinterpret_cast< const sal_math_Double * >(&mpArray[i])->nan_parts.fraction_lo;
77  if (!(nErr & 0xffff0000))
78  fSum += mpArray[i]; // Let errors encoded as NaNs propagate ???
79  }
80  else
81  fSum += mpArray[i];
82  }
83  }
84  }
85  return fSum;
86  }
87 
88 private:
89 
90  double executeSSE2(size_t& i, const double* pCurrent) const;
91  double executeUnrolled(size_t& i, const double* pCurrent) const
92  {
93  size_t nRealSize = mnSize - i;
94  size_t nUnrolledSize = nRealSize - (nRealSize % 4);
95 
96  if (nUnrolledSize > 0)
97  {
98  double sum0 = 0.0;
99  double sum1 = 0.0;
100  double sum2 = 0.0;
101  double sum3 = 0.0;
102 
103  for (; i < nUnrolledSize; i += 4)
104  {
105  sum0 += *pCurrent++;
106  sum1 += *pCurrent++;
107  sum2 += *pCurrent++;
108  sum3 += *pCurrent++;
109  }
110  return sum0 + sum1 + sum2 + sum3;
111  }
112  return 0.0;
113  }
114 };
115 
116 } // end namespace sc
117 
118 #endif
119 
120 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const double * mpArray
bool hasSSE2()
double executeUnrolled(size_t &i, const double *pCurrent) const
int i
ArraySumFunctor(const double *pArray, size_t nSize)
double executeSSE2(size_t &i, const double *pCurrent) const
if(!pCandidateA->getEnd().equal(pCandidateB->getStart()))