LibreOffice Module sc (master)  1
subtotal.cxx
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  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <subtotal.hxx>
21 #include <interpre.hxx>
22 #include <cfloat>
23 
24 bool SubTotal::SafePlus(double& fVal1, double fVal2)
25 {
26  bool bOk = true;
28  fVal1 += fVal2;
29  if (!std::isfinite(fVal1))
30  {
31  bOk = false;
32  if (fVal2 > 0.0)
33  fVal1 = DBL_MAX;
34  else
35  fVal1 = -DBL_MAX;
36  }
37  return bOk;
38 }
39 
40 bool SubTotal::SafeMult(double& fVal1, double fVal2)
41 {
42  bool bOk = true;
44  fVal1 *= fVal2;
45  if (!std::isfinite(fVal1))
46  {
47  bOk = false;
48  fVal1 = DBL_MAX;
49  }
50  return bOk;
51 }
52 
53 bool SubTotal::SafeDiv(double& fVal1, double fVal2)
54 {
55  bool bOk = true;
57  fVal1 /= fVal2;
58  if (!std::isfinite(fVal1))
59  {
60  bOk = false;
61  fVal1 = DBL_MAX;
62  }
63  return bOk;
64 }
65 
66 void ScFunctionData::update( double fNewVal )
67 {
68  if (mbError)
69  return;
70 
71  switch (meFunc)
72  {
73  case SUBTOTAL_FUNC_SUM:
74  if (!SubTotal::SafePlus(getValueRef(), fNewVal))
75  mbError = true;
76  break;
77  case SUBTOTAL_FUNC_PROD:
78  if (getCountRef() == 0) // copy first value (nVal is initialized to 0)
79  {
80  getValueRef() = fNewVal;
81  getCountRef() = 1; // don't care about further count
82  }
83  else if (!SubTotal::SafeMult(getValueRef(), fNewVal))
84  mbError = true;
85  break;
86  case SUBTOTAL_FUNC_CNT:
87  case SUBTOTAL_FUNC_CNT2:
88  ++getCountRef();
89  break;
91  getCountRef() += fNewVal;
92  break;
93  case SUBTOTAL_FUNC_AVE:
94  if (!SubTotal::SafePlus(getValueRef(), fNewVal))
95  mbError = true;
96  else
97  ++getCountRef();
98  break;
99  case SUBTOTAL_FUNC_MAX:
100  if (getCountRef() == 0) // copy first value (nVal is initialized to 0)
101  {
102  getValueRef() = fNewVal;
103  getCountRef() = 1; // don't care about further count
104  }
105  else if (fNewVal > getValueRef())
106  getValueRef() = fNewVal;
107  break;
108  case SUBTOTAL_FUNC_MIN:
109  if (getCountRef() == 0) // copy first value (nVal is initialized to 0)
110  {
111  getValueRef() = fNewVal;
112  getCountRef() = 1; // don't care about further count
113  }
114  else if (fNewVal < getValueRef())
115  getValueRef() = fNewVal;
116  break;
117  case SUBTOTAL_FUNC_VAR:
118  case SUBTOTAL_FUNC_STD:
119  case SUBTOTAL_FUNC_VARP:
120  case SUBTOTAL_FUNC_STDP:
121  maWelford.update( fNewVal);
122  break;
123  default:
124  // unhandled unknown
125  mbError = true;
126  }
127 }
128 
130 {
131  if (mbError)
132  return 0.0;
133 
134  double fRet = 0.0;
135  switch (meFunc)
136  {
137  case SUBTOTAL_FUNC_CNT:
138  case SUBTOTAL_FUNC_CNT2:
140  fRet = getCountRef();
141  break;
142  case SUBTOTAL_FUNC_SUM:
143  case SUBTOTAL_FUNC_MAX:
144  case SUBTOTAL_FUNC_MIN:
145  // Note that nVal is 0.0 for MAX and MIN if nCount==0, that's also
146  // how it is defined in ODFF.
147  fRet = getValueRef();
148  break;
149  case SUBTOTAL_FUNC_PROD:
150  fRet = (getCountRef() > 0) ? getValueRef() : 0.0;
151  break;
152  case SUBTOTAL_FUNC_AVE:
153  if (getCountRef() == 0)
154  mbError = true;
155  else
156  fRet = getValueRef() / getCountRef();
157  break;
158  case SUBTOTAL_FUNC_VAR:
159  case SUBTOTAL_FUNC_STD:
160  if (maWelford.getCount() < 2)
161  mbError = true;
162  else
163  {
164  fRet = maWelford.getVarianceSample();
165  if (fRet < 0.0)
166  mbError = true;
167  else if (meFunc == SUBTOTAL_FUNC_STD)
168  fRet = sqrt( fRet);
169  }
170  break;
171  case SUBTOTAL_FUNC_VARP:
172  case SUBTOTAL_FUNC_STDP:
173  if (maWelford.getCount() < 1)
174  mbError = true;
175  else if (maWelford.getCount() == 1)
176  fRet = 0.0;
177  else
178  {
180  if (fRet < 0.0)
181  mbError = true;
182  else if (meFunc == SUBTOTAL_FUNC_STDP)
183  fRet = sqrt( fRet);
184  }
185  break;
186  default:
187  assert(!"unhandled unknown");
188  mbError = true;
189  break;
190  }
191  if (mbError)
192  fRet = 0.0;
193  return fRet;
194 }
195 
196 void WelfordRunner::update( double fVal )
197 {
198  ++mnCount;
199  const double fDelta = fVal - mfMean;
200  mfMean += fDelta / mnCount;
201  mfM2 += fDelta * (fVal - mfMean);
202 }
203 
204 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScSubTotalFunc meFunc
Definition: subtotal.hxx:76
double getVarianceSample() const
Definition: subtotal.hxx:45
double getVariancePopulation() const
Definition: subtotal.hxx:46
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
static bool SafeMult(double &fVal1, double fVal2)
Definition: subtotal.cxx:40
sal_uInt64 & getCountRef()
Definition: subtotal.hxx:80
sal_uInt64 mnCount
Definition: subtotal.hxx:57
double getResult()
Check getError() after (!) obtaining the result.
Definition: subtotal.cxx:129
static bool SafePlus(double &fVal1, double fVal2)
Definition: subtotal.cxx:24
double mfMean
Definition: subtotal.hxx:55
static bool SafeDiv(double &fVal1, double fVal2)
Definition: subtotal.cxx:53
double & getValueRef()
Definition: subtotal.hxx:79
sal_uInt64 getCount() const
Definition: subtotal.hxx:44
WelfordRunner maWelford
Definition: subtotal.hxx:75
void update(double fNewVal)
Definition: subtotal.cxx:66
void update(double fVal)
Definition: subtotal.cxx:196
double mfM2
Definition: subtotal.hxx:56
#define SAL_MATH_FPEXCEPTIONS_OFF()