Line data Source code
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 "interpre.hxx"
21 : #include "columnspanset.hxx"
22 : #include "column.hxx"
23 : #include "document.hxx"
24 : #include "cellvalue.hxx"
25 : #include "dociter.hxx"
26 : #include "mtvcellfunc.hxx"
27 : #include "scmatrix.hxx"
28 :
29 : #include <formula/token.hxx>
30 :
31 : using namespace formula;
32 :
33 : double const fHalfMachEps = 0.5 * ::std::numeric_limits<double>::epsilon();
34 :
35 : // The idea how this group of gamma functions is calculated, is
36 : // based on the Cephes library
37 : // online http://www.moshier.net/#Cephes [called 2008-02]
38 :
39 : /** You must ensure fA>0.0 && fX>0.0
40 : valid results only if fX > fA+1.0
41 : uses continued fraction with odd items */
42 188 : double ScInterpreter::GetGammaContFraction( double fA, double fX )
43 : {
44 :
45 188 : double const fBigInv = ::std::numeric_limits<double>::epsilon();
46 188 : double const fBig = 1.0/fBigInv;
47 188 : double fCount = 0.0;
48 188 : double fY = 1.0 - fA;
49 188 : double fDenom = fX + 2.0-fA;
50 188 : double fPkm1 = fX + 1.0;
51 188 : double fPkm2 = 1.0;
52 188 : double fQkm1 = fDenom * fX;
53 188 : double fQkm2 = fX;
54 188 : double fApprox = fPkm1/fQkm1;
55 188 : bool bFinished = false;
56 3984 : do
57 : {
58 3984 : fCount = fCount +1.0;
59 3984 : fY = fY+ 1.0;
60 3984 : const double fNum = fY * fCount;
61 3984 : fDenom = fDenom +2.0;
62 3984 : double fPk = fPkm1 * fDenom - fPkm2 * fNum;
63 3984 : const double fQk = fQkm1 * fDenom - fQkm2 * fNum;
64 3984 : if (fQk != 0.0)
65 : {
66 3984 : const double fR = fPk/fQk;
67 3984 : bFinished = (fabs( (fApprox - fR)/fR ) <= fHalfMachEps);
68 3984 : fApprox = fR;
69 : }
70 3984 : fPkm2 = fPkm1;
71 3984 : fPkm1 = fPk;
72 3984 : fQkm2 = fQkm1;
73 3984 : fQkm1 = fQk;
74 3984 : if (fabs(fPk) > fBig)
75 : {
76 : // reduce a fraction does not change the value
77 244 : fPkm2 = fPkm2 * fBigInv;
78 244 : fPkm1 = fPkm1 * fBigInv;
79 244 : fQkm2 = fQkm2 * fBigInv;
80 244 : fQkm1 = fQkm1 * fBigInv;
81 : }
82 7780 : } while (!bFinished && fCount<10000);
83 : // most iterations, if fX==fAlpha+1.0; approx sqrt(fAlpha) iterations then
84 188 : if (!bFinished)
85 : {
86 0 : SetError(errNoConvergence);
87 : }
88 188 : return fApprox;
89 : }
90 :
91 : /** You must ensure fA>0.0 && fX>0.0
92 : valid results only if fX <= fA+1.0
93 : uses power series */
94 343 : double ScInterpreter::GetGammaSeries( double fA, double fX )
95 : {
96 343 : double fDenomfactor = fA;
97 343 : double fSummand = 1.0/fA;
98 343 : double fSum = fSummand;
99 343 : int nCount=1;
100 4793 : do
101 : {
102 4793 : fDenomfactor = fDenomfactor + 1.0;
103 4793 : fSummand = fSummand * fX/fDenomfactor;
104 4793 : fSum = fSum + fSummand;
105 4793 : nCount = nCount+1;
106 9243 : } while ( fSummand/fSum > fHalfMachEps && nCount<=10000);
107 : // large amount of iterations will be carried out for huge fAlpha, even
108 : // if fX <= fAlpha+1.0
109 343 : if (nCount>10000)
110 : {
111 0 : SetError(errNoConvergence);
112 : }
113 343 : return fSum;
114 : }
115 :
116 : /** You must ensure fA>0.0 && fX>0.0) */
117 327 : double ScInterpreter::GetLowRegIGamma( double fA, double fX )
118 : {
119 327 : double fLnFactor = fA * log(fX) - fX - GetLogGamma(fA);
120 327 : double fFactor = exp(fLnFactor); // Do we need more accuracy than exp(ln()) has?
121 327 : if (fX>fA+1.0) // includes fX>1.0; 1-GetUpRegIGamma, continued fraction
122 11 : return 1.0 - fFactor * GetGammaContFraction(fA,fX);
123 : else // fX<=1.0 || fX<=fA+1.0, series
124 316 : return fFactor * GetGammaSeries(fA,fX);
125 : }
126 :
127 : /** You must ensure fA>0.0 && fX>0.0) */
128 204 : double ScInterpreter::GetUpRegIGamma( double fA, double fX )
129 : {
130 :
131 204 : double fLnFactor= fA*log(fX)-fX-GetLogGamma(fA);
132 204 : double fFactor = exp(fLnFactor); //Do I need more accuracy than exp(ln()) has?;
133 204 : if (fX>fA+1.0) // includes fX>1.0
134 177 : return fFactor * GetGammaContFraction(fA,fX);
135 : else //fX<=1 || fX<=fA+1, 1-GetLowRegIGamma, series
136 27 : return 1.0 -fFactor * GetGammaSeries(fA,fX);
137 : }
138 :
139 : /** Gamma distribution, probability density function.
140 : fLambda is "scale" parameter
141 : You must ensure fAlpha>0.0 and fLambda>0.0 */
142 0 : double ScInterpreter::GetGammaDistPDF( double fX, double fAlpha, double fLambda )
143 : {
144 0 : if (fX < 0.0)
145 0 : return 0.0; // see ODFF
146 0 : else if (fX == 0)
147 : // in this case 0^0 isn't zero
148 : {
149 0 : if (fAlpha < 1.0)
150 : {
151 0 : SetError(errDivisionByZero); // should be #DIV/0
152 0 : return HUGE_VAL;
153 : }
154 0 : else if (fAlpha == 1)
155 : {
156 0 : return (1.0 / fLambda);
157 : }
158 : else
159 : {
160 0 : return 0.0;
161 : }
162 : }
163 : else
164 : {
165 0 : double fXr = fX / fLambda;
166 : // use exp(ln()) only for large arguments because of less accuracy
167 0 : if (fXr > 1.0)
168 : {
169 0 : const double fLogDblMax = log( ::std::numeric_limits<double>::max());
170 0 : if (log(fXr) * (fAlpha-1.0) < fLogDblMax && fAlpha < fMaxGammaArgument)
171 : {
172 0 : return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / GetGamma(fAlpha);
173 : }
174 : else
175 : {
176 0 : return exp( (fAlpha-1.0) * log(fXr) - fXr - log(fLambda) - GetLogGamma(fAlpha));
177 : }
178 : }
179 : else // fXr near to zero
180 : {
181 0 : if (fAlpha<fMaxGammaArgument)
182 : {
183 0 : return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / GetGamma(fAlpha);
184 : }
185 : else
186 : {
187 0 : return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / exp( GetLogGamma(fAlpha));
188 : }
189 : }
190 : }
191 : }
192 :
193 : /** Gamma distribution, cumulative distribution function.
194 : fLambda is "scale" parameter
195 : You must ensure fAlpha>0.0 and fLambda>0.0 */
196 246 : double ScInterpreter::GetGammaDist( double fX, double fAlpha, double fLambda )
197 : {
198 246 : if (fX <= 0.0)
199 3 : return 0.0;
200 : else
201 243 : return GetLowRegIGamma( fAlpha, fX / fLambda);
202 : }
203 :
204 : namespace {
205 :
206 : class NumericCellAccumulator
207 : {
208 : double mfSum;
209 : sal_uInt16 mnError;
210 :
211 : public:
212 2852 : NumericCellAccumulator() : mfSum(0.0), mnError(0) {}
213 :
214 5016 : void operator() (size_t, double fVal)
215 : {
216 5016 : mfSum += fVal;
217 5016 : }
218 :
219 771 : void operator() (size_t, const ScFormulaCell* pCell)
220 : {
221 771 : if (mnError)
222 : // Skip all the rest if we have an error.
223 4 : return;
224 :
225 770 : double fVal = 0.0;
226 770 : sal_uInt16 nErr = 0;
227 770 : ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*pCell);
228 770 : if (!rCell.GetErrorOrValue(nErr, fVal))
229 : // The cell has neither error nor value. Perhaps string result.
230 0 : return;
231 :
232 770 : if (nErr)
233 : {
234 : // Cell has error.
235 2 : mnError = nErr;
236 2 : return;
237 : }
238 :
239 768 : mfSum += fVal;
240 : }
241 :
242 2852 : sal_uInt16 getError() const { return mnError; }
243 2850 : double getSum() const { return mfSum; }
244 : };
245 :
246 : class NumericCellCounter
247 : {
248 : size_t mnCount;
249 : public:
250 42 : NumericCellCounter() : mnCount(0) {}
251 :
252 70 : void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize)
253 : {
254 70 : switch (rNode.type)
255 : {
256 : case sc::element_type_numeric:
257 34 : mnCount += nDataSize;
258 34 : break;
259 : case sc::element_type_formula:
260 : {
261 22 : sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
262 22 : std::advance(it, nOffset);
263 22 : sc::formula_block::const_iterator itEnd = it;
264 22 : std::advance(itEnd, nDataSize);
265 56 : for (; it != itEnd; ++it)
266 : {
267 34 : ScFormulaCell& rCell = const_cast<ScFormulaCell&>(**it);
268 34 : if (rCell.IsValueNoError())
269 32 : ++mnCount;
270 : }
271 : }
272 22 : break;
273 : default:
274 : ;
275 : }
276 70 : }
277 :
278 42 : size_t getCount() const { return mnCount; }
279 : };
280 :
281 27 : class FuncCount : public sc::ColumnSpanSet::ColumnAction
282 : {
283 : sc::ColumnBlockConstPosition maPos;
284 : ScColumn* mpCol;
285 : size_t mnCount;
286 : sal_uInt32 mnNumFmt;
287 :
288 : public:
289 27 : FuncCount() : mpCol(0), mnCount(0), mnNumFmt(0) {}
290 :
291 42 : virtual void startColumn(ScColumn* pCol) SAL_OVERRIDE
292 : {
293 42 : mpCol = pCol;
294 42 : mpCol->InitBlockPosition(maPos);
295 42 : }
296 :
297 84 : virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) SAL_OVERRIDE
298 : {
299 84 : if (!bVal)
300 126 : return;
301 :
302 42 : NumericCellCounter aFunc;
303 42 : maPos.miCellPos = sc::ParseBlock(maPos.miCellPos, mpCol->GetCellStore(), aFunc, nRow1, nRow2);
304 42 : mnCount += aFunc.getCount();
305 42 : mnNumFmt = mpCol->GetNumberFormat(nRow2);
306 : };
307 :
308 27 : size_t getCount() const { return mnCount; }
309 27 : sal_uInt32 getNumberFormat() const { return mnNumFmt; }
310 : };
311 :
312 992 : class FuncSum : public sc::ColumnSpanSet::ColumnAction
313 : {
314 : sc::ColumnBlockConstPosition maPos;
315 : ScColumn* mpCol;
316 : double mfSum;
317 : sal_uInt16 mnError;
318 : sal_uInt32 mnNumFmt;
319 :
320 : public:
321 992 : FuncSum() : mpCol(0), mfSum(0.0), mnError(0), mnNumFmt(0) {}
322 :
323 2852 : virtual void startColumn(ScColumn* pCol) SAL_OVERRIDE
324 : {
325 2852 : mpCol = pCol;
326 2852 : mpCol->InitBlockPosition(maPos);
327 2852 : }
328 :
329 8303 : virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) SAL_OVERRIDE
330 : {
331 8303 : if (!bVal)
332 10904 : return;
333 :
334 2852 : if (mnError)
335 0 : return;
336 :
337 2852 : NumericCellAccumulator aFunc;
338 2852 : maPos.miCellPos = sc::ParseFormulaNumeric(maPos.miCellPos, mpCol->GetCellStore(), nRow1, nRow2, aFunc);
339 2852 : mnError = aFunc.getError();
340 2852 : if (mnError)
341 2 : return;
342 :
343 2850 : mfSum += aFunc.getSum();
344 2850 : mnNumFmt = mpCol->GetNumberFormat(nRow2);
345 : };
346 :
347 992 : sal_uInt16 getError() const { return mnError; }
348 990 : double getSum() const { return mfSum; }
349 990 : sal_uInt32 getNumberFormat() const { return mnNumFmt; }
350 : };
351 :
352 17 : void IterateMatrix(
353 : const ScMatrixRef& pMat, ScIterFunc eFunc, bool bTextAsZero,
354 : sal_uLong& rCount, short& rFuncFmtType, double& fRes, double& fMem, bool& bNull)
355 : {
356 17 : if (!pMat)
357 17 : return;
358 :
359 : // TODO fdo73148 take mnSubTotalFlags into account
360 17 : rFuncFmtType = css::util::NumberFormat::NUMBER;
361 17 : switch (eFunc)
362 : {
363 : case ifAVERAGE:
364 : case ifSUM:
365 : {
366 7 : ScMatrix::IterateResult aRes = pMat->Sum(bTextAsZero);
367 7 : if (bNull)
368 : {
369 7 : bNull = false;
370 7 : fMem = aRes.mfFirst;
371 7 : fRes += aRes.mfRest;
372 : }
373 : else
374 0 : fRes += aRes.mfFirst + aRes.mfRest;
375 7 : rCount += aRes.mnCount;
376 : }
377 7 : break;
378 : case ifCOUNT:
379 2 : rCount += pMat->Count(bTextAsZero);
380 2 : break;
381 : case ifCOUNT2:
382 1 : rCount += pMat->Count(true);
383 1 : break;
384 : case ifPRODUCT:
385 : {
386 7 : ScMatrix::IterateResult aRes = pMat->Product(bTextAsZero);
387 7 : fRes = aRes.mfFirst;
388 7 : fRes *= aRes.mfRest;
389 7 : rCount += aRes.mnCount;
390 : }
391 7 : break;
392 : case ifSUMSQ:
393 : {
394 0 : ScMatrix::IterateResult aRes = pMat->SumSquare(bTextAsZero);
395 0 : fRes += aRes.mfRest;
396 0 : rCount += aRes.mnCount;
397 : }
398 0 : break;
399 : default:
400 : ;
401 : }
402 : }
403 :
404 : }
405 :
406 357 : double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
407 : {
408 357 : short nParamCount = GetByte();
409 357 : double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
410 357 : double fVal = 0.0;
411 357 : double fMem = 0.0; // first numeric value.
412 357 : bool bNull = true;
413 357 : sal_uLong nCount = 0;
414 357 : ScAddress aAdr;
415 357 : ScRange aRange;
416 357 : size_t nRefInList = 0;
417 357 : if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
418 0 : ( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL ) ) )
419 0 : nGlobalError = 0;
420 1098 : while (nParamCount-- > 0)
421 : {
422 384 : switch (GetStackType())
423 : {
424 : case svString:
425 : {
426 3 : if( eFunc == ifCOUNT )
427 : {
428 0 : OUString aStr = PopString().getString();
429 0 : if ( bTextAsZero )
430 0 : nCount++;
431 : else
432 : {
433 : // Only check if string can be converted to number, no
434 : // error propagation.
435 0 : sal_uInt16 nErr = nGlobalError;
436 0 : nGlobalError = 0;
437 0 : ConvertStringToValue( aStr );
438 0 : if (!nGlobalError)
439 0 : ++nCount;
440 0 : nGlobalError = nErr;
441 0 : }
442 : }
443 : else
444 : {
445 3 : switch ( eFunc )
446 : {
447 : case ifAVERAGE:
448 : case ifSUM:
449 : case ifSUMSQ:
450 : case ifPRODUCT:
451 : {
452 0 : if ( bTextAsZero )
453 : {
454 0 : Pop();
455 0 : nCount++;
456 0 : if ( eFunc == ifPRODUCT )
457 0 : fRes = 0.0;
458 : }
459 : else
460 : {
461 0 : while (nParamCount-- > 0)
462 0 : Pop();
463 0 : SetError( errNoValue );
464 : }
465 : }
466 0 : break;
467 : default:
468 3 : Pop();
469 3 : nCount++;
470 : }
471 : }
472 : }
473 3 : break;
474 : case svDouble :
475 28 : fVal = GetDouble();
476 28 : nCount++;
477 28 : switch( eFunc )
478 : {
479 : case ifAVERAGE:
480 : case ifSUM:
481 7 : if ( bNull && fVal != 0.0 )
482 : {
483 2 : bNull = false;
484 2 : fMem = fVal;
485 : }
486 : else
487 5 : fRes += fVal;
488 7 : break;
489 3 : case ifSUMSQ: fRes += fVal * fVal; break;
490 9 : case ifPRODUCT: fRes *= fVal; break;
491 : default: ; // nothing
492 : }
493 28 : nFuncFmtType = css::util::NumberFormat::NUMBER;
494 28 : break;
495 : case svExternalSingleRef:
496 : {
497 0 : ScExternalRefCache::TokenRef pToken;
498 0 : ScExternalRefCache::CellFormat aFmt;
499 0 : PopExternalSingleRef(pToken, &aFmt);
500 0 : if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
501 0 : ( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL ) ) )
502 : {
503 0 : nGlobalError = 0;
504 0 : if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL ) )
505 0 : ++nCount;
506 0 : break;
507 : }
508 :
509 0 : if (!pToken)
510 0 : break;
511 :
512 0 : StackVar eType = pToken->GetType();
513 0 : if (eFunc == ifCOUNT2)
514 : {
515 0 : if ( eType != formula::svEmptyCell &&
516 0 : ( ( pToken->GetOpCode() != ocSubTotal &&
517 0 : pToken->GetOpCode() != ocAggregate ) ||
518 0 : ( mnSubTotalFlags & SUBTOTAL_IGN_NESTED_ST_AG ) ) )
519 0 : nCount++;
520 0 : if (nGlobalError)
521 0 : nGlobalError = 0;
522 : }
523 0 : else if (eType == formula::svDouble)
524 : {
525 0 : nCount++;
526 0 : fVal = pToken->GetDouble();
527 0 : if (aFmt.mbIsSet)
528 : {
529 0 : nFuncFmtType = aFmt.mnType;
530 0 : nFuncFmtIndex = aFmt.mnIndex;
531 : }
532 0 : switch( eFunc )
533 : {
534 : case ifAVERAGE:
535 : case ifSUM:
536 0 : if ( bNull && fVal != 0.0 )
537 : {
538 0 : bNull = false;
539 0 : fMem = fVal;
540 : }
541 : else
542 0 : fRes += fVal;
543 0 : break;
544 0 : case ifSUMSQ: fRes += fVal * fVal; break;
545 0 : case ifPRODUCT: fRes *= fVal; break;
546 : case ifCOUNT:
547 0 : if ( nGlobalError )
548 : {
549 0 : nGlobalError = 0;
550 0 : nCount--;
551 : }
552 0 : break;
553 : default: ; // nothing
554 : }
555 : }
556 0 : else if (bTextAsZero && eType == formula::svString)
557 : {
558 0 : nCount++;
559 0 : if ( eFunc == ifPRODUCT )
560 0 : fRes = 0.0;
561 0 : }
562 : }
563 0 : break;
564 : case svSingleRef :
565 : {
566 3 : PopSingleRef( aAdr );
567 3 : if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
568 0 : ( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL ) ) )
569 : {
570 0 : nGlobalError = 0;
571 0 : if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL ) )
572 0 : ++nCount;
573 0 : break;
574 : }
575 3 : if ( ( mnSubTotalFlags & SUBTOTAL_IGN_FILTERED ) &&
576 0 : pDok->RowFiltered( aAdr.Row(), aAdr.Tab() ) )
577 : {
578 0 : break;
579 : }
580 3 : ScRefCellValue aCell;
581 3 : aCell.assign(*pDok, aAdr);
582 3 : if (!aCell.isEmpty())
583 : {
584 3 : if( eFunc == ifCOUNT2 )
585 : {
586 0 : CellType eCellType = aCell.meType;
587 0 : if ( eCellType != CELLTYPE_NONE )
588 0 : nCount++;
589 0 : if ( nGlobalError )
590 0 : nGlobalError = 0;
591 : }
592 3 : else if (aCell.hasNumeric())
593 : {
594 3 : nCount++;
595 3 : fVal = GetCellValue(aAdr, aCell);
596 3 : CurFmtToFuncFmt();
597 3 : switch( eFunc )
598 : {
599 : case ifAVERAGE:
600 : case ifSUM:
601 0 : if ( bNull && fVal != 0.0 )
602 : {
603 0 : bNull = false;
604 0 : fMem = fVal;
605 : }
606 : else
607 0 : fRes += fVal;
608 0 : break;
609 3 : case ifSUMSQ: fRes += fVal * fVal; break;
610 0 : case ifPRODUCT: fRes *= fVal; break;
611 : case ifCOUNT:
612 0 : if ( nGlobalError )
613 : {
614 0 : nGlobalError = 0;
615 0 : nCount--;
616 : }
617 0 : break;
618 : default: ; // nothing
619 : }
620 : }
621 0 : else if (bTextAsZero && aCell.hasString())
622 : {
623 0 : nCount++;
624 0 : if ( eFunc == ifPRODUCT )
625 0 : fRes = 0.0;
626 : }
627 3 : }
628 : }
629 3 : break;
630 : case svDoubleRef :
631 : case svRefList :
632 : {
633 340 : PopDoubleRef( aRange, nParamCount, nRefInList);
634 340 : if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
635 0 : ( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL ) ) )
636 : {
637 0 : nGlobalError = 0;
638 0 : if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL ) )
639 0 : ++nCount;
640 0 : if ( eFunc == ifCOUNT2 || eFunc == ifCOUNT )
641 : break;
642 : }
643 340 : if( eFunc == ifCOUNT2 )
644 : {
645 62 : ScCellIterator aIter( pDok, aRange, mnSubTotalFlags );
646 604 : for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
647 : {
648 542 : if ( !aIter.hasEmptyData() )
649 : {
650 542 : ++nCount;
651 : }
652 : }
653 :
654 62 : if ( nGlobalError )
655 0 : nGlobalError = 0;
656 : }
657 : else
658 : {
659 278 : ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero );
660 278 : sal_uInt16 nErr = 0;
661 278 : if (aValIter.GetFirst(fVal, nErr))
662 : {
663 : // placed the loop on the inside for performance reasons:
664 278 : aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
665 278 : switch( eFunc )
666 : {
667 : case ifAVERAGE:
668 : case ifSUM:
669 166 : if ( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL )
670 : {
671 402 : do
672 : {
673 402 : if ( !nErr )
674 : {
675 402 : SetError(nErr);
676 402 : if ( bNull && fVal != 0.0 )
677 : {
678 45 : bNull = false;
679 45 : fMem = fVal;
680 : }
681 : else
682 357 : fRes += fVal;
683 402 : nCount++;
684 : }
685 : }
686 : while (aValIter.GetNext(fVal, nErr));
687 : }
688 : else
689 : {
690 803 : do
691 : {
692 803 : SetError(nErr);
693 803 : if ( bNull && fVal != 0.0 )
694 : {
695 121 : bNull = false;
696 121 : fMem = fVal;
697 : }
698 : else
699 682 : fRes += fVal;
700 803 : nCount++;
701 : }
702 : while (aValIter.GetNext(fVal, nErr));
703 : }
704 166 : break;
705 : case ifSUMSQ:
706 6 : if ( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL )
707 : {
708 0 : do
709 : {
710 0 : if ( !nErr )
711 : {
712 0 : SetError(nErr);
713 0 : fRes += fVal * fVal;
714 0 : nCount++;
715 : }
716 : }
717 : while (aValIter.GetNext(fVal, nErr));
718 : }
719 : else
720 : {
721 21 : do
722 : {
723 21 : SetError(nErr);
724 21 : fRes += fVal * fVal;
725 21 : nCount++;
726 : }
727 : while (aValIter.GetNext(fVal, nErr));
728 : }
729 6 : break;
730 : case ifPRODUCT:
731 516 : do
732 : {
733 516 : if ( !( nErr && ( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL ) ) )
734 : {
735 516 : SetError(nErr);
736 516 : fRes *= fVal;
737 516 : nCount++;
738 : }
739 : }
740 : while (aValIter.GetNext(fVal, nErr));
741 61 : break;
742 : case ifCOUNT:
743 402 : do
744 : {
745 402 : if ( !nErr )
746 402 : nCount++;
747 : }
748 : while (aValIter.GetNext(fVal, nErr));
749 45 : break;
750 : default: ; // nothing
751 : }
752 278 : SetError( nErr );
753 : }
754 : }
755 : }
756 340 : break;
757 : case svExternalDoubleRef:
758 : {
759 3 : ScMatrixRef pMat;
760 3 : PopExternalDoubleRef(pMat);
761 3 : if ( nGlobalError && !( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL ) )
762 0 : break;
763 :
764 3 : IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fRes, fMem, bNull);
765 : }
766 3 : break;
767 : case svMatrix :
768 : {
769 7 : ScMatrixRef pMat = PopMatrix();
770 7 : IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fRes, fMem, bNull);
771 : }
772 7 : break;
773 : case svError:
774 : {
775 0 : PopError();
776 0 : if ( eFunc == ifCOUNT || ( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL ) )
777 : {
778 0 : nGlobalError = 0;
779 : }
780 0 : else if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SUBTOTAL_IGN_ERR_VAL ) )
781 : {
782 0 : nCount++;
783 0 : nGlobalError = 0;
784 : }
785 : }
786 0 : break;
787 : default :
788 0 : while (nParamCount-- > 0)
789 0 : PopError();
790 0 : SetError(errIllegalParameter);
791 : }
792 : }
793 357 : switch( eFunc )
794 : {
795 53 : case ifSUM: fRes = ::rtl::math::approxAdd( fRes, fMem ); break;
796 117 : case ifAVERAGE: fRes = div(::rtl::math::approxAdd( fRes, fMem ), nCount); break;
797 : case ifCOUNT2:
798 108 : case ifCOUNT: fRes = nCount; break;
799 71 : case ifPRODUCT: if ( !nCount ) fRes = 0.0; break;
800 : default: ; // nothing
801 : }
802 : // Bei Summen etc. macht ein bool-Ergebnis keinen Sinn
803 : // und Anzahl ist immer Number (#38345#)
804 357 : if( eFunc == ifCOUNT || nFuncFmtType == css::util::NumberFormat::LOGICAL )
805 45 : nFuncFmtType = css::util::NumberFormat::NUMBER;
806 357 : return fRes;
807 : }
808 :
809 8 : void ScInterpreter::ScSumSQ()
810 : {
811 8 : PushDouble( IterateParameters( ifSUMSQ ) );
812 8 : }
813 :
814 1060 : void ScInterpreter::ScSum()
815 : {
816 1060 : if ( mnSubTotalFlags )
817 53 : PushDouble( IterateParameters( ifSUM ) );
818 : else
819 : {
820 1007 : short nParamCount = GetByte();
821 1007 : double fRes = 0.0;
822 1007 : double fVal = 0.0;
823 1007 : ScAddress aAdr;
824 1007 : ScRange aRange;
825 1007 : size_t nRefInList = 0;
826 3106 : while (nParamCount-- > 0)
827 : {
828 1094 : switch (GetStackType())
829 : {
830 : case svString:
831 : {
832 0 : while (nParamCount-- > 0)
833 0 : Pop();
834 0 : SetError( errNoValue );
835 : }
836 0 : break;
837 : case svDouble :
838 2 : fVal = GetDouble();
839 2 : fRes += fVal;
840 2 : nFuncFmtType = css::util::NumberFormat::NUMBER;
841 2 : break;
842 : case svExternalSingleRef:
843 : {
844 0 : ScExternalRefCache::TokenRef pToken;
845 0 : ScExternalRefCache::CellFormat aFmt;
846 0 : PopExternalSingleRef(pToken, &aFmt);
847 :
848 0 : if (!pToken)
849 0 : break;
850 :
851 0 : StackVar eType = pToken->GetType();
852 0 : if (eType == formula::svDouble)
853 : {
854 0 : fVal = pToken->GetDouble();
855 0 : if (aFmt.mbIsSet)
856 : {
857 0 : nFuncFmtType = aFmt.mnType;
858 0 : nFuncFmtIndex = aFmt.mnIndex;
859 : }
860 :
861 0 : fRes += fVal;
862 0 : }
863 : }
864 0 : break;
865 : case svSingleRef :
866 : {
867 95 : PopSingleRef( aAdr );
868 :
869 95 : ScRefCellValue aCell;
870 95 : aCell.assign(*pDok, aAdr);
871 95 : if (!aCell.isEmpty())
872 : {
873 94 : if (aCell.hasNumeric())
874 : {
875 94 : fVal = GetCellValue(aAdr, aCell);
876 94 : CurFmtToFuncFmt();
877 94 : fRes += fVal;
878 : }
879 95 : }
880 : }
881 95 : break;
882 : case svDoubleRef :
883 : case svRefList :
884 : {
885 992 : PopDoubleRef( aRange, nParamCount, nRefInList);
886 :
887 992 : sc::ColumnSpanSet aSet(false);
888 992 : aSet.set(aRange, true);
889 :
890 1982 : FuncSum aAction;
891 992 : aSet.executeColumnAction(*pDok, aAction);
892 992 : sal_uInt16 nErr = aAction.getError();
893 992 : if (nErr)
894 : {
895 2 : SetError(nErr);
896 1062 : return;
897 : }
898 990 : fRes += aAction.getSum();
899 :
900 : // Get the number format of the last iterated cell.
901 990 : nFuncFmtIndex = aAction.getNumberFormat();
902 1980 : nFuncFmtType = pDok->GetFormatTable()->GetType(nFuncFmtIndex);
903 : }
904 990 : break;
905 : case svExternalDoubleRef:
906 : {
907 2 : ScMatrixRef pMat;
908 2 : PopExternalDoubleRef(pMat);
909 2 : if (nGlobalError)
910 0 : break;
911 :
912 2 : sal_uLong nCount = 0;
913 2 : double fMem = 0.0;
914 2 : bool bNull = true;
915 2 : IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull);
916 2 : fRes += fMem;
917 : }
918 2 : break;
919 : case svMatrix :
920 : {
921 3 : ScMatrixRef pMat = PopMatrix();
922 3 : sal_uLong nCount = 0;
923 3 : double fMem = 0.0;
924 3 : bool bNull = true;
925 3 : IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull);
926 3 : fRes += fMem;
927 : }
928 3 : break;
929 : case svError:
930 : {
931 0 : PopError();
932 : }
933 0 : break;
934 : default :
935 0 : while (nParamCount-- > 0)
936 0 : PopError();
937 0 : SetError(errIllegalParameter);
938 : }
939 : }
940 :
941 1005 : if (nFuncFmtType == css::util::NumberFormat::LOGICAL)
942 0 : nFuncFmtType = css::util::NumberFormat::NUMBER;
943 :
944 1005 : PushDouble(fRes);
945 : }
946 : }
947 :
948 71 : void ScInterpreter::ScProduct()
949 : {
950 71 : PushDouble( IterateParameters( ifPRODUCT ) );
951 71 : }
952 :
953 117 : void ScInterpreter::ScAverage( bool bTextAsZero )
954 : {
955 117 : PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
956 117 : }
957 :
958 77 : void ScInterpreter::ScCount()
959 : {
960 77 : if ( mnSubTotalFlags )
961 45 : PushDouble( IterateParameters( ifCOUNT ) );
962 : else
963 : {
964 32 : short nParamCount = GetByte();
965 32 : sal_uLong nCount = 0;
966 32 : ScAddress aAdr;
967 32 : ScRange aRange;
968 32 : size_t nRefInList = 0;
969 32 : if (nGlobalError)
970 0 : nGlobalError = 0;
971 :
972 121 : while (nParamCount-- > 0)
973 : {
974 57 : switch (GetRawStackType())
975 : {
976 : case svString:
977 : {
978 6 : OUString aStr = PopString().getString();
979 : // Only check if string can be converted to number, no
980 : // error propagation.
981 6 : sal_uInt16 nErr = nGlobalError;
982 6 : nGlobalError = 0;
983 6 : ConvertStringToValue( aStr );
984 6 : if (!nGlobalError)
985 0 : ++nCount;
986 6 : nGlobalError = nErr;
987 : }
988 6 : break;
989 : case svDouble :
990 20 : GetDouble();
991 20 : nCount++;
992 20 : nFuncFmtType = css::util::NumberFormat::NUMBER;
993 20 : break;
994 : case svExternalSingleRef:
995 : {
996 0 : ScExternalRefCache::TokenRef pToken;
997 0 : ScExternalRefCache::CellFormat aFmt;
998 0 : PopExternalSingleRef(pToken, &aFmt);
999 0 : if (nGlobalError)
1000 : {
1001 0 : nGlobalError = 0;
1002 0 : break;
1003 : }
1004 :
1005 0 : if (!pToken)
1006 0 : break;
1007 :
1008 0 : StackVar eType = pToken->GetType();
1009 0 : if (eType == formula::svDouble)
1010 : {
1011 0 : nCount++;
1012 0 : if (aFmt.mbIsSet)
1013 : {
1014 0 : nFuncFmtType = aFmt.mnType;
1015 0 : nFuncFmtIndex = aFmt.mnIndex;
1016 : }
1017 :
1018 0 : if (nGlobalError)
1019 : {
1020 0 : nGlobalError = 0;
1021 0 : nCount--;
1022 : }
1023 0 : }
1024 : }
1025 0 : break;
1026 : case svSingleRef :
1027 : {
1028 2 : PopSingleRef( aAdr );
1029 2 : if (nGlobalError)
1030 : {
1031 0 : nGlobalError = 0;
1032 0 : break;
1033 : }
1034 2 : ScRefCellValue aCell;
1035 2 : aCell.assign(*pDok, aAdr);
1036 2 : if (!aCell.isEmpty())
1037 : {
1038 2 : if (aCell.hasNumeric())
1039 : {
1040 2 : nCount++;
1041 2 : CurFmtToFuncFmt();
1042 2 : if (nGlobalError)
1043 : {
1044 0 : nGlobalError = 0;
1045 0 : nCount--;
1046 : }
1047 : }
1048 2 : }
1049 : }
1050 2 : break;
1051 : case svDoubleRef :
1052 : case svRefList :
1053 : {
1054 27 : PopDoubleRef( aRange, nParamCount, nRefInList);
1055 27 : if (nGlobalError)
1056 : {
1057 0 : nGlobalError = 0;
1058 0 : break;
1059 : }
1060 :
1061 27 : sc::ColumnSpanSet aSet(false);
1062 27 : aSet.set(aRange, true);
1063 :
1064 54 : FuncCount aAction;
1065 27 : aSet.executeColumnAction(*pDok, aAction);
1066 27 : nCount += aAction.getCount();
1067 :
1068 : // Get the number format of the last iterated cell.
1069 27 : nFuncFmtIndex = aAction.getNumberFormat();
1070 54 : nFuncFmtType = pDok->GetFormatTable()->GetType(nFuncFmtIndex);
1071 : }
1072 27 : break;
1073 : case svExternalDoubleRef:
1074 : {
1075 2 : ScMatrixRef pMat;
1076 2 : PopExternalDoubleRef(pMat);
1077 2 : if (nGlobalError)
1078 0 : break;
1079 :
1080 2 : double fMem = 0.0, fRes = 0.0;
1081 2 : bool bNull = true;
1082 2 : IterateMatrix(pMat, ifCOUNT, false, nCount, nFuncFmtType, fRes, fMem, bNull);
1083 : }
1084 2 : break;
1085 : case svMatrix :
1086 : {
1087 0 : ScMatrixRef pMat = PopMatrix();
1088 0 : double fMem = 0.0, fRes = 0.0;
1089 0 : bool bNull = true;
1090 0 : IterateMatrix(pMat, ifCOUNT, false, nCount, nFuncFmtType, fRes, fMem, bNull);
1091 : }
1092 0 : break;
1093 : case svError:
1094 : {
1095 0 : PopError();
1096 0 : nGlobalError = 0;
1097 : }
1098 0 : break;
1099 : default :
1100 0 : while (nParamCount-- > 0)
1101 0 : PopError();
1102 0 : SetError(errIllegalParameter);
1103 : }
1104 : }
1105 :
1106 32 : nFuncFmtType = css::util::NumberFormat::NUMBER;
1107 :
1108 32 : PushDouble(nCount);
1109 : }
1110 77 : }
1111 :
1112 63 : void ScInterpreter::ScCount2()
1113 : {
1114 63 : PushDouble( IterateParameters( ifCOUNT2 ) );
1115 219 : }
1116 :
1117 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|