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 <mtvfunctions.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 const double ResInitVal = (eFunc == ifPRODUCT) ? 1.0 : 0.0; 517 double fRes = ResInitVal; 518 double fVal = 0.0; 519 double fMem = 0.0; // first numeric value != 0.0 520 sal_uLong nCount = 0; 521 ScAddress aAdr; 522 ScRange aRange; 523 size_t nRefInList = 0; 524 size_t nRefArrayPos = std::numeric_limits<size_t>::max(); 525 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT || 526 ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) ) 527 nGlobalError = FormulaError::NONE; 528 while (nParamCount-- > 0) 529 { 530 switch (GetStackType()) 531 { 532 case svString: 533 { 534 if( eFunc == ifCOUNT ) 535 { 536 OUString aStr = PopString().getString(); 537 if ( bTextAsZero ) 538 nCount++; 539 else 540 { 541 // Only check if string can be converted to number, no 542 // error propagation. 543 FormulaError nErr = nGlobalError; 544 nGlobalError = FormulaError::NONE; 545 ConvertStringToValue( aStr ); 546 if (nGlobalError == FormulaError::NONE) 547 ++nCount; 548 nGlobalError = nErr; 549 } 550 } 551 else 552 { 553 Pop(); 554 switch ( eFunc ) 555 { 556 case ifAVERAGE: 557 case ifSUM: 558 case ifSUMSQ: 559 case ifPRODUCT: 560 { 561 if ( bTextAsZero ) 562 { 563 nCount++; 564 if ( eFunc == ifPRODUCT ) 565 fRes = 0.0; 566 } 567 else 568 { 569 while (nParamCount-- > 0) 570 Pop(); 571 SetError( FormulaError::NoValue ); 572 } 573 } 574 break; 575 default: 576 nCount++; 577 } 578 } 579 } 580 break; 581 case svDouble : 582 fVal = GetDouble(); 583 nCount++; 584 switch( eFunc ) 585 { 586 case ifAVERAGE: 587 case ifSUM: 588 if ( fMem ) 589 fRes += fVal; 590 else 591 fMem = fVal; 592 break; 593 case ifSUMSQ: fRes += fVal * fVal; break; 594 case ifPRODUCT: fRes *= fVal; break; 595 default: ; // nothing 596 } 597 nFuncFmtType = SvNumFormatType::NUMBER; 598 break; 599 case svExternalSingleRef: 600 { 601 ScExternalRefCache::TokenRef pToken; 602 ScExternalRefCache::CellFormat aFmt; 603 PopExternalSingleRef(pToken, &aFmt); 604 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT || 605 ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) ) 606 { 607 nGlobalError = FormulaError::NONE; 608 if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) 609 ++nCount; 610 break; 611 } 612 613 if (!pToken) 614 break; 615 616 StackVar eType = pToken->GetType(); 617 if (eFunc == ifCOUNT2) 618 { 619 if ( eType != svEmptyCell && 620 ( ( pToken->GetOpCode() != ocSubTotal && 621 pToken->GetOpCode() != ocAggregate ) || 622 ( mnSubTotalFlags & SubtotalFlags::IgnoreNestedStAg ) ) ) 623 nCount++; 624 if (nGlobalError != FormulaError::NONE) 625 nGlobalError = FormulaError::NONE; 626 } 627 else if (eType == svDouble) 628 { 629 nCount++; 630 fVal = pToken->GetDouble(); 631 if (aFmt.mbIsSet) 632 { 633 nFuncFmtType = aFmt.mnType; 634 nFuncFmtIndex = aFmt.mnIndex; 635 } 636 switch( eFunc ) 637 { 638 case ifAVERAGE: 639 case ifSUM: 640 if ( fMem ) 641 fRes += fVal; 642 else 643 fMem = fVal; 644 break; 645 case ifSUMSQ: fRes += fVal * fVal; break; 646 case ifPRODUCT: fRes *= fVal; break; 647 case ifCOUNT: 648 if ( nGlobalError != FormulaError::NONE ) 649 { 650 nGlobalError = FormulaError::NONE; 651 nCount--; 652 } 653 break; 654 default: ; // nothing 655 } 656 } 657 else if (bTextAsZero && eType == svString) 658 { 659 nCount++; 660 if ( eFunc == ifPRODUCT ) 661 fRes = 0.0; 662 } 663 } 664 break; 665 case svSingleRef : 666 { 667 PopSingleRef( aAdr ); 668 if (nGlobalError == FormulaError::NoRef) 669 { 670 PushError( FormulaError::NoRef); 671 return; 672 } 673 674 if ( ( ( mnSubTotalFlags & SubtotalFlags::IgnoreFiltered ) && 675 mrDoc.RowFiltered( aAdr.Row(), aAdr.Tab() ) ) || 676 ( ( mnSubTotalFlags & SubtotalFlags::IgnoreHidden ) && 677 mrDoc.RowHidden( aAdr.Row(), aAdr.Tab() ) ) ) 678 { 679 break; 680 } 681 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT || 682 ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) ) 683 { 684 nGlobalError = FormulaError::NONE; 685 if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) 686 ++nCount; 687 break; 688 } 689 ScRefCellValue aCell(mrDoc, aAdr); 690 if (!aCell.isEmpty()) 691 { 692 if( eFunc == ifCOUNT2 ) 693 { 694 CellType eCellType = aCell.meType; 695 if ( eCellType != CELLTYPE_NONE ) 696 nCount++; 697 if ( nGlobalError != FormulaError::NONE ) 698 nGlobalError = FormulaError::NONE; 699 } 700 else if (aCell.hasNumeric()) 701 { 702 nCount++; 703 fVal = GetCellValue(aAdr, aCell); 704 CurFmtToFuncFmt(); 705 switch( eFunc ) 706 { 707 case ifAVERAGE: 708 case ifSUM: 709 if ( fMem ) 710 fRes += fVal; 711 else 712 fMem = fVal; 713 break; 714 case ifSUMSQ: fRes += fVal * fVal; break; 715 case ifPRODUCT: fRes *= fVal; break; 716 case ifCOUNT: 717 if ( nGlobalError != FormulaError::NONE ) 718 { 719 nGlobalError = FormulaError::NONE; 720 nCount--; 721 } 722 break; 723 default: ; // nothing 724 } 725 } 726 else if (bTextAsZero && aCell.hasString()) 727 { 728 nCount++; 729 if ( eFunc == ifPRODUCT ) 730 fRes = 0.0; 731 } 732 } 733 } 734 break; 735 case svRefList : 736 { 737 const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]); 738 if (p && p->IsArrayResult()) 739 { 740 nRefArrayPos = nRefInList; 741 if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0) 742 { 743 fRes = rtl::math::approxAdd( fRes, fMem); 744 fMem = 0.0; 745 } 746 // The "one value to all references of an array" seems to 747 // be what Excel does if there are other types than just 748 // arrays of references. 749 if (!xResMat) 750 { 751 // Create and init all elements with current value. 752 assert(nMatRows > 0); 753 xResMat = GetNewMat( 1, nMatRows, true); 754 xResMat->FillDouble( fRes, 0,0, 0,nMatRows-1); 755 if (eFunc != ifSUM) 756 { 757 xResCount = GetNewMat( 1, nMatRows, true); 758 xResCount->FillDouble( nCount, 0,0, 0,nMatRows-1); 759 } 760 } 761 else 762 { 763 // Current value and values from vector are operands 764 // for each vector position. 765 if (nCount && xResCount) 766 { 767 for (SCSIZE i=0; i < nMatRows; ++i) 768 { 769 xResCount->PutDouble( xResCount->GetDouble(0,i) + nCount, 0,i); 770 } 771 } 772 if (fRes != ResInitVal) 773 { 774 for (SCSIZE i=0; i < nMatRows; ++i) 775 { 776 double fVecRes = xResMat->GetDouble(0,i); 777 if (eFunc == ifPRODUCT) 778 fVecRes *= fRes; 779 else 780 fVecRes += fRes; 781 xResMat->PutDouble( fVecRes, 0,i); 782 } 783 } 784 } 785 fRes = ResInitVal; 786 nCount = 0; 787 } 788 } 789 [[fallthrough]]; 790 case svDoubleRef : 791 { 792 PopDoubleRef( aRange, nParamCount, nRefInList); 793 if (nGlobalError == FormulaError::NoRef) 794 { 795 PushError( FormulaError::NoRef); 796 return; 797 } 798 799 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT || 800 ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) ) 801 { 802 nGlobalError = FormulaError::NONE; 803 if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) 804 ++nCount; 805 if ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) 806 break; 807 } 808 if( eFunc == ifCOUNT2 ) 809 { 810 ScCellIterator aIter( mrDoc, aRange, mnSubTotalFlags ); 811 for (bool bHas = aIter.first(); bHas; bHas = aIter.next()) 812 { 813 if ( !aIter.isEmpty() ) 814 { 815 ++nCount; 816 } 817 } 818 819 if ( nGlobalError != FormulaError::NONE ) 820 nGlobalError = FormulaError::NONE; 821 } 822 else if (((eFunc == ifSUM && !bCalcAsShown) || eFunc == ifCOUNT ) 823 && mnSubTotalFlags == SubtotalFlags::NONE) 824 { 825 // Use fast span set array method. 826 // ifSUM with bCalcAsShown has to use the slow bells and 827 // whistles ScValueIterator below. 828 sc::RangeColumnSpanSet aSet( aRange ); 829 830 if ( eFunc == ifSUM ) 831 { 832 FuncSum aAction(mrContext); 833 aSet.executeColumnAction( mrDoc, aAction, fMem ); 834 FormulaError nErr = aAction.getError(); 835 if ( nErr != FormulaError::NONE ) 836 { 837 PushError( nErr ); 838 return; 839 } 840 fRes += aAction.getSum(); 841 842 // Get the number format of the last iterated cell. 843 nFuncFmtIndex = aAction.getNumberFormat(); 844 } 845 else 846 { 847 FuncCount aAction(mrContext); 848 aSet.executeColumnAction(mrDoc, aAction); 849 nCount += aAction.getCount(); 850 851 // Get the number format of the last iterated cell. 852 nFuncFmtIndex = aAction.getNumberFormat(); 853 } 854 855 nFuncFmtType = mrContext.GetNumberFormatType( nFuncFmtIndex ); 856 } 857 else 858 { 859 ScValueIterator aValIter( mrDoc, aRange, mnSubTotalFlags, bTextAsZero ); 860 aValIter.SetInterpreterContext( &mrContext ); 861 FormulaError nErr = FormulaError::NONE; 862 if (aValIter.GetFirst(fVal, nErr)) 863 { 864 // placed the loop on the inside for performance reasons: 865 aValIter.GetCurNumFmtInfo( mrContext, nFuncFmtType, nFuncFmtIndex ); 866 switch( eFunc ) 867 { 868 case ifAVERAGE: 869 case ifSUM: 870 if ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) 871 { 872 do 873 { 874 if ( nErr == FormulaError::NONE ) 875 { 876 SetError(nErr); 877 if ( fMem ) 878 fRes += fVal; 879 else 880 fMem = fVal; 881 nCount++; 882 } 883 } 884 while (aValIter.GetNext(fVal, nErr)); 885 } 886 else 887 { 888 do 889 { 890 SetError(nErr); 891 if ( fMem ) 892 fRes += fVal; 893 else 894 fMem = fVal; 895 nCount++; 896 } 897 while (aValIter.GetNext(fVal, nErr)); 898 } 899 break; 900 case ifSUMSQ: 901 if ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) 902 { 903 do 904 { 905 if ( nErr == FormulaError::NONE ) 906 { 907 SetError(nErr); 908 fRes += fVal * fVal; 909 nCount++; 910 } 911 } 912 while (aValIter.GetNext(fVal, nErr)); 913 } 914 else 915 { 916 do 917 { 918 SetError(nErr); 919 fRes += fVal * fVal; 920 nCount++; 921 } 922 while (aValIter.GetNext(fVal, nErr)); 923 } 924 break; 925 case ifPRODUCT: 926 do 927 { 928 if ( !( nErr != FormulaError::NONE && ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) ) 929 { 930 SetError(nErr); 931 fRes *= fVal; 932 nCount++; 933 } 934 } 935 while (aValIter.GetNext(fVal, nErr)); 936 break; 937 case ifCOUNT: 938 do 939 { 940 if ( nErr == FormulaError::NONE ) 941 nCount++; 942 } 943 while (aValIter.GetNext(fVal, nErr)); 944 break; 945 default: ; // nothing 946 } 947 SetError( nErr ); 948 } 949 } 950 if (nRefArrayPos != std::numeric_limits<size_t>::max()) 951 { 952 // Update vector element with current value. 953 if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0) 954 { 955 fRes = rtl::math::approxAdd( fRes, fMem); 956 fMem = 0.0; 957 } 958 if (xResCount) 959 xResCount->PutDouble( xResCount->GetDouble(0,nRefArrayPos) + nCount, 0,nRefArrayPos); 960 double fVecRes = xResMat->GetDouble(0,nRefArrayPos); 961 if (eFunc == ifPRODUCT) 962 fVecRes *= fRes; 963 else 964 fVecRes += fRes; 965 xResMat->PutDouble( fVecRes, 0,nRefArrayPos); 966 // Reset. 967 fRes = ResInitVal; 968 nCount = 0; 969 nRefArrayPos = std::numeric_limits<size_t>::max(); 970 } 971 } 972 break; 973 case svExternalDoubleRef: 974 { 975 ScMatrixRef pMat; 976 PopExternalDoubleRef(pMat); 977 if ( nGlobalError != FormulaError::NONE && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) 978 break; 979 980 IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes, fMem ); 981 } 982 break; 983 case svMatrix : 984 { 985 ScMatrixRef pMat = PopMatrix(); 986 987 IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes, fMem ); 988 } 989 break; 990 case svError: 991 { 992 PopError(); 993 if ( eFunc == ifCOUNT || ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) 994 { 995 nGlobalError = FormulaError::NONE; 996 } 997 else if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) 998 { 999 nCount++; 1000 nGlobalError = FormulaError::NONE; 1001 } 1002 } 1003 break; 1004 default : 1005 while (nParamCount-- > 0) 1006 PopError(); 1007 SetError(FormulaError::IllegalParameter); 1008 } 1009 } 1010 1011 // A boolean return type makes no sense on sums et al. 1012 // Counts are always numbers. 1013 if( nFuncFmtType == SvNumFormatType::LOGICAL || eFunc == ifCOUNT || eFunc == ifCOUNT2 ) 1014 nFuncFmtType = SvNumFormatType::NUMBER; 1015 1016 if (xResMat) 1017 { 1018 // Include value of last non-references-array type and calculate final result. 1019 for (SCSIZE i=0; i < nMatRows; ++i) 1020 { 1021 sal_uLong nVecCount = (xResCount ? nCount + xResCount->GetDouble(0,i) : nCount); 1022 double fVecRes = xResMat->GetDouble(0,i); 1023 if (eFunc == ifPRODUCT) 1024 fVecRes *= fRes; 1025 else 1026 fVecRes += fRes; 1027 fVecRes = lcl_IterResult( eFunc, fVecRes, fMem, nVecCount); 1028 xResMat->PutDouble( fVecRes, 0,i); 1029 } 1030 PushMatrix( xResMat); 1031 } 1032 else 1033 { 1034 PushDouble( lcl_IterResult( eFunc, fRes, fMem, nCount)); 1035 } 1036 } 1037 1038 void ScInterpreter::ScSumSQ() 1039 { 1040 IterateParameters( ifSUMSQ ); 1041 } 1042 1043 void ScInterpreter::ScSum() 1044 { 1045 IterateParameters( ifSUM ); 1046 } 1047 1048 void ScInterpreter::ScProduct() 1049 { 1050 IterateParameters( ifPRODUCT ); 1051 } 1052 1053 void ScInterpreter::ScAverage( bool bTextAsZero ) 1054 { 1055 IterateParameters( ifAVERAGE, bTextAsZero ); 1056 } 1057 1058 void ScInterpreter::ScCount() 1059 { 1060 IterateParameters( ifCOUNT ); 1061 } 1062 1063 void ScInterpreter::ScCount2() 1064 { 1065 IterateParameters( ifCOUNT2 ); 1066 } 1067 1068 void ScInterpreter::ScRawSubtract() 1069 { 1070 short nParamCount = GetByte(); 1071 if (!MustHaveParamCountMin( nParamCount, 2)) 1072 return; 1073 1074 // Fish the 1st parameter from the stack and push it on top. 1075 const FormulaToken* p = pStack[ sp - nParamCount ]; 1076 PushWithoutError( *p ); 1077 // Obtain the minuend. 1078 double fRes = GetDouble(); 1079 1080 while (nGlobalError == FormulaError::NONE && nParamCount > 1) 1081 { 1082 // Simple single values without matrix support. 1083 fRes -= GetDouble(); 1084 --nParamCount; 1085 } 1086 while (nParamCount-- > 0) 1087 PopError(); 1088 1089 PushDouble( fRes); 1090 } 1091 1092 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1093
