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