1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sc.hxx" 26 27 // INCLUDE --------------------------------------------------------------- 28 29 #ifndef INCLUDED_RTL_MATH_HXX 30 #include <rtl/math.hxx> 31 #endif 32 #include <rtl/logfile.hxx> 33 #include <string.h> 34 #include <math.h> 35 #include <stdio.h> 36 37 #if OSL_DEBUG_LEVEL > 1 38 #include <stdio.h> 39 #endif 40 #include <unotools/bootstrap.hxx> 41 #include <svl/zforlist.hxx> 42 43 #include "interpre.hxx" 44 #include "global.hxx" 45 #include "compiler.hxx" 46 #include "cell.hxx" 47 #include "document.hxx" 48 #include "dociter.hxx" 49 #include "scmatrix.hxx" 50 #include "globstr.hrc" 51 #include "cellkeytranslator.hxx" 52 #include "osversiondef.hxx" 53 54 #include <string.h> 55 #include <math.h> 56 #include <vector> 57 58 using ::std::vector; 59 using namespace formula; 60 61 const double fInvEpsilon = 1.0E-7; 62 63 // ----------------------------------------------------------------------- 64 struct MatrixAdd : public ::std::binary_function<double,double,double> 65 { 66 inline double operator() (const double& lhs, const double& rhs) const 67 { 68 return ::rtl::math::approxAdd( lhs,rhs); 69 } 70 }; 71 struct MatrixSub : public ::std::binary_function<double,double,double> 72 { 73 inline double operator() (const double& lhs, const double& rhs) const 74 { 75 return ::rtl::math::approxSub( lhs,rhs); 76 } 77 }; 78 struct MatrixMul : public ::std::binary_function<double,double,double> 79 { 80 inline double operator() (const double& lhs, const double& rhs) const 81 { 82 return lhs * rhs; 83 } 84 }; 85 struct MatrixDiv : public ::std::binary_function<double,double,double> 86 { 87 inline double operator() (const double& lhs, const double& rhs) const 88 { 89 return ScInterpreter::div( lhs,rhs); 90 } 91 }; 92 struct MatrixPow : public ::std::binary_function<double,double,double> 93 { 94 inline double operator() (const double& lhs, const double& rhs) const 95 { 96 return ::pow( lhs,rhs); 97 } 98 }; 99 100 double ScInterpreter::ScGetGCD(double fx, double fy) 101 { 102 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::div" ); 103 // By ODFF definition GCD(0,a) => a. This is also vital for the code in 104 // ScGCD() to work correctly with a preset fy=0.0 105 if (fy == 0.0) 106 return fx; 107 else if (fx == 0.0) 108 return fy; 109 else 110 { 111 double fz = fmod(fx, fy); 112 while (fz > 0.0) 113 { 114 fx = fy; 115 fy = fz; 116 fz = fmod(fx, fy); 117 } 118 return fy; 119 } 120 } 121 122 void ScInterpreter::ScGCD() 123 { 124 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGCD" ); 125 short nParamCount = GetByte(); 126 if ( MustHaveParamCountMin( nParamCount, 1 ) ) 127 { 128 double fx, fy = 0.0; 129 ScRange aRange; 130 size_t nRefInList = 0; 131 while (!nGlobalError && nParamCount-- > 0) 132 { 133 switch (GetStackType()) 134 { 135 case svDouble : 136 case svString: 137 case svSingleRef: 138 { 139 fx = ::rtl::math::approxFloor( GetDouble()); 140 if (fx < 0.0) 141 { 142 PushIllegalArgument(); 143 return; 144 } 145 fy = ScGetGCD(fx, fy); 146 } 147 break; 148 case svDoubleRef : 149 case svRefList : 150 { 151 sal_uInt16 nErr = 0; 152 PopDoubleRef( aRange, nParamCount, nRefInList); 153 double nCellVal; 154 ScValueIterator aValIter(pDok, aRange, glSubTotal); 155 if (aValIter.GetFirst(nCellVal, nErr)) 156 { 157 do 158 { 159 fx = ::rtl::math::approxFloor( nCellVal); 160 if (fx < 0.0) 161 { 162 PushIllegalArgument(); 163 return; 164 } 165 fy = ScGetGCD(fx, fy); 166 } while (nErr == 0 && aValIter.GetNext(nCellVal, nErr)); 167 } 168 SetError(nErr); 169 } 170 break; 171 case svMatrix : 172 { 173 ScMatrixRef pMat = PopMatrix(); 174 if (pMat) 175 { 176 SCSIZE nC, nR; 177 pMat->GetDimensions(nC, nR); 178 if (nC == 0 || nR == 0) 179 SetError(errIllegalArgument); 180 else 181 { 182 SCSIZE nCount = nC * nR; 183 for ( SCSIZE j = 0; j < nCount; j++ ) 184 { 185 if (!pMat->IsValue(j)) 186 { 187 PushIllegalArgument(); 188 return; 189 } 190 fx = ::rtl::math::approxFloor( pMat->GetDouble(j)); 191 if (fx < 0.0) 192 { 193 PushIllegalArgument(); 194 return; 195 } 196 fy = ScGetGCD(fx, fy); 197 } 198 } 199 } 200 } 201 break; 202 default : SetError(errIllegalParameter); break; 203 } 204 } 205 PushDouble(fy); 206 } 207 } 208 209 void ScInterpreter:: ScLCM() 210 { 211 short nParamCount = GetByte(); 212 if ( MustHaveParamCountMin( nParamCount, 1 ) ) 213 { 214 double fx, fy = 1.0; 215 ScRange aRange; 216 size_t nRefInList = 0; 217 while (!nGlobalError && nParamCount-- > 0) 218 { 219 switch (GetStackType()) 220 { 221 case svDouble : 222 case svString: 223 case svSingleRef: 224 { 225 fx = ::rtl::math::approxFloor( GetDouble()); 226 if (fx < 0.0) 227 { 228 PushIllegalArgument(); 229 return; 230 } 231 if (fx == 0.0 || fy == 0.0) 232 fy = 0.0; 233 else 234 fy = fx * fy / ScGetGCD(fx, fy); 235 } 236 break; 237 case svDoubleRef : 238 case svRefList : 239 { 240 sal_uInt16 nErr = 0; 241 PopDoubleRef( aRange, nParamCount, nRefInList); 242 double nCellVal; 243 ScValueIterator aValIter(pDok, aRange, glSubTotal); 244 if (aValIter.GetFirst(nCellVal, nErr)) 245 { 246 do 247 { 248 fx = ::rtl::math::approxFloor( nCellVal); 249 if (fx < 0.0) 250 { 251 PushIllegalArgument(); 252 return; 253 } 254 if (fx == 0.0 || fy == 0.0) 255 fy = 0.0; 256 else 257 fy = fx * fy / ScGetGCD(fx, fy); 258 } while (nErr == 0 && aValIter.GetNext(nCellVal, nErr)); 259 } 260 SetError(nErr); 261 } 262 break; 263 case svMatrix : 264 { 265 ScMatrixRef pMat = PopMatrix(); 266 if (pMat) 267 { 268 SCSIZE nC, nR; 269 pMat->GetDimensions(nC, nR); 270 if (nC == 0 || nR == 0) 271 SetError(errIllegalArgument); 272 else 273 { 274 SCSIZE nCount = nC * nR; 275 for ( SCSIZE j = 0; j < nCount; j++ ) 276 { 277 if (!pMat->IsValue(j)) 278 { 279 PushIllegalArgument(); 280 return; 281 } 282 fx = ::rtl::math::approxFloor( pMat->GetDouble(j)); 283 if (fx < 0.0) 284 { 285 PushIllegalArgument(); 286 return; 287 } 288 if (fx == 0.0 || fy == 0.0) 289 fy = 0.0; 290 else 291 fy = fx * fy / ScGetGCD(fx, fy); 292 } 293 } 294 } 295 } 296 break; 297 default : SetError(errIllegalParameter); break; 298 } 299 } 300 PushDouble(fy); 301 } 302 } 303 304 ScMatrixRef ScInterpreter::GetNewMat(SCSIZE nC, SCSIZE nR) 305 { 306 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetNewMat" ); 307 ScMatrix* pMat = new ScMatrix( nC, nR); 308 pMat->SetErrorInterpreter( this); 309 // A temporary matrix is mutable and ScMatrix::CloneIfConst() returns the 310 // very matrix. 311 pMat->SetImmutable( false); 312 SCSIZE nCols, nRows; 313 pMat->GetDimensions( nCols, nRows); 314 if ( nCols != nC || nRows != nR ) 315 { // arbitray limit of elements exceeded 316 SetError( errStackOverflow); 317 pMat->Delete(); 318 pMat = NULL; 319 } 320 return pMat; 321 } 322 323 ScMatrixRef ScInterpreter::CreateMatrixFromDoubleRef( const FormulaToken* pToken, 324 SCCOL nCol1, SCROW nRow1, SCTAB nTab1, 325 SCCOL nCol2, SCROW nRow2, SCTAB nTab2 ) 326 { 327 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CreateMatrixFromDoubleRef" ); 328 ScMatrixRef pMat = NULL; 329 if (nTab1 == nTab2 && !nGlobalError) 330 { 331 ScTokenMatrixMap::const_iterator aIter; 332 if ( static_cast<SCSIZE>(nRow2 - nRow1 + 1) * 333 static_cast<SCSIZE>(nCol2 - nCol1 + 1) > 334 ScMatrix::GetElementsMax() ) 335 SetError(errStackOverflow); 336 else if (pTokenMatrixMap && ((aIter = pTokenMatrixMap->find( pToken)) 337 != pTokenMatrixMap->end())) 338 pMat = static_cast<ScToken*>((*aIter).second.get())->GetMatrix(); 339 else 340 { 341 SCSIZE nMatCols = static_cast<SCSIZE>(nCol2 - nCol1 + 1); 342 SCSIZE nMatRows = static_cast<SCSIZE>(nRow2 - nRow1 + 1); 343 pMat = GetNewMat( nMatCols, nMatRows); 344 if (pMat && !nGlobalError) 345 { 346 // Set position where the next entry is expected. 347 SCROW nNextRow = nRow1; 348 SCCOL nNextCol = nCol1; 349 // Set last position as if there was a previous entry. 350 SCROW nThisRow = nRow2; 351 SCCOL nThisCol = nCol1 - 1; 352 ScCellIterator aCellIter( pDok, nCol1, nRow1, nTab1, nCol2, 353 nRow2, nTab2); 354 for (ScBaseCell* pCell = aCellIter.GetFirst(); pCell; pCell = 355 aCellIter.GetNext()) 356 { 357 nThisCol = aCellIter.GetCol(); 358 nThisRow = aCellIter.GetRow(); 359 if (nThisCol != nNextCol || nThisRow != nNextRow) 360 { 361 // Fill empty between iterator's positions. 362 for ( ; nNextCol <= nThisCol; ++nNextCol) 363 { 364 SCSIZE nC = nNextCol - nCol1; 365 SCSIZE nMatStopRow = ((nNextCol < nThisCol) ? 366 nMatRows : nThisRow - nRow1); 367 for (SCSIZE nR = nNextRow - nRow1; nR < 368 nMatStopRow; ++nR) 369 { 370 pMat->PutEmpty( nC, nR); 371 } 372 nNextRow = nRow1; 373 } 374 } 375 if (nThisRow == nRow2) 376 { 377 nNextCol = nThisCol + 1; 378 nNextRow = nRow1; 379 } 380 else 381 { 382 nNextCol = nThisCol; 383 nNextRow = nThisRow + 1; 384 } 385 if (HasCellEmptyData(pCell)) 386 { 387 pMat->PutEmpty( static_cast<SCSIZE>(nThisCol-nCol1), 388 static_cast<SCSIZE>(nThisRow-nRow1)); 389 } 390 else if (HasCellValueData(pCell)) 391 { 392 ScAddress aAdr( nThisCol, nThisRow, nTab1); 393 double fVal = GetCellValue( aAdr, pCell); 394 if ( nGlobalError ) 395 { 396 fVal = CreateDoubleError( nGlobalError); 397 nGlobalError = 0; 398 } 399 pMat->PutDouble( fVal, 400 static_cast<SCSIZE>(nThisCol-nCol1), 401 static_cast<SCSIZE>(nThisRow-nRow1)); 402 } 403 else 404 { 405 String aStr; 406 GetCellString( aStr, pCell); 407 if ( nGlobalError ) 408 { 409 double fVal = CreateDoubleError( nGlobalError); 410 nGlobalError = 0; 411 pMat->PutDouble( fVal, 412 static_cast<SCSIZE>(nThisCol-nCol1), 413 static_cast<SCSIZE>(nThisRow-nRow1)); 414 } 415 else 416 pMat->PutString( aStr, 417 static_cast<SCSIZE>(nThisCol-nCol1), 418 static_cast<SCSIZE>(nThisRow-nRow1)); 419 } 420 } 421 // Fill empty if iterator's last position wasn't the end. 422 if (nThisCol != nCol2 || nThisRow != nRow2) 423 { 424 for ( ; nNextCol <= nCol2; ++nNextCol) 425 { 426 SCSIZE nC = nNextCol - nCol1; 427 for (SCSIZE nR = nNextRow - nRow1; nR < nMatRows; ++nR) 428 { 429 pMat->PutEmpty( nC, nR); 430 } 431 nNextRow = nRow1; 432 } 433 } 434 if (pTokenMatrixMap) 435 pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( 436 pToken, new ScMatrixToken( pMat))); 437 } 438 } 439 } 440 else // not a 2D matrix 441 SetError(errIllegalParameter); 442 return pMat; 443 } 444 445 446 ScMatrixRef ScInterpreter::GetMatrix() 447 { 448 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetMatrix" ); 449 ScMatrixRef pMat = NULL; 450 switch (GetRawStackType()) 451 { 452 case svSingleRef : 453 { 454 ScAddress aAdr; 455 PopSingleRef( aAdr ); 456 pMat = GetNewMat(1, 1); 457 if (pMat) 458 { 459 ScBaseCell* pCell = GetCell( aAdr ); 460 if (HasCellEmptyData(pCell)) 461 pMat->PutEmpty( 0 ); 462 else if (HasCellValueData(pCell)) 463 pMat->PutDouble(GetCellValue(aAdr, pCell), 0); 464 else 465 { 466 String aStr; 467 GetCellString(aStr, pCell); 468 pMat->PutString(aStr, 0); 469 } 470 } 471 } 472 break; 473 case svDoubleRef: 474 { 475 SCCOL nCol1, nCol2; 476 SCROW nRow1, nRow2; 477 SCTAB nTab1, nTab2; 478 const ScToken* p = sp ? static_cast<const ScToken*>(pStack[sp-1]) : NULL; 479 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); 480 pMat = CreateMatrixFromDoubleRef( p, nCol1, nRow1, nTab1, 481 nCol2, nRow2, nTab2); 482 } 483 break; 484 case svMatrix: 485 pMat = PopMatrix(); 486 break; 487 case svError : 488 case svMissing : 489 case svDouble : 490 { 491 double fVal = GetDouble(); 492 pMat = GetNewMat( 1, 1); 493 if ( pMat ) 494 { 495 if ( nGlobalError ) 496 { 497 fVal = CreateDoubleError( nGlobalError); 498 nGlobalError = 0; 499 } 500 pMat->PutDouble( fVal, 0); 501 } 502 } 503 break; 504 case svString : 505 { 506 String aStr = GetString(); 507 pMat = GetNewMat( 1, 1); 508 if ( pMat ) 509 { 510 if ( nGlobalError ) 511 { 512 double fVal = CreateDoubleError( nGlobalError); 513 pMat->PutDouble( fVal, 0); 514 nGlobalError = 0; 515 } 516 else 517 pMat->PutString( aStr, 0); 518 } 519 } 520 break; 521 default: 522 PopError(); 523 SetError( errIllegalArgument); 524 break; 525 } 526 return pMat; 527 } 528 529 void ScInterpreter::ScMatValue() 530 { 531 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatValue" ); 532 if ( MustHaveParamCount( GetByte(), 3 ) ) 533 { 534 // 0 to count-1 535 SCSIZE nR = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble())); 536 SCSIZE nC = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble())); 537 switch (GetStackType()) 538 { 539 case svSingleRef : 540 { 541 ScAddress aAdr; 542 PopSingleRef( aAdr ); 543 ScBaseCell* pCell = GetCell( aAdr ); 544 if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA) 545 { 546 sal_uInt16 nErrCode = ((ScFormulaCell*)pCell)->GetErrCode(); 547 if (nErrCode != 0) 548 PushError( nErrCode); 549 else 550 { 551 const ScMatrix* pMat = ((ScFormulaCell*)pCell)->GetMatrix(); 552 CalculateMatrixValue(pMat,nC,nR); 553 } 554 } 555 else 556 PushIllegalParameter(); 557 } 558 break; 559 case svDoubleRef : 560 { 561 SCCOL nCol1; 562 SCROW nRow1; 563 SCTAB nTab1; 564 SCCOL nCol2; 565 SCROW nRow2; 566 SCTAB nTab2; 567 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); 568 if (nCol2 - nCol1 >= static_cast<SCCOL>(nR) && 569 nRow2 - nRow1 >= static_cast<SCROW>(nC) && 570 nTab1 == nTab2) 571 { 572 ScAddress aAdr( sal::static_int_cast<SCCOL>( nCol1 + nR ), 573 sal::static_int_cast<SCROW>( nRow1 + nC ), nTab1 ); 574 ScBaseCell* pCell = GetCell( aAdr ); 575 if (HasCellValueData(pCell)) 576 PushDouble(GetCellValue( aAdr, pCell )); 577 else 578 { 579 String aStr; 580 GetCellString(aStr, pCell); 581 PushString(aStr); 582 } 583 } 584 else 585 PushNoValue(); 586 } 587 break; 588 case svMatrix: 589 { 590 ScMatrixRef pMat = PopMatrix(); 591 CalculateMatrixValue(pMat,nC,nR); 592 } 593 break; 594 default: 595 PopError(); 596 PushIllegalParameter(); 597 break; 598 } 599 } 600 } 601 void ScInterpreter::CalculateMatrixValue(const ScMatrix* pMat,SCSIZE nC,SCSIZE nR) 602 { 603 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateMatrixValue" ); 604 if (pMat) 605 { 606 SCSIZE nCl, nRw; 607 pMat->GetDimensions(nCl, nRw); 608 if (nC < nCl && nR < nRw) 609 { 610 ScMatValType nMatValType; 611 const ScMatrixValue* pMatVal = pMat->Get( nC, nR,nMatValType); 612 if (ScMatrix::IsNonValueType( nMatValType)) 613 PushString( pMatVal->GetString() ); 614 else 615 PushDouble(pMatVal->fVal); 616 // also handles DoubleError 617 } 618 else 619 PushNoValue(); 620 } 621 else 622 PushNoValue(); 623 } 624 625 void ScInterpreter::ScEMat() 626 { 627 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEMat" ); 628 if ( MustHaveParamCount( GetByte(), 1 ) ) 629 { 630 SCSIZE nDim = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble())); 631 if ( nDim * nDim > ScMatrix::GetElementsMax() || nDim == 0) 632 PushIllegalArgument(); 633 else 634 { 635 ScMatrixRef pRMat = GetNewMat(nDim, nDim); 636 if (pRMat) 637 { 638 MEMat(pRMat, nDim); 639 PushMatrix(pRMat); 640 } 641 else 642 PushIllegalArgument(); 643 } 644 } 645 } 646 647 void ScInterpreter::MEMat(ScMatrix* mM, SCSIZE n) 648 { 649 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MEMat" ); 650 mM->FillDouble(0.0, 0, 0, n-1, n-1); 651 for (SCSIZE i = 0; i < n; i++) 652 mM->PutDouble(1.0, i, i); 653 } 654 655 /* Matrix LUP decomposition according to the pseudocode of "Introduction to 656 * Algorithms" by Cormen, Leiserson, Rivest, Stein. 657 * 658 * Added scaling for numeric stability. 659 * 660 * Given an n x n nonsingular matrix A, find a permutation matrix P, a unit 661 * lower-triangular matrix L, and an upper-triangular matrix U such that PA=LU. 662 * Compute L and U "in place" in the matrix A, the original content is 663 * destroyed. Note that the diagonal elements of the U triangular matrix 664 * replace the diagonal elements of the L-unit matrix (that are each ==1). The 665 * permutation matrix P is an array, where P[i]=j means that the i-th row of P 666 * contains a 1 in column j. Additionally keep track of the number of 667 * permutations (row exchanges). 668 * 669 * Returns 0 if a singular matrix is encountered, else +1 if an even number of 670 * permutations occurred, or -1 if odd, which is the sign of the determinant. 671 * This may be used to calculate the determinant by multiplying the sign with 672 * the product of the diagonal elements of the LU matrix. 673 */ 674 static int lcl_LUP_decompose( ScMatrix* mA, const SCSIZE n, 675 ::std::vector< SCSIZE> & P ) 676 { 677 int nSign = 1; 678 // Find scale of each row. 679 ::std::vector< double> aScale(n); 680 for (SCSIZE i=0; i < n; ++i) 681 { 682 double fMax = 0.0; 683 for (SCSIZE j=0; j < n; ++j) 684 { 685 double fTmp = fabs( mA->GetDouble( j, i)); 686 if (fMax < fTmp) 687 fMax = fTmp; 688 } 689 if (fMax == 0.0) 690 return 0; // singular matrix 691 aScale[i] = 1.0 / fMax; 692 } 693 // Represent identity permutation, P[i]=i 694 for (SCSIZE i=0; i < n; ++i) 695 P[i] = i; 696 // "Recursion" on the diagonale. 697 SCSIZE l = n - 1; 698 for (SCSIZE k=0; k < l; ++k) 699 { 700 // Implicit pivoting. With the scale found for a row, compare values of 701 // a column and pick largest. 702 double fMax = 0.0; 703 double fScale = aScale[k]; 704 SCSIZE kp = k; 705 for (SCSIZE i = k; i < n; ++i) 706 { 707 double fTmp = fScale * fabs( mA->GetDouble( k, i)); 708 if (fMax < fTmp) 709 { 710 fMax = fTmp; 711 kp = i; 712 } 713 } 714 if (fMax == 0.0) 715 return 0; // singular matrix 716 // Swap rows. The pivot element will be at mA[k,kp] (row,col notation) 717 if (k != kp) 718 { 719 // permutations 720 SCSIZE nTmp = P[k]; 721 P[k] = P[kp]; 722 P[kp] = nTmp; 723 nSign = -nSign; 724 // scales 725 double fTmp = aScale[k]; 726 aScale[k] = aScale[kp]; 727 aScale[kp] = fTmp; 728 // elements 729 for (SCSIZE i=0; i < n; ++i) 730 { 731 double fMatTmp = mA->GetDouble( i, k); 732 mA->PutDouble( mA->GetDouble( i, kp), i, k); 733 mA->PutDouble( fMatTmp, i, kp); 734 } 735 } 736 // Compute Schur complement. 737 for (SCSIZE i = k+1; i < n; ++i) 738 { 739 double fTmp = mA->GetDouble( k, i) / mA->GetDouble( k, k); 740 mA->PutDouble( fTmp, k, i); 741 for (SCSIZE j = k+1; j < n; ++j) 742 mA->PutDouble( mA->GetDouble( j, i) - fTmp * mA->GetDouble( j, 743 k), j, i); 744 } 745 } 746 #if OSL_DEBUG_LEVEL > 1 747 fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): LU"); 748 for (SCSIZE i=0; i < n; ++i) 749 { 750 for (SCSIZE j=0; j < n; ++j) 751 fprintf( stderr, "%8.2g ", mA->GetDouble( j, i)); 752 fprintf( stderr, "\n%s\n", ""); 753 } 754 fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): P"); 755 for (SCSIZE j=0; j < n; ++j) 756 fprintf( stderr, "%5u ", (unsigned)P[j]); 757 fprintf( stderr, "\n%s\n", ""); 758 #endif 759 760 bool bSingular=false; 761 for (SCSIZE i=0; i < n && !bSingular; i++) 762 bSingular = (mA->GetDouble(i,i) == 0.0); 763 if (bSingular) 764 nSign = 0; 765 766 return nSign; 767 } 768 769 770 /* Solve a LUP decomposed equation Ax=b. LU is a combined matrix of L and U 771 * triangulars and P the permutation vector as obtained from 772 * lcl_LUP_decompose(). B is the right-hand side input vector, X is used to 773 * return the solution vector. 774 */ 775 static void lcl_LUP_solve( const ScMatrix* mLU, const SCSIZE n, 776 const ::std::vector< SCSIZE> & P, const ::std::vector< double> & B, 777 ::std::vector< double> & X ) 778 { 779 SCSIZE nFirst = SCSIZE_MAX; 780 // Ax=b => PAx=Pb, with decomposition LUx=Pb. 781 // Define y=Ux and solve for y in Ly=Pb using forward substitution. 782 for (SCSIZE i=0; i < n; ++i) 783 { 784 double fSum = B[P[i]]; 785 // Matrix inversion comes with a lot of zeros in the B vectors, we 786 // don't have to do all the computing with results multiplied by zero. 787 // Until then, simply lookout for the position of the first nonzero 788 // value. 789 if (nFirst != SCSIZE_MAX) 790 { 791 for (SCSIZE j = nFirst; j < i; ++j) 792 fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === y[j] 793 } 794 else if (fSum) 795 nFirst = i; 796 X[i] = fSum; // X[i] === y[i] 797 } 798 // Solve for x in Ux=y using back substitution. 799 for (SCSIZE i = n; i--; ) 800 { 801 double fSum = X[i]; // X[i] === y[i] 802 for (SCSIZE j = i+1; j < n; ++j) 803 fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === x[j] 804 X[i] = fSum / mLU->GetDouble( i, i); // X[i] === x[i] 805 } 806 #if OSL_DEBUG_LEVEL >1 807 fprintf( stderr, "\n%s\n", "lcl_LUP_solve():"); 808 for (SCSIZE i=0; i < n; ++i) 809 fprintf( stderr, "%8.2g ", X[i]); 810 fprintf( stderr, "%s\n", ""); 811 #endif 812 } 813 814 815 void ScInterpreter::ScMatDet() 816 { 817 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatDet" ); 818 if ( MustHaveParamCount( GetByte(), 1 ) ) 819 { 820 ScMatrixRef pMat = GetMatrix(); 821 if (!pMat) 822 { 823 PushIllegalParameter(); 824 return; 825 } 826 if ( !pMat->IsNumeric() ) 827 { 828 PushNoValue(); 829 return; 830 } 831 SCSIZE nC, nR; 832 pMat->GetDimensions(nC, nR); 833 if ( nC != nR || nC == 0 || (sal_uLong) nC * nC > ScMatrix::GetElementsMax() ) 834 PushIllegalArgument(); 835 else 836 { 837 // LUP decomposition is done inplace, use copy. 838 ScMatrixRef xLU = pMat->Clone(); 839 if (!xLU) 840 PushError( errCodeOverflow); 841 else 842 { 843 ::std::vector< SCSIZE> P(nR); 844 int nDetSign = lcl_LUP_decompose( xLU, nR, P); 845 if (!nDetSign) 846 PushInt(0); // singular matrix 847 else 848 { 849 // In an LU matrix the determinant is simply the product of 850 // all diagonal elements. 851 double fDet = nDetSign; 852 ScMatrix* pLU = xLU; 853 for (SCSIZE i=0; i < nR; ++i) 854 fDet *= pLU->GetDouble( i, i); 855 PushDouble( fDet); 856 } 857 } 858 } 859 } 860 } 861 862 void ScInterpreter::ScMatInv() 863 { 864 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatInv" ); 865 if ( MustHaveParamCount( GetByte(), 1 ) ) 866 { 867 ScMatrixRef pMat = GetMatrix(); 868 if (!pMat) 869 { 870 PushIllegalParameter(); 871 return; 872 } 873 if ( !pMat->IsNumeric() ) 874 { 875 PushNoValue(); 876 return; 877 } 878 SCSIZE nC, nR; 879 pMat->GetDimensions(nC, nR); 880 if ( nC != nR || nC == 0 || (sal_uLong) nC * nC > ScMatrix::GetElementsMax() ) 881 PushIllegalArgument(); 882 else 883 { 884 // LUP decomposition is done inplace, use copy. 885 ScMatrixRef xLU = pMat->Clone(); 886 // The result matrix. 887 ScMatrixRef xY = GetNewMat( nR, nR); 888 if (!xLU || !xY) 889 PushError( errCodeOverflow); 890 else 891 { 892 ::std::vector< SCSIZE> P(nR); 893 int nDetSign = lcl_LUP_decompose( xLU, nR, P); 894 if (!nDetSign) 895 PushIllegalArgument(); 896 else 897 { 898 // Solve equation for each column. 899 ScMatrix* pY = xY; 900 ::std::vector< double> B(nR); 901 ::std::vector< double> X(nR); 902 for (SCSIZE j=0; j < nR; ++j) 903 { 904 for (SCSIZE i=0; i < nR; ++i) 905 B[i] = 0.0; 906 B[j] = 1.0; 907 lcl_LUP_solve( xLU, nR, P, B, X); 908 for (SCSIZE i=0; i < nR; ++i) 909 pY->PutDouble( X[i], j, i); 910 } 911 #if 0 912 /* Possible checks for ill-condition: 913 * 1. Scale matrix, invert scaled matrix. If there are 914 * elements of the inverted matrix that are several 915 * orders of magnitude greater than 1 => 916 * ill-conditioned. 917 * Just how much is "several orders"? 918 * 2. Invert the inverted matrix and assess whether the 919 * result is sufficiently close to the original matrix. 920 * If not => ill-conditioned. 921 * Just what is sufficient? 922 * 3. Multiplying the inverse by the original matrix should 923 * produce a result sufficiently close to the identity 924 * matrix. 925 * Just what is sufficient? 926 * 927 * The following is #3. 928 */ 929 ScMatrixRef xR = GetNewMat( nR, nR); 930 if (xR) 931 { 932 ScMatrix* pR = xR; 933 lcl_MFastMult( pMat, pY, pR, nR, nR, nR); 934 #if OSL_DEBUG_LEVEL > 1 935 fprintf( stderr, "\n%s\n", "ScMatInv(): mult-identity"); 936 #endif 937 for (SCSIZE i=0; i < nR; ++i) 938 { 939 for (SCSIZE j=0; j < nR; ++j) 940 { 941 double fTmp = pR->GetDouble( j, i); 942 #if OSL_DEBUG_LEVEL > 1 943 fprintf( stderr, "%8.2g ", fTmp); 944 #endif 945 if (fabs( fTmp - (i == j)) > fInvEpsilon) 946 SetError( errIllegalArgument); 947 } 948 #if OSL_DEBUG_LEVEL > 1 949 fprintf( stderr, "\n%s\n", ""); 950 #endif 951 } 952 } 953 #endif 954 if (nGlobalError) 955 PushError( nGlobalError); 956 else 957 PushMatrix( pY); 958 } 959 } 960 } 961 } 962 } 963 964 void ScInterpreter::ScMatMult() 965 { 966 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatMult" ); 967 if ( MustHaveParamCount( GetByte(), 2 ) ) 968 { 969 ScMatrixRef pMat2 = GetMatrix(); 970 ScMatrixRef pMat1 = GetMatrix(); 971 ScMatrixRef pRMat; 972 if (pMat1 && pMat2) 973 { 974 if ( pMat1->IsNumeric() && pMat2->IsNumeric() ) 975 { 976 SCSIZE nC1, nC2; 977 SCSIZE nR1, nR2; 978 pMat1->GetDimensions(nC1, nR1); 979 pMat2->GetDimensions(nC2, nR2); 980 if (nC1 != nR2) 981 PushIllegalArgument(); 982 else 983 { 984 pRMat = GetNewMat(nC2, nR1); 985 if (pRMat) 986 { 987 double sum; 988 for (SCSIZE i = 0; i < nR1; i++) 989 { 990 for (SCSIZE j = 0; j < nC2; j++) 991 { 992 sum = 0.0; 993 for (SCSIZE k = 0; k < nC1; k++) 994 { 995 sum += pMat1->GetDouble(k,i)*pMat2->GetDouble(j,k); 996 } 997 pRMat->PutDouble(sum, j, i); 998 } 999 } 1000 PushMatrix(pRMat); 1001 } 1002 else 1003 PushIllegalArgument(); 1004 } 1005 } 1006 else 1007 PushNoValue(); 1008 } 1009 else 1010 PushIllegalParameter(); 1011 } 1012 } 1013 1014 void ScInterpreter::ScMatTrans() 1015 { 1016 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatTrans" ); 1017 if ( MustHaveParamCount( GetByte(), 1 ) ) 1018 { 1019 ScMatrixRef pMat = GetMatrix(); 1020 ScMatrixRef pRMat; 1021 if (pMat) 1022 { 1023 SCSIZE nC, nR; 1024 pMat->GetDimensions(nC, nR); 1025 pRMat = GetNewMat(nR, nC); 1026 if ( pRMat ) 1027 { 1028 pMat->MatTrans(*pRMat); 1029 PushMatrix(pRMat); 1030 } 1031 else 1032 PushIllegalArgument(); 1033 } 1034 else 1035 PushIllegalParameter(); 1036 } 1037 } 1038 1039 1040 /** Minimum extent of one result matrix dimension. 1041 For a row or column vector to be replicated the larger matrix dimension is 1042 returned, else the smaller dimension. 1043 */ 1044 inline SCSIZE lcl_GetMinExtent( SCSIZE n1, SCSIZE n2 ) 1045 { 1046 if (n1 == 1) 1047 return n2; 1048 else if (n2 == 1) 1049 return n1; 1050 else if (n1 < n2) 1051 return n1; 1052 else 1053 return n2; 1054 } 1055 1056 template<class _Function> 1057 ScMatrixRef lcl_MatrixCalculation(const _Function& _pOperation,ScMatrix* pMat1, ScMatrix* pMat2,ScInterpreter* _pIterpreter) 1058 { 1059 SCSIZE nC1, nC2, nMinC; 1060 SCSIZE nR1, nR2, nMinR; 1061 SCSIZE i, j; 1062 pMat1->GetDimensions(nC1, nR1); 1063 pMat2->GetDimensions(nC2, nR2); 1064 nMinC = lcl_GetMinExtent( nC1, nC2); 1065 nMinR = lcl_GetMinExtent( nR1, nR2); 1066 ScMatrixRef xResMat = _pIterpreter->GetNewMat(nMinC, nMinR); 1067 if (xResMat) 1068 { 1069 ScMatrix* pResMat = xResMat; 1070 for (i = 0; i < nMinC; i++) 1071 { 1072 for (j = 0; j < nMinR; j++) 1073 { 1074 if (pMat1->IsValueOrEmpty(i,j) && pMat2->IsValueOrEmpty(i,j)) 1075 { 1076 double d = _pOperation(pMat1->GetDouble(i,j),pMat2->GetDouble(i,j)); 1077 pResMat->PutDouble( d, i, j); 1078 } 1079 else 1080 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, j); 1081 } 1082 } 1083 } 1084 return xResMat; 1085 } 1086 1087 ScMatrixRef ScInterpreter::MatConcat(ScMatrix* pMat1, ScMatrix* pMat2) 1088 { 1089 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MatConcat" ); 1090 SCSIZE nC1, nC2, nMinC; 1091 SCSIZE nR1, nR2, nMinR; 1092 SCSIZE i, j; 1093 pMat1->GetDimensions(nC1, nR1); 1094 pMat2->GetDimensions(nC2, nR2); 1095 nMinC = lcl_GetMinExtent( nC1, nC2); 1096 nMinR = lcl_GetMinExtent( nR1, nR2); 1097 ScMatrixRef xResMat = GetNewMat(nMinC, nMinR); 1098 if (xResMat) 1099 { 1100 ScMatrix* pResMat = xResMat; 1101 for (i = 0; i < nMinC; i++) 1102 { 1103 for (j = 0; j < nMinR; j++) 1104 { 1105 sal_uInt16 nErr = pMat1->GetErrorIfNotString( i, j); 1106 if (!nErr) 1107 nErr = pMat2->GetErrorIfNotString( i, j); 1108 if (nErr) 1109 pResMat->PutError( nErr, i, j); 1110 else 1111 { 1112 String aTmp( pMat1->GetString( *pFormatter, i, j)); 1113 aTmp += pMat2->GetString( *pFormatter, i, j); 1114 pResMat->PutString( aTmp, i, j); 1115 } 1116 } 1117 } 1118 } 1119 return xResMat; 1120 } 1121 1122 1123 // fuer DATE, TIME, DATETIME 1124 void lcl_GetDiffDateTimeFmtType( short& nFuncFmt, short nFmt1, short nFmt2 ) 1125 { 1126 if ( nFmt1 != NUMBERFORMAT_UNDEFINED || nFmt2 != NUMBERFORMAT_UNDEFINED ) 1127 { 1128 if ( nFmt1 == nFmt2 ) 1129 { 1130 if ( nFmt1 == NUMBERFORMAT_TIME || nFmt1 == NUMBERFORMAT_DATETIME ) 1131 nFuncFmt = NUMBERFORMAT_TIME; // Zeiten ergeben Zeit 1132 // else: nichts besonderes, Zahl (Datum - Datum := Tage) 1133 } 1134 else if ( nFmt1 == NUMBERFORMAT_UNDEFINED ) 1135 nFuncFmt = nFmt2; // z.B. Datum + Tage := Datum 1136 else if ( nFmt2 == NUMBERFORMAT_UNDEFINED ) 1137 nFuncFmt = nFmt1; 1138 else 1139 { 1140 if ( nFmt1 == NUMBERFORMAT_DATE || nFmt2 == NUMBERFORMAT_DATE || 1141 nFmt1 == NUMBERFORMAT_DATETIME || nFmt2 == NUMBERFORMAT_DATETIME ) 1142 { 1143 if ( nFmt1 == NUMBERFORMAT_TIME || nFmt2 == NUMBERFORMAT_TIME ) 1144 nFuncFmt = NUMBERFORMAT_DATETIME; // Datum + Zeit 1145 } 1146 } 1147 } 1148 } 1149 1150 1151 void ScInterpreter::ScAdd() 1152 { 1153 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAdd" ); 1154 CalculateAddSub(sal_False); 1155 } 1156 void ScInterpreter::CalculateAddSub(sal_Bool _bSub) 1157 { 1158 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateAddSub" ); 1159 ScMatrixRef pMat1 = NULL; 1160 ScMatrixRef pMat2 = NULL; 1161 double fVal1 = 0.0, fVal2 = 0.0; 1162 short nFmt1, nFmt2; 1163 nFmt1 = nFmt2 = NUMBERFORMAT_UNDEFINED; 1164 short nFmtCurrencyType = nCurFmtType; 1165 sal_uLong nFmtCurrencyIndex = nCurFmtIndex; 1166 short nFmtPercentType = nCurFmtType; 1167 if ( GetStackType() == svMatrix ) 1168 pMat2 = GetMatrix(); 1169 else 1170 { 1171 fVal2 = GetDouble(); 1172 switch ( nCurFmtType ) 1173 { 1174 case NUMBERFORMAT_DATE : 1175 case NUMBERFORMAT_TIME : 1176 case NUMBERFORMAT_DATETIME : 1177 nFmt2 = nCurFmtType; 1178 break; 1179 case NUMBERFORMAT_CURRENCY : 1180 nFmtCurrencyType = nCurFmtType; 1181 nFmtCurrencyIndex = nCurFmtIndex; 1182 break; 1183 case NUMBERFORMAT_PERCENT : 1184 nFmtPercentType = NUMBERFORMAT_PERCENT; 1185 break; 1186 } 1187 } 1188 if ( GetStackType() == svMatrix ) 1189 pMat1 = GetMatrix(); 1190 else 1191 { 1192 fVal1 = GetDouble(); 1193 switch ( nCurFmtType ) 1194 { 1195 case NUMBERFORMAT_DATE : 1196 case NUMBERFORMAT_TIME : 1197 case NUMBERFORMAT_DATETIME : 1198 nFmt1 = nCurFmtType; 1199 break; 1200 case NUMBERFORMAT_CURRENCY : 1201 nFmtCurrencyType = nCurFmtType; 1202 nFmtCurrencyIndex = nCurFmtIndex; 1203 break; 1204 case NUMBERFORMAT_PERCENT : 1205 nFmtPercentType = NUMBERFORMAT_PERCENT; 1206 break; 1207 } 1208 } 1209 if (pMat1 && pMat2) 1210 { 1211 ScMatrixRef pResMat; 1212 if ( _bSub ) 1213 { 1214 MatrixSub aSub; 1215 pResMat = lcl_MatrixCalculation(aSub ,pMat1, pMat2,this); 1216 } 1217 else 1218 { 1219 MatrixAdd aAdd; 1220 pResMat = lcl_MatrixCalculation(aAdd ,pMat1, pMat2,this); 1221 } 1222 1223 if (!pResMat) 1224 PushNoValue(); 1225 else 1226 PushMatrix(pResMat); 1227 } 1228 else if (pMat1 || pMat2) 1229 { 1230 double fVal; 1231 sal_Bool bFlag; 1232 ScMatrixRef pMat = pMat1; 1233 if (!pMat) 1234 { 1235 fVal = fVal1; 1236 pMat = pMat2; 1237 bFlag = sal_True; // double - Matrix 1238 } 1239 else 1240 { 1241 fVal = fVal2; 1242 bFlag = sal_False; // Matrix - double 1243 } 1244 SCSIZE nC, nR; 1245 pMat->GetDimensions(nC, nR); 1246 ScMatrixRef pResMat = GetNewMat(nC, nR); 1247 if (pResMat) 1248 { 1249 SCSIZE nCount = nC * nR; 1250 if (bFlag || !_bSub ) 1251 { 1252 for ( SCSIZE i = 0; i < nCount; i++ ) 1253 { 1254 if (pMat->IsValue(i)) 1255 pResMat->PutDouble( _bSub ? ::rtl::math::approxSub( fVal, pMat->GetDouble(i)) : ::rtl::math::approxAdd( pMat->GetDouble(i), fVal), i); 1256 else 1257 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i); 1258 } // for ( SCSIZE i = 0; i < nCount; i++ ) 1259 } // if (bFlag || !_bSub ) 1260 else 1261 { 1262 for ( SCSIZE i = 0; i < nCount; i++ ) 1263 { if (pMat->IsValue(i)) 1264 pResMat->PutDouble( ::rtl::math::approxSub( pMat->GetDouble(i), fVal), i); 1265 else 1266 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i); 1267 } // for ( SCSIZE i = 0; i < nCount; i++ ) 1268 } 1269 PushMatrix(pResMat); 1270 } 1271 else 1272 PushIllegalArgument(); 1273 } 1274 else if ( _bSub ) 1275 PushDouble( ::rtl::math::approxSub( fVal1, fVal2 ) ); 1276 else 1277 PushDouble( ::rtl::math::approxAdd( fVal1, fVal2 ) ); 1278 if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY ) 1279 { 1280 nFuncFmtType = nFmtCurrencyType; 1281 nFuncFmtIndex = nFmtCurrencyIndex; 1282 } 1283 else 1284 { 1285 lcl_GetDiffDateTimeFmtType( nFuncFmtType, nFmt1, nFmt2 ); 1286 if ( nFmtPercentType == NUMBERFORMAT_PERCENT && nFuncFmtType == NUMBERFORMAT_NUMBER ) 1287 nFuncFmtType = NUMBERFORMAT_PERCENT; 1288 } 1289 } 1290 1291 void ScInterpreter::ScAmpersand() 1292 { 1293 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAmpersand" ); 1294 ScMatrixRef pMat1 = NULL; 1295 ScMatrixRef pMat2 = NULL; 1296 String sStr1, sStr2; 1297 if ( GetStackType() == svMatrix ) 1298 pMat2 = GetMatrix(); 1299 else 1300 sStr2 = GetString(); 1301 if ( GetStackType() == svMatrix ) 1302 pMat1 = GetMatrix(); 1303 else 1304 sStr1 = GetString(); 1305 if (pMat1 && pMat2) 1306 { 1307 ScMatrixRef pResMat = MatConcat(pMat1, pMat2); 1308 if (!pResMat) 1309 PushNoValue(); 1310 else 1311 PushMatrix(pResMat); 1312 } 1313 else if (pMat1 || pMat2) 1314 { 1315 String sStr; 1316 sal_Bool bFlag; 1317 ScMatrixRef pMat = pMat1; 1318 if (!pMat) 1319 { 1320 sStr = sStr1; 1321 pMat = pMat2; 1322 bFlag = sal_True; // double - Matrix 1323 } 1324 else 1325 { 1326 sStr = sStr2; 1327 bFlag = sal_False; // Matrix - double 1328 } 1329 SCSIZE nC, nR; 1330 pMat->GetDimensions(nC, nR); 1331 ScMatrixRef pResMat = GetNewMat(nC, nR); 1332 if (pResMat) 1333 { 1334 SCSIZE nCount = nC * nR; 1335 if (nGlobalError) 1336 { 1337 for ( SCSIZE i = 0; i < nCount; i++ ) 1338 pResMat->PutError( nGlobalError, i); 1339 } 1340 else if (bFlag) 1341 { 1342 for ( SCSIZE i = 0; i < nCount; i++ ) 1343 { 1344 sal_uInt16 nErr = pMat->GetErrorIfNotString( i); 1345 if (nErr) 1346 pResMat->PutError( nErr, i); 1347 else 1348 { 1349 String aTmp( sStr); 1350 aTmp += pMat->GetString( *pFormatter, i); 1351 pResMat->PutString( aTmp, i); 1352 } 1353 } 1354 } 1355 else 1356 { 1357 for ( SCSIZE i = 0; i < nCount; i++ ) 1358 { 1359 sal_uInt16 nErr = pMat->GetErrorIfNotString( i); 1360 if (nErr) 1361 pResMat->PutError( nErr, i); 1362 else 1363 { 1364 String aTmp( pMat->GetString( *pFormatter, i)); 1365 aTmp += sStr; 1366 pResMat->PutString( aTmp, i); 1367 } 1368 } 1369 } 1370 PushMatrix(pResMat); 1371 } 1372 else 1373 PushIllegalArgument(); 1374 } 1375 else 1376 { 1377 if ( CheckStringResultLen( sStr1, sStr2 ) ) 1378 sStr1 += sStr2; 1379 PushString(sStr1); 1380 } 1381 } 1382 1383 void ScInterpreter::ScSub() 1384 { 1385 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSub" ); 1386 CalculateAddSub(sal_True); 1387 } 1388 1389 void ScInterpreter::ScMul() 1390 { 1391 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMul" ); 1392 ScMatrixRef pMat1 = NULL; 1393 ScMatrixRef pMat2 = NULL; 1394 double fVal1 = 0.0, fVal2 = 0.0; 1395 short nFmtCurrencyType = nCurFmtType; 1396 sal_uLong nFmtCurrencyIndex = nCurFmtIndex; 1397 if ( GetStackType() == svMatrix ) 1398 pMat2 = GetMatrix(); 1399 else 1400 { 1401 fVal2 = GetDouble(); 1402 switch ( nCurFmtType ) 1403 { 1404 case NUMBERFORMAT_CURRENCY : 1405 nFmtCurrencyType = nCurFmtType; 1406 nFmtCurrencyIndex = nCurFmtIndex; 1407 break; 1408 } 1409 } 1410 if ( GetStackType() == svMatrix ) 1411 pMat1 = GetMatrix(); 1412 else 1413 { 1414 fVal1 = GetDouble(); 1415 switch ( nCurFmtType ) 1416 { 1417 case NUMBERFORMAT_CURRENCY : 1418 nFmtCurrencyType = nCurFmtType; 1419 nFmtCurrencyIndex = nCurFmtIndex; 1420 break; 1421 } 1422 } 1423 if (pMat1 && pMat2) 1424 { 1425 MatrixMul aMul; 1426 ScMatrixRef pResMat = lcl_MatrixCalculation(aMul,pMat1, pMat2,this); 1427 if (!pResMat) 1428 PushNoValue(); 1429 else 1430 PushMatrix(pResMat); 1431 } 1432 else if (pMat1 || pMat2) 1433 { 1434 double fVal; 1435 ScMatrixRef pMat = pMat1; 1436 if (!pMat) 1437 { 1438 fVal = fVal1; 1439 pMat = pMat2; 1440 } 1441 else 1442 fVal = fVal2; 1443 SCSIZE nC, nR; 1444 pMat->GetDimensions(nC, nR); 1445 ScMatrixRef pResMat = GetNewMat(nC, nR); 1446 if (pResMat) 1447 { 1448 SCSIZE nCount = nC * nR; 1449 for ( SCSIZE i = 0; i < nCount; i++ ) 1450 if (pMat->IsValue(i)) 1451 pResMat->PutDouble(pMat->GetDouble(i)*fVal, i); 1452 else 1453 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i); 1454 PushMatrix(pResMat); 1455 } 1456 else 1457 PushIllegalArgument(); 1458 } 1459 else 1460 PushDouble(fVal1 * fVal2); 1461 if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY ) 1462 { 1463 nFuncFmtType = nFmtCurrencyType; 1464 nFuncFmtIndex = nFmtCurrencyIndex; 1465 } 1466 } 1467 1468 void ScInterpreter::ScDiv() 1469 { 1470 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDiv" ); 1471 ScMatrixRef pMat1 = NULL; 1472 ScMatrixRef pMat2 = NULL; 1473 double fVal1 = 0.0, fVal2 = 0.0; 1474 short nFmtCurrencyType = nCurFmtType; 1475 sal_uLong nFmtCurrencyIndex = nCurFmtIndex; 1476 short nFmtCurrencyType2 = NUMBERFORMAT_UNDEFINED; 1477 if ( GetStackType() == svMatrix ) 1478 pMat2 = GetMatrix(); 1479 else 1480 { 1481 fVal2 = GetDouble(); 1482 // hier kein Currency uebernehmen, 123kg/456DM sind nicht DM 1483 nFmtCurrencyType2 = nCurFmtType; 1484 } 1485 if ( GetStackType() == svMatrix ) 1486 pMat1 = GetMatrix(); 1487 else 1488 { 1489 fVal1 = GetDouble(); 1490 switch ( nCurFmtType ) 1491 { 1492 case NUMBERFORMAT_CURRENCY : 1493 nFmtCurrencyType = nCurFmtType; 1494 nFmtCurrencyIndex = nCurFmtIndex; 1495 break; 1496 } 1497 } 1498 if (pMat1 && pMat2) 1499 { 1500 MatrixDiv aDiv; 1501 ScMatrixRef pResMat = lcl_MatrixCalculation(aDiv,pMat1, pMat2,this); 1502 if (!pResMat) 1503 PushNoValue(); 1504 else 1505 PushMatrix(pResMat); 1506 } 1507 else if (pMat1 || pMat2) 1508 { 1509 double fVal; 1510 sal_Bool bFlag; 1511 ScMatrixRef pMat = pMat1; 1512 if (!pMat) 1513 { 1514 fVal = fVal1; 1515 pMat = pMat2; 1516 bFlag = sal_True; // double - Matrix 1517 } 1518 else 1519 { 1520 fVal = fVal2; 1521 bFlag = sal_False; // Matrix - double 1522 } 1523 SCSIZE nC, nR; 1524 pMat->GetDimensions(nC, nR); 1525 ScMatrixRef pResMat = GetNewMat(nC, nR); 1526 if (pResMat) 1527 { 1528 SCSIZE nCount = nC * nR; 1529 if (bFlag) 1530 { for ( SCSIZE i = 0; i < nCount; i++ ) 1531 if (pMat->IsValue(i)) 1532 pResMat->PutDouble( div( fVal, pMat->GetDouble(i)), i); 1533 else 1534 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i); 1535 } 1536 else 1537 { for ( SCSIZE i = 0; i < nCount; i++ ) 1538 if (pMat->IsValue(i)) 1539 pResMat->PutDouble( div( pMat->GetDouble(i), fVal), i); 1540 else 1541 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i); 1542 } 1543 PushMatrix(pResMat); 1544 } 1545 else 1546 PushIllegalArgument(); 1547 } 1548 else 1549 { 1550 PushDouble( div( fVal1, fVal2) ); 1551 } 1552 if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY && nFmtCurrencyType2 != NUMBERFORMAT_CURRENCY ) 1553 { // auch DM/DM ist nicht DM bzw. DEM/EUR nicht DEM 1554 nFuncFmtType = nFmtCurrencyType; 1555 nFuncFmtIndex = nFmtCurrencyIndex; 1556 } 1557 } 1558 1559 void ScInterpreter::ScPower() 1560 { 1561 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPower" ); 1562 if ( MustHaveParamCount( GetByte(), 2 ) ) 1563 ScPow(); 1564 } 1565 1566 void ScInterpreter::ScPow() 1567 { 1568 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPow" ); 1569 ScMatrixRef pMat1 = NULL; 1570 ScMatrixRef pMat2 = NULL; 1571 double fVal1 = 0.0, fVal2 = 0.0; 1572 if ( GetStackType() == svMatrix ) 1573 pMat2 = GetMatrix(); 1574 else 1575 fVal2 = GetDouble(); 1576 if ( GetStackType() == svMatrix ) 1577 pMat1 = GetMatrix(); 1578 else 1579 fVal1 = GetDouble(); 1580 if (pMat1 && pMat2) 1581 { 1582 MatrixPow aPow; 1583 ScMatrixRef pResMat = lcl_MatrixCalculation(aPow,pMat1, pMat2,this); 1584 if (!pResMat) 1585 PushNoValue(); 1586 else 1587 PushMatrix(pResMat); 1588 } 1589 else if (pMat1 || pMat2) 1590 { 1591 double fVal; 1592 sal_Bool bFlag; 1593 ScMatrixRef pMat = pMat1; 1594 if (!pMat) 1595 { 1596 fVal = fVal1; 1597 pMat = pMat2; 1598 bFlag = sal_True; // double - Matrix 1599 } 1600 else 1601 { 1602 fVal = fVal2; 1603 bFlag = sal_False; // Matrix - double 1604 } 1605 SCSIZE nC, nR; 1606 pMat->GetDimensions(nC, nR); 1607 ScMatrixRef pResMat = GetNewMat(nC, nR); 1608 if (pResMat) 1609 { 1610 SCSIZE nCount = nC * nR; 1611 if (bFlag) 1612 { for ( SCSIZE i = 0; i < nCount; i++ ) 1613 if (pMat->IsValue(i)) 1614 pResMat->PutDouble(pow(fVal,pMat->GetDouble(i)), i); 1615 else 1616 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i); 1617 } 1618 else 1619 { for ( SCSIZE i = 0; i < nCount; i++ ) 1620 if (pMat->IsValue(i)) 1621 pResMat->PutDouble(pow(pMat->GetDouble(i),fVal), i); 1622 else 1623 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i); 1624 } 1625 PushMatrix(pResMat); 1626 } 1627 else 1628 PushIllegalArgument(); 1629 } 1630 else 1631 PushDouble(pow(fVal1,fVal2)); 1632 } 1633 1634 void ScInterpreter::ScSumProduct() 1635 { 1636 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumProduct" ); 1637 sal_uInt8 nParamCount = GetByte(); 1638 if ( !MustHaveParamCount( nParamCount, 1, 30 ) ) 1639 return; 1640 1641 ScMatrixRef pMat1 = NULL; 1642 ScMatrixRef pMat2 = NULL; 1643 ScMatrixRef pMat = NULL; 1644 pMat2 = GetMatrix(); 1645 if (!pMat2) 1646 { 1647 PushIllegalParameter(); 1648 return; 1649 } 1650 SCSIZE nC, nC1; 1651 SCSIZE nR, nR1; 1652 pMat2->GetDimensions(nC, nR); 1653 pMat = pMat2; 1654 MatrixMul aMul; 1655 for (sal_uInt16 i = 1; i < nParamCount; i++) 1656 { 1657 pMat1 = GetMatrix(); 1658 if (!pMat1) 1659 { 1660 PushIllegalParameter(); 1661 return; 1662 } 1663 pMat1->GetDimensions(nC1, nR1); 1664 if (nC1 != nC || nR1 != nR) 1665 { 1666 PushNoValue(); 1667 return; 1668 } 1669 ScMatrixRef pResMat = lcl_MatrixCalculation(aMul,pMat1, pMat,this); 1670 if (!pResMat) 1671 { 1672 PushNoValue(); 1673 return; 1674 } 1675 else 1676 pMat = pResMat; 1677 } 1678 double fSum = 0.0; 1679 SCSIZE nCount = pMat->GetElementCount(); 1680 for (SCSIZE j = 0; j < nCount; j++) 1681 { 1682 if (!pMat->IsString(j)) 1683 fSum += pMat->GetDouble(j); 1684 } 1685 PushDouble(fSum); 1686 } 1687 1688 void ScInterpreter::ScSumX2MY2() 1689 { 1690 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumX2MY2" ); 1691 CalculateSumX2MY2SumX2DY2(sal_False); 1692 } 1693 void ScInterpreter::CalculateSumX2MY2SumX2DY2(sal_Bool _bSumX2DY2) 1694 { 1695 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateSumX2MY2SumX2DY2" ); 1696 if ( !MustHaveParamCount( GetByte(), 2 ) ) 1697 return; 1698 1699 ScMatrixRef pMat1 = NULL; 1700 ScMatrixRef pMat2 = NULL; 1701 SCSIZE i, j; 1702 pMat2 = GetMatrix(); 1703 pMat1 = GetMatrix(); 1704 if (!pMat2 || !pMat1) 1705 { 1706 PushIllegalParameter(); 1707 return; 1708 } 1709 SCSIZE nC1, nC2; 1710 SCSIZE nR1, nR2; 1711 pMat2->GetDimensions(nC2, nR2); 1712 pMat1->GetDimensions(nC1, nR1); 1713 if (nC1 != nC2 || nR1 != nR2) 1714 { 1715 PushNoValue(); 1716 return; 1717 } 1718 double fVal, fSum = 0.0; 1719 for (i = 0; i < nC1; i++) 1720 for (j = 0; j < nR1; j++) 1721 if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j)) 1722 { 1723 fVal = pMat1->GetDouble(i,j); 1724 fSum += fVal * fVal; 1725 fVal = pMat2->GetDouble(i,j); 1726 if ( _bSumX2DY2 ) 1727 fSum += fVal * fVal; 1728 else 1729 fSum -= fVal * fVal; 1730 } 1731 PushDouble(fSum); 1732 } 1733 1734 void ScInterpreter::ScSumX2DY2() 1735 { 1736 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumX2DY2" ); 1737 CalculateSumX2MY2SumX2DY2(sal_True); 1738 } 1739 1740 void ScInterpreter::ScSumXMY2() 1741 { 1742 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumXMY2" ); 1743 if ( !MustHaveParamCount( GetByte(), 2 ) ) 1744 return; 1745 1746 ScMatrixRef pMat1 = NULL; 1747 ScMatrixRef pMat2 = NULL; 1748 pMat2 = GetMatrix(); 1749 pMat1 = GetMatrix(); 1750 if (!pMat2 || !pMat1) 1751 { 1752 PushIllegalParameter(); 1753 return; 1754 } 1755 SCSIZE nC1, nC2; 1756 SCSIZE nR1, nR2; 1757 pMat2->GetDimensions(nC2, nR2); 1758 pMat1->GetDimensions(nC1, nR1); 1759 if (nC1 != nC2 || nR1 != nR2) 1760 { 1761 PushNoValue(); 1762 return; 1763 } // if (nC1 != nC2 || nR1 != nR2) 1764 MatrixSub aSub; 1765 ScMatrixRef pResMat = lcl_MatrixCalculation(aSub,pMat1, pMat2,this); 1766 if (!pResMat) 1767 { 1768 PushNoValue(); 1769 } 1770 else 1771 { 1772 double fVal, fSum = 0.0; 1773 SCSIZE nCount = pResMat->GetElementCount(); 1774 for (SCSIZE i = 0; i < nCount; i++) 1775 if (!pResMat->IsString(i)) 1776 { 1777 fVal = pResMat->GetDouble(i); 1778 fSum += fVal * fVal; 1779 } 1780 PushDouble(fSum); 1781 } 1782 } 1783 1784 void ScInterpreter::ScFrequency() 1785 { 1786 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFrequency" ); 1787 if ( !MustHaveParamCount( GetByte(), 2 ) ) 1788 return; 1789 1790 vector<double> aBinArray; 1791 vector<long> aBinIndexOrder; 1792 1793 GetSortArray(1, aBinArray, &aBinIndexOrder); 1794 SCSIZE nBinSize = aBinArray.size(); 1795 if (nGlobalError) 1796 { 1797 PushNoValue(); 1798 return; 1799 } 1800 1801 vector<double> aDataArray; 1802 GetSortArray(1, aDataArray); 1803 SCSIZE nDataSize = aDataArray.size(); 1804 1805 if (aDataArray.empty() || nGlobalError) 1806 { 1807 PushNoValue(); 1808 return; 1809 } 1810 ScMatrixRef pResMat = GetNewMat(1, nBinSize+1); 1811 if (!pResMat) 1812 { 1813 PushIllegalArgument(); 1814 return; 1815 } 1816 1817 if (nBinSize != aBinIndexOrder.size()) 1818 { 1819 PushIllegalArgument(); 1820 return; 1821 } 1822 1823 SCSIZE j; 1824 SCSIZE i = 0; 1825 for (j = 0; j < nBinSize; ++j) 1826 { 1827 SCSIZE nCount = 0; 1828 while (i < nDataSize && aDataArray[i] <= aBinArray[j]) 1829 { 1830 ++nCount; 1831 ++i; 1832 } 1833 pResMat->PutDouble(static_cast<double>(nCount), aBinIndexOrder[j]); 1834 } 1835 pResMat->PutDouble(static_cast<double>(nDataSize-i), j); 1836 PushMatrix(pResMat); 1837 } 1838 1839 // ----------------------------------------------------------------------------- 1840 // Helper methods for LINEST/LOGEST and TREND/GROWTH 1841 // All matrices must already exist and have the needed size, no control tests 1842 // done. Those methodes, which names start with lcl_T, are adapted to case 3, 1843 // where Y (=observed values) is given as row. 1844 // Remember, ScMatrix matrices are zero based, index access (column,row). 1845 // ----------------------------------------------------------------------------- 1846 1847 // Multiply n x m Mat A with m x l Mat B to n x l Mat R 1848 void lcl_MFastMult( ScMatrixRef pA, ScMatrixRef pB, ScMatrixRef pR, SCSIZE n, SCSIZE m, SCSIZE l ) 1849 { 1850 double sum; 1851 for (SCSIZE row = 0; row < n; row++) 1852 { 1853 for (SCSIZE col = 0; col < l; col++) 1854 { // result element(col, row) =sum[ (row of A) * (column of B)] 1855 sum = 0.0; 1856 for (SCSIZE k = 0; k < m; k++) 1857 sum += pA->GetDouble(k,row) * pB->GetDouble(col,k); 1858 pR->PutDouble(sum, col, row); 1859 } 1860 } 1861 } 1862 1863 // <A;B> over all elements; uses the matrices as vectors of length M 1864 double lcl_GetSumProduct( ScMatrixRef pMatA, ScMatrixRef pMatB, SCSIZE nM ) 1865 { 1866 double fSum = 0.0; 1867 for (SCSIZE i=0; i<nM; i++) 1868 fSum += pMatA->GetDouble(i) * pMatB->GetDouble(i); 1869 return fSum; 1870 } 1871 1872 // Special version for use within QR decomposition. 1873 // Euclidean norm of column index C starting in row index R; 1874 // matrix A has count N rows. 1875 double lcl_GetColumnEuclideanNorm( ScMatrixRef pMatA, SCSIZE nC, SCSIZE nR, SCSIZE nN ) 1876 { 1877 double fNorm = 0.0; 1878 for (SCSIZE row=nR; row<nN; row++) 1879 fNorm += (pMatA->GetDouble(nC,row)) * (pMatA->GetDouble(nC,row)); 1880 return sqrt(fNorm); 1881 } 1882 1883 // Euclidean norm of row index R starting in column index C; 1884 // matrix A has count N columns. 1885 double lcl_TGetColumnEuclideanNorm( ScMatrixRef pMatA, SCSIZE nR, SCSIZE nC, SCSIZE nN ) 1886 { 1887 double fNorm = 0.0; 1888 for (SCSIZE col=nC; col<nN; col++) 1889 fNorm += (pMatA->GetDouble(col,nR)) * (pMatA->GetDouble(col,nR)); 1890 return sqrt(fNorm); 1891 } 1892 1893 // Special version for use within QR decomposition. 1894 // Maximum norm of column index C starting in row index R; 1895 // matrix A has count N rows. 1896 double lcl_GetColumnMaximumNorm( ScMatrixRef pMatA, SCSIZE nC, SCSIZE nR, SCSIZE nN ) 1897 { 1898 double fNorm = 0.0; 1899 for (SCSIZE row=nR; row<nN; row++) 1900 if (fNorm < fabs(pMatA->GetDouble(nC,row))) 1901 fNorm = fabs(pMatA->GetDouble(nC,row)); 1902 return fNorm; 1903 } 1904 1905 // Maximum norm of row index R starting in col index C; 1906 // matrix A has count N columns. 1907 double lcl_TGetColumnMaximumNorm( ScMatrixRef pMatA, SCSIZE nR, SCSIZE nC, SCSIZE nN ) 1908 { 1909 double fNorm = 0.0; 1910 for (SCSIZE col=nC; col<nN; col++) 1911 if (fNorm < fabs(pMatA->GetDouble(col,nR))) 1912 fNorm = fabs(pMatA->GetDouble(col,nR)); 1913 return fNorm; 1914 } 1915 1916 // Special version for use within QR decomposition. 1917 // <A(Ca);B(Cb)> starting in row index R; 1918 // Ca and Cb are indices of columns, matrices A and B have count N rows. 1919 double lcl_GetColumnSumProduct( ScMatrixRef pMatA, SCSIZE nCa, ScMatrixRef pMatB, 1920 SCSIZE nCb, SCSIZE nR, SCSIZE nN ) 1921 { 1922 double fResult = 0.0; 1923 for (SCSIZE row=nR; row<nN; row++) 1924 fResult += pMatA->GetDouble(nCa,row) * pMatB->GetDouble(nCb,row); 1925 return fResult; 1926 } 1927 1928 // <A(Ra);B(Rb)> starting in column index C; 1929 // Ra and Rb are indices of rows, matrices A and B have count N columns. 1930 double lcl_TGetColumnSumProduct( ScMatrixRef pMatA, SCSIZE nRa, 1931 ScMatrixRef pMatB, SCSIZE nRb, SCSIZE nC, SCSIZE nN ) 1932 { 1933 double fResult = 0.0; 1934 for (SCSIZE col=nC; col<nN; col++) 1935 fResult += pMatA->GetDouble(col,nRa) * pMatB->GetDouble(col,nRb); 1936 return fResult; 1937 } 1938 1939 // #118029# no mathematical signum, but used to switch between adding and subtracting 1940 double lcl_GetSign(double fValue) 1941 { 1942 return (fValue >= 0.0 ? 1.0 : -1.0 ); 1943 } 1944 1945 /* Calculates a QR decomposition with Householder reflection. 1946 * For each NxK matrix A exists a decomposition A=Q*R with an orthogonal 1947 * NxN matrix Q and a NxK matrix R. 1948 * Q=H1*H2*...*Hk with Householder matrices H. Such a householder matrix can 1949 * be build from a vector u by H=I-(2/u'u)*(u u'). This vectors u are returned 1950 * in the columns of matrix A, overwriting the old content. 1951 * The matrix R has a quadric upper part KxK with values in the upper right 1952 * triangle and zeros in all other elements. Here the diagonal elements of R 1953 * are stored in the vector R and the other upper right elements in the upper 1954 * right of the matrix A. 1955 * The function returns false, if calculation breaks. But because of round-off 1956 * errors singularity is often not detected. 1957 */ 1958 bool lcl_CalculateQRdecomposition(ScMatrixRef pMatA, 1959 ::std::vector< double>& pVecR, SCSIZE nK, SCSIZE nN) 1960 { 1961 double fScale ; 1962 double fEuclid ; 1963 double fFactor ; 1964 double fSignum ; 1965 double fSum ; 1966 // ScMatrix matrices are zero based, index access (column,row) 1967 for (SCSIZE col = 0; col <nK; col++) 1968 { 1969 // calculate vector u of the householder transformation 1970 fScale = lcl_GetColumnMaximumNorm(pMatA, col, col, nN); 1971 if (fScale == 0.0) 1972 // A is singular 1973 return false; 1974 1975 for (SCSIZE row = col; row <nN; row++) 1976 pMatA->PutDouble( pMatA->GetDouble(col,row)/fScale, col, row); 1977 1978 fEuclid = lcl_GetColumnEuclideanNorm(pMatA, col, col, nN); 1979 fFactor = 1.0/fEuclid/(fEuclid + fabs(pMatA->GetDouble(col,col))); 1980 fSignum = lcl_GetSign(pMatA->GetDouble(col,col)); 1981 pMatA->PutDouble( pMatA->GetDouble(col,col) + fSignum*fEuclid, col,col); 1982 pVecR[col] = -fSignum * fScale * fEuclid; 1983 1984 // apply Householder transformation to A 1985 for (SCSIZE c=col+1; c<nK; c++) 1986 { 1987 fSum =lcl_GetColumnSumProduct(pMatA, col, pMatA, c, col, nN); 1988 for (SCSIZE row = col; row <nN; row++) 1989 pMatA->PutDouble( pMatA->GetDouble(c,row) 1990 - fSum * fFactor * pMatA->GetDouble(col,row), c, row); 1991 } 1992 } 1993 return true; 1994 } 1995 1996 // same with transposed matrix A, N is count of columns, K count of rows 1997 bool lcl_TCalculateQRdecomposition(ScMatrixRef pMatA, 1998 ::std::vector< double>& pVecR, SCSIZE nK, SCSIZE nN) 1999 { 2000 double fScale ; 2001 double fEuclid ; 2002 double fFactor ; 2003 double fSignum ; 2004 double fSum ; 2005 // ScMatrix matrices are zero based, index access (column,row) 2006 for (SCSIZE row = 0; row <nK; row++) 2007 { 2008 // calculate vector u of the householder transformation 2009 fScale = lcl_TGetColumnMaximumNorm(pMatA, row, row, nN); 2010 if (fScale == 0.0) 2011 // A is singular 2012 return false; 2013 2014 for (SCSIZE col = row; col <nN; col++) 2015 pMatA->PutDouble( pMatA->GetDouble(col,row)/fScale, col, row); 2016 2017 fEuclid = lcl_TGetColumnEuclideanNorm(pMatA, row, row, nN); 2018 fFactor = 1.0/fEuclid/(fEuclid + fabs(pMatA->GetDouble(row,row))); 2019 fSignum = lcl_GetSign(pMatA->GetDouble(row,row)); 2020 pMatA->PutDouble( pMatA->GetDouble(row,row) + fSignum*fEuclid, row,row); 2021 pVecR[row] = -fSignum * fScale * fEuclid; 2022 2023 // apply Householder transformation to A 2024 for (SCSIZE r=row+1; r<nK; r++) 2025 { 2026 fSum =lcl_TGetColumnSumProduct(pMatA, row, pMatA, r, row, nN); 2027 for (SCSIZE col = row; col <nN; col++) 2028 pMatA->PutDouble( pMatA->GetDouble(col,r) 2029 - fSum * fFactor * pMatA->GetDouble(col,row), col, r); 2030 } 2031 } 2032 return true; 2033 } 2034 2035 2036 /* Applies a Householder transformation to a column vector Y with is given as 2037 * Nx1 Matrix. The Vektor u, from which the Householder transformation is build, 2038 * is the column part in matrix A, with column index C, starting with row 2039 * index C. A is the result of the QR decomposition as obtained from 2040 * lcl_CaluclateQRdecomposition. 2041 */ 2042 void lcl_ApplyHouseholderTransformation(ScMatrixRef pMatA, SCSIZE nC, 2043 ScMatrixRef pMatY, SCSIZE nN) 2044 { 2045 // ScMatrix matrices are zero based, index access (column,row) 2046 double fDenominator = lcl_GetColumnSumProduct(pMatA, nC, pMatA, nC, nC, nN); 2047 double fNumerator = lcl_GetColumnSumProduct(pMatA, nC, pMatY, 0, nC, nN); 2048 double fFactor = 2.0 * (fNumerator/fDenominator); 2049 for (SCSIZE row = nC; row < nN; row++) 2050 pMatY->PutDouble( 2051 pMatY->GetDouble(row) - fFactor * pMatA->GetDouble(nC,row), row); 2052 } 2053 2054 // Same with transposed matrices A and Y. 2055 void lcl_TApplyHouseholderTransformation(ScMatrixRef pMatA, SCSIZE nR, 2056 ScMatrixRef pMatY, SCSIZE nN) 2057 { 2058 // ScMatrix matrices are zero based, index access (column,row) 2059 double fDenominator = lcl_TGetColumnSumProduct(pMatA, nR, pMatA, nR, nR, nN); 2060 double fNumerator = lcl_TGetColumnSumProduct(pMatA, nR, pMatY, 0, nR, nN); 2061 double fFactor = 2.0 * (fNumerator/fDenominator); 2062 for (SCSIZE col = nR; col < nN; col++) 2063 pMatY->PutDouble( 2064 pMatY->GetDouble(col) - fFactor * pMatA->GetDouble(col,nR), col); 2065 } 2066 2067 /* Solve for X in R*X=S using back substitution. The solution X overwrites S. 2068 * Uses R from the result of the QR decomposition of a NxK matrix A. 2069 * S is a column vector given as matrix, with at least elements on index 2070 * 0 to K-1; elements on index>=K are ignored. Vector R must not have zero 2071 * elements, no check is done. 2072 */ 2073 void lcl_SolveWithUpperRightTriangle(ScMatrixRef pMatA, 2074 ::std::vector< double>& pVecR, ScMatrixRef pMatS, 2075 SCSIZE nK, bool bIsTransposed) 2076 { 2077 // ScMatrix matrices are zero based, index access (column,row) 2078 double fSum; 2079 SCSIZE row; 2080 // SCSIZE is never negative, therefore test with rowp1=row+1 2081 for (SCSIZE rowp1 = nK; rowp1>0; rowp1--) 2082 { 2083 row = rowp1-1; 2084 fSum = pMatS->GetDouble(row); 2085 for (SCSIZE col = rowp1; col<nK ; col++) 2086 if (bIsTransposed) 2087 fSum -= pMatA->GetDouble(row,col) * pMatS->GetDouble(col); 2088 else 2089 fSum -= pMatA->GetDouble(col,row) * pMatS->GetDouble(col); 2090 pMatS->PutDouble( fSum / pVecR[row] , row); 2091 } 2092 } 2093 2094 /* Solve for X in R' * X= T using forward substitution. The solution X 2095 * overwrites T. Uses R from the result of the QR decomposition of a NxK 2096 * matrix A. T is a column vectors given as matrix, with at least elements on 2097 * index 0 to K-1; elements on index>=K are ignored. Vector R must not have 2098 * zero elements, no check is done. 2099 */ 2100 void lcl_SolveWithLowerLeftTriangle(ScMatrixRef pMatA, 2101 ::std::vector< double>& pVecR, ScMatrixRef pMatT, 2102 SCSIZE nK, bool bIsTransposed) 2103 { 2104 // ScMatrix matrices are zero based, index access (column,row) 2105 double fSum; 2106 for (SCSIZE row = 0; row < nK; row++) 2107 { 2108 fSum = pMatT -> GetDouble(row); 2109 for (SCSIZE col=0; col < row; col++) 2110 { 2111 if (bIsTransposed) 2112 fSum -= pMatA->GetDouble(col,row) * pMatT->GetDouble(col); 2113 else 2114 fSum -= pMatA->GetDouble(row,col) * pMatT->GetDouble(col); 2115 } 2116 pMatT->PutDouble( fSum / pVecR[row] , row); 2117 } 2118 } 2119 2120 /* Calculates Z = R * B 2121 * R is given in matrix A and vector VecR as obtained from the QR 2122 * decompostion in lcl_CalculateQRdecomposition. B and Z are column vectors 2123 * given as matrix with at least index 0 to K-1; elements on index>=K are 2124 * not used. 2125 */ 2126 void lcl_ApplyUpperRightTriangle(ScMatrixRef pMatA, 2127 ::std::vector< double>& pVecR, ScMatrixRef pMatB, 2128 ScMatrixRef pMatZ, SCSIZE nK, bool bIsTransposed) 2129 { 2130 // ScMatrix matrices are zero based, index access (column,row) 2131 double fSum; 2132 for (SCSIZE row = 0; row < nK; row++) 2133 { 2134 fSum = pVecR[row] * pMatB->GetDouble(row); 2135 for (SCSIZE col = row+1; col < nK; col++) 2136 if (bIsTransposed) 2137 fSum += pMatA->GetDouble(row,col) * pMatB->GetDouble(col); 2138 else 2139 fSum += pMatA->GetDouble(col,row) * pMatB->GetDouble(col); 2140 pMatZ->PutDouble( fSum, row); 2141 } 2142 } 2143 2144 2145 2146 double lcl_GetMeanOverAll(ScMatrixRef pMat, SCSIZE nN) 2147 { 2148 double fSum = 0.0; 2149 for (SCSIZE i=0 ; i<nN; i++) 2150 fSum += pMat->GetDouble(i); 2151 return fSum/static_cast<double>(nN); 2152 } 2153 2154 // Calculates means of the columns of matrix X. X is a RxC matrix; 2155 // ResMat is a 1xC matrix (=row). 2156 void lcl_CalculateColumnMeans(ScMatrixRef pX, ScMatrixRef pResMat, 2157 SCSIZE nC, SCSIZE nR) 2158 { 2159 double fSum = 0.0; 2160 for (SCSIZE i=0; i < nC; i++) 2161 { 2162 fSum =0.0; 2163 for (SCSIZE k=0; k < nR; k++) 2164 fSum += pX->GetDouble(i,k); // GetDouble(Column,Row) 2165 pResMat ->PutDouble( fSum/static_cast<double>(nR),i); 2166 } 2167 } 2168 2169 // Calculates means of the rows of matrix X. X is a RxC matrix; 2170 // ResMat is a Rx1 matrix (=column). 2171 void lcl_CalculateRowMeans(ScMatrixRef pX, ScMatrixRef pResMat, 2172 SCSIZE nC, SCSIZE nR) 2173 { 2174 double fSum = 0.0; 2175 for (SCSIZE k=0; k < nR; k++) 2176 { 2177 fSum =0.0; 2178 for (SCSIZE i=0; i < nC; i++) 2179 fSum += pX->GetDouble(i,k); // GetDouble(Column,Row) 2180 pResMat ->PutDouble( fSum/static_cast<double>(nC),k); 2181 } 2182 } 2183 2184 void lcl_CalculateColumnsDelta(ScMatrixRef pMat, ScMatrixRef pColumnMeans, 2185 SCSIZE nC, SCSIZE nR) 2186 { 2187 for (SCSIZE i = 0; i < nC; i++) 2188 for (SCSIZE k = 0; k < nR; k++) 2189 pMat->PutDouble( ::rtl::math::approxSub 2190 (pMat->GetDouble(i,k) , pColumnMeans->GetDouble(i) ) , i, k); 2191 } 2192 2193 void lcl_CalculateRowsDelta(ScMatrixRef pMat, ScMatrixRef pRowMeans, 2194 SCSIZE nC, SCSIZE nR) 2195 { 2196 for (SCSIZE k = 0; k < nR; k++) 2197 for (SCSIZE i = 0; i < nC; i++) 2198 pMat->PutDouble( ::rtl::math::approxSub 2199 ( pMat->GetDouble(i,k) , pRowMeans->GetDouble(k) ) , i, k); 2200 } 2201 2202 // Case1 = simple regression 2203 // MatX = X - MeanX, MatY = Y - MeanY, y - haty = (y - MeanY) - (haty - MeanY) 2204 // = (y-MeanY)-((slope*x+a)-(slope*MeanX+a)) = (y-MeanY)-slope*(x-MeanX) 2205 double lcl_GetSSresid(ScMatrixRef pMatX, ScMatrixRef pMatY, double fSlope, 2206 SCSIZE nN) 2207 { 2208 double fSum = 0.0; 2209 double fTemp = 0.0; 2210 for (SCSIZE i=0; i<nN; i++) 2211 { 2212 fTemp = pMatY->GetDouble(i) - fSlope * pMatX->GetDouble(i); 2213 fSum += fTemp * fTemp; 2214 } 2215 return fSum; 2216 } 2217 2218 // Fill default values in matrix X, transform Y to log(Y) in case LOGEST|GROWTH, 2219 // determine sizes of matrices X and Y, determine kind of regression, clone 2220 // Y in case LOGEST|GROWTH, if constant. 2221 bool ScInterpreter::CheckMatrix(bool _bLOG, sal_uInt8& nCase, SCSIZE& nCX, 2222 SCSIZE& nCY, SCSIZE& nRX, SCSIZE& nRY, SCSIZE& M, 2223 SCSIZE& N, ScMatrixRef& pMatX, ScMatrixRef& pMatY) 2224 { 2225 2226 nCX = 0; 2227 nCY = 0; 2228 nRX = 0; 2229 nRY = 0; 2230 M = 0; 2231 N = 0; 2232 pMatY->GetDimensions(nCY, nRY); 2233 const SCSIZE nCountY = nCY * nRY; 2234 for ( SCSIZE i = 0; i < nCountY; i++ ) 2235 { 2236 if (!pMatY->IsValue(i)) 2237 { 2238 PushIllegalArgument(); 2239 return false; 2240 } 2241 } 2242 2243 if ( _bLOG ) 2244 { 2245 ScMatrixRef pNewY = pMatY->CloneIfConst(); 2246 for (SCSIZE nElem = 0; nElem < nCountY; nElem++) 2247 { 2248 const double fVal = pNewY->GetDouble(nElem); 2249 if (fVal <= 0.0) 2250 { 2251 PushIllegalArgument(); 2252 return false; 2253 } 2254 else 2255 pNewY->PutDouble(log(fVal), nElem); 2256 } 2257 pMatY = pNewY; 2258 } 2259 2260 if (pMatX) 2261 { 2262 pMatX->GetDimensions(nCX, nRX); 2263 const SCSIZE nCountX = nCX * nRX; 2264 for ( SCSIZE i = 0; i < nCountX; i++ ) 2265 if (!pMatX->IsValue(i)) 2266 { 2267 PushIllegalArgument(); 2268 return false; 2269 } 2270 if (nCX == nCY && nRX == nRY) 2271 { 2272 nCase = 1; // simple regression 2273 M = 1; 2274 N = nCountY; 2275 } 2276 else if (nCY != 1 && nRY != 1) 2277 { 2278 PushIllegalArgument(); 2279 return false; 2280 } 2281 else if (nCY == 1) 2282 { 2283 if (nRX != nRY) 2284 { 2285 PushIllegalArgument(); 2286 return false; 2287 } 2288 else 2289 { 2290 nCase = 2; // Y is column 2291 N = nRY; 2292 M = nCX; 2293 } 2294 } 2295 else if (nCX != nCY) 2296 { 2297 PushIllegalArgument(); 2298 return false; 2299 } 2300 else 2301 { 2302 nCase = 3; // Y is row 2303 N = nCY; 2304 M = nRX; 2305 } 2306 } 2307 else 2308 { 2309 pMatX = GetNewMat(nCY, nRY); 2310 nCX = nCY; 2311 nRX = nRY; 2312 if (!pMatX) 2313 { 2314 PushIllegalArgument(); 2315 return false; 2316 } 2317 for ( SCSIZE i = 1; i <= nCountY; i++ ) 2318 pMatX->PutDouble(static_cast<double>(i), i-1); 2319 nCase = 1; 2320 N = nCountY; 2321 M = 1; 2322 } 2323 return true; 2324 } 2325 // ----------------------------------------------------------------------------- 2326 2327 // LINEST 2328 void ScInterpreter::ScRGP() 2329 { 2330 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRGP" ); 2331 CalulateRGPRKP(false); 2332 } 2333 2334 // LOGEST 2335 void ScInterpreter::ScRKP() 2336 { 2337 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRKP" ); 2338 CalulateRGPRKP(true); 2339 } 2340 2341 void ScInterpreter::CalulateRGPRKP(bool _bRKP) 2342 { 2343 sal_uInt8 nParamCount = GetByte(); 2344 if ( !MustHaveParamCount( nParamCount, 1, 4 ) ) 2345 return; 2346 bool bConstant, bStats; 2347 2348 // optional forth parameter 2349 if (nParamCount == 4) 2350 bStats = GetBool(); 2351 else 2352 bStats = false; 2353 2354 // The third parameter may not be missing in ODF, if the forth parameter 2355 // is present. But Excel allows it with default true, we too. 2356 if (nParamCount >= 3) 2357 { 2358 if (IsMissing()) 2359 { 2360 Pop(); 2361 bConstant = true; 2362 // PushIllegalParameter(); if ODF behavior is desired 2363 // return; 2364 } 2365 else 2366 bConstant = GetBool(); 2367 } 2368 else 2369 bConstant = true; 2370 2371 ScMatrixRef pMatX; 2372 if (nParamCount >= 2) 2373 { 2374 if (IsMissing()) 2375 { 2376 // In ODF1.2 empty second parameter (which is two ;; ) is allowed 2377 Pop(); 2378 pMatX = NULL; 2379 } 2380 else 2381 { 2382 pMatX = GetMatrix(); 2383 } 2384 } 2385 else 2386 pMatX = NULL; 2387 2388 ScMatrixRef pMatY; 2389 pMatY = GetMatrix(); 2390 if (!pMatY) 2391 { 2392 PushIllegalParameter(); 2393 return; 2394 } 2395 2396 // 1 = simple; 2 = multiple with Y as column; 3 = multiple with Y as row 2397 sal_uInt8 nCase; 2398 2399 SCSIZE nCX, nCY; // number of columns 2400 SCSIZE nRX, nRY; // number of rows 2401 SCSIZE K = 0, N = 0; // K=number of variables X, N=number of data samples 2402 if ( !CheckMatrix(_bRKP,nCase,nCX,nCY,nRX,nRY,K,N,pMatX,pMatY) ) 2403 { 2404 PushIllegalParameter(); 2405 return; 2406 } 2407 2408 // Enough data samples? 2409 if ( (bConstant && (N<K+1)) || (!bConstant && (N<K)) || (N<1) || (K<1) ) 2410 { 2411 PushIllegalParameter(); 2412 return; 2413 } 2414 2415 ScMatrixRef pResMat; 2416 if (bStats) 2417 pResMat = GetNewMat(K+1,5); 2418 else 2419 pResMat = GetNewMat(K+1,1); 2420 if (!pResMat) 2421 { 2422 PushError(errCodeOverflow); 2423 return; 2424 } 2425 // Fill unused cells in pResMat; order (column,row) 2426 if (bStats) 2427 { 2428 for (SCSIZE i=2; i<K+1; i++) 2429 { 2430 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 2 ); 2431 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 3 ); 2432 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 4 ); 2433 } 2434 } 2435 2436 // Uses sum(x-MeanX)^2 and not [sum x^2]-N * MeanX^2 in case bConstant. 2437 // Clone constant matrices, so that Mat = Mat - Mean is possible. 2438 double fMeanY = 0.0; 2439 if (bConstant) 2440 { 2441 ScMatrixRef pNewX = pMatX->CloneIfConst(); 2442 ScMatrixRef pNewY = pMatY->CloneIfConst(); 2443 if (!pNewX || !pNewY) 2444 { 2445 PushError(errCodeOverflow); 2446 return; 2447 } 2448 pMatX = pNewX; 2449 pMatY = pNewY; 2450 // DeltaY is possible here; DeltaX depends on nCase, so later 2451 fMeanY = lcl_GetMeanOverAll(pMatY, N); 2452 for (SCSIZE i=0; i<N; i++) 2453 { 2454 pMatY->PutDouble( ::rtl::math::approxSub(pMatY->GetDouble(i),fMeanY), i ); 2455 } 2456 } 2457 2458 if (nCase==1) 2459 { 2460 // calculate simple regression 2461 double fMeanX = 0.0; 2462 if (bConstant) 2463 { // Mat = Mat - Mean 2464 fMeanX = lcl_GetMeanOverAll(pMatX, N); 2465 for (SCSIZE i=0; i<N; i++) 2466 { 2467 pMatX->PutDouble( ::rtl::math::approxSub(pMatX->GetDouble(i),fMeanX), i ); 2468 } 2469 } 2470 double fSumXY = lcl_GetSumProduct(pMatX,pMatY,N); 2471 double fSumX2 = lcl_GetSumProduct(pMatX,pMatX,N); 2472 if (fSumX2==0.0) 2473 { 2474 PushNoValue(); // all x-values are identical 2475 return; 2476 } 2477 double fSlope = fSumXY / fSumX2; 2478 double fIntercept = 0.0; 2479 if (bConstant) 2480 fIntercept = fMeanY - fSlope * fMeanX; 2481 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, 1, 0); //order (column,row) 2482 pResMat->PutDouble(_bRKP ? exp(fSlope) : fSlope, 0, 0); 2483 2484 if (bStats) 2485 { 2486 double fSSreg = fSlope * fSlope * fSumX2; 2487 pResMat->PutDouble(fSSreg, 0, 4); 2488 2489 double fDegreesFreedom =static_cast<double>( (bConstant) ? N-2 : N-1 ); 2490 pResMat->PutDouble(fDegreesFreedom, 1, 3); 2491 2492 double fSSresid = lcl_GetSSresid(pMatX,pMatY,fSlope,N); 2493 pResMat->PutDouble(fSSresid, 1, 4); 2494 2495 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0) 2496 { // exact fit; test SSreg too, because SSresid might be 2497 // unequal zero due to round of errors 2498 pResMat->PutDouble(0.0, 1, 4); // SSresid 2499 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), 0, 3); // F 2500 pResMat->PutDouble(0.0, 1, 2); // RMSE 2501 pResMat->PutDouble(0.0, 0, 1); // SigmaSlope 2502 if (bConstant) 2503 pResMat->PutDouble(0.0, 1, 1); //SigmaIntercept 2504 else 2505 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), 1, 1); 2506 pResMat->PutDouble(1.0, 0, 2); // R^2 2507 } 2508 else 2509 { 2510 double fFstatistic = (fSSreg / static_cast<double>(K)) 2511 / (fSSresid / fDegreesFreedom); 2512 pResMat->PutDouble(fFstatistic, 0, 3); 2513 2514 // standard error of estimate 2515 double fRMSE = sqrt(fSSresid / fDegreesFreedom); 2516 pResMat->PutDouble(fRMSE, 1, 2); 2517 2518 double fSigmaSlope = fRMSE / sqrt(fSumX2); 2519 pResMat->PutDouble(fSigmaSlope, 0, 1); 2520 2521 if (bConstant) 2522 { 2523 double fSigmaIntercept = fRMSE 2524 * sqrt(fMeanX*fMeanX/fSumX2 + 1.0/static_cast<double>(N)); 2525 pResMat->PutDouble(fSigmaIntercept, 1, 1); 2526 } 2527 else 2528 { 2529 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), 1, 1); 2530 } 2531 2532 double fR2 = fSSreg / (fSSreg + fSSresid); 2533 pResMat->PutDouble(fR2, 0, 2); 2534 } 2535 } 2536 PushMatrix(pResMat); 2537 } 2538 else // calculate multiple regression; 2539 { 2540 // Uses a QR decomposition X = QR. The solution B = (X'X)^(-1) * X' * Y 2541 // becomes B = R^(-1) * Q' * Y 2542 if (nCase ==2) // Y is column 2543 { 2544 ::std::vector< double> aVecR(N); // for QR decomposition 2545 // Enough memory for needed matrices? 2546 ScMatrixRef pMeans = GetNewMat(K, 1); // mean of each column 2547 ScMatrixRef pMatZ; // for Q' * Y , inter alia 2548 if (bStats) 2549 pMatZ = pMatY->Clone(); // Y is used in statistic, keep it 2550 else 2551 pMatZ = pMatY; // Y can be overwritten 2552 ScMatrixRef pSlopes = GetNewMat(1,K); // from b1 to bK 2553 if (!pMeans || !pMatZ || !pSlopes) 2554 { 2555 PushError(errCodeOverflow); 2556 return; 2557 } 2558 if (bConstant) 2559 { 2560 lcl_CalculateColumnMeans(pMatX, pMeans, K, N); 2561 lcl_CalculateColumnsDelta(pMatX, pMeans, K, N); 2562 } 2563 if (!lcl_CalculateQRdecomposition(pMatX, aVecR, K, N)) 2564 { 2565 PushNoValue(); 2566 return; 2567 } 2568 // Later on we will divide by elements of aVecR, so make sure 2569 // that they aren't zero. 2570 bool bIsSingular=false; 2571 for (SCSIZE row=0; row < K && !bIsSingular; row++) 2572 bIsSingular = bIsSingular || aVecR[row]==0.0; 2573 if (bIsSingular) 2574 { 2575 PushNoValue(); 2576 return; 2577 } 2578 // Z = Q' Y; 2579 for (SCSIZE col = 0; col < K; col++) 2580 { 2581 lcl_ApplyHouseholderTransformation(pMatX, col, pMatZ, N); 2582 } 2583 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z 2584 // result Z should have zeros for index>=K; if not, ignore values 2585 for (SCSIZE col = 0; col < K ; col++) 2586 { 2587 pSlopes->PutDouble( pMatZ->GetDouble(col), col); 2588 } 2589 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, false); 2590 double fIntercept = 0.0; 2591 if (bConstant) 2592 fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K); 2593 // Fill first line in result matrix 2594 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, K, 0 ); 2595 for (SCSIZE i = 0; i < K; i++) 2596 pResMat->PutDouble(_bRKP ? exp(pSlopes->GetDouble(i)) 2597 : pSlopes->GetDouble(i) , K-1-i, 0); 2598 2599 2600 if (bStats) 2601 { 2602 double fSSreg = 0.0; 2603 double fSSresid = 0.0; 2604 // re-use memory of Z; 2605 pMatZ->FillDouble(0.0, 0, 0, 0, N-1); 2606 // Z = R * Slopes 2607 lcl_ApplyUpperRightTriangle(pMatX, aVecR, pSlopes, pMatZ, K, false); 2608 // Z = Q * Z, that is Q * R * Slopes = X * Slopes 2609 for (SCSIZE colp1 = K; colp1 > 0; colp1--) 2610 { 2611 lcl_ApplyHouseholderTransformation(pMatX, colp1-1, pMatZ,N); 2612 } 2613 fSSreg =lcl_GetSumProduct(pMatZ, pMatZ, N); 2614 // re-use Y for residuals, Y = Y-Z 2615 for (SCSIZE row = 0; row < N; row++) 2616 pMatY->PutDouble(pMatY->GetDouble(row) - pMatZ->GetDouble(row), row); 2617 fSSresid = lcl_GetSumProduct(pMatY, pMatY, N); 2618 pResMat->PutDouble(fSSreg, 0, 4); 2619 pResMat->PutDouble(fSSresid, 1, 4); 2620 2621 double fDegreesFreedom =static_cast<double>( (bConstant) ? N-K-1 : N-K ); 2622 pResMat->PutDouble(fDegreesFreedom, 1, 3); 2623 2624 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0) 2625 { // exact fit; incl. observed values Y are identical 2626 pResMat->PutDouble(0.0, 1, 4); // SSresid 2627 // F = (SSreg/K) / (SSresid/df) = #DIV/0! 2628 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), 0, 3); // F 2629 // RMSE = sqrt(SSresid / df) = sqrt(0 / df) = 0 2630 pResMat->PutDouble(0.0, 1, 2); // RMSE 2631 // SigmaSlope[i] = RMSE * sqrt(matrix[i,i]) = 0 * sqrt(...) = 0 2632 for (SCSIZE i=0; i<K; i++) 2633 pResMat->PutDouble(0.0, K-1-i, 1); 2634 2635 // SigmaIntercept = RMSE * sqrt(...) = 0 2636 if (bConstant) 2637 pResMat->PutDouble(0.0, K, 1); //SigmaIntercept 2638 else 2639 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), K, 1); 2640 2641 // R^2 = SSreg / (SSreg + SSresid) = 1.0 2642 pResMat->PutDouble(1.0, 0, 2); // R^2 2643 } 2644 else 2645 { 2646 double fFstatistic = (fSSreg / static_cast<double>(K)) 2647 / (fSSresid / fDegreesFreedom); 2648 pResMat->PutDouble(fFstatistic, 0, 3); 2649 2650 // standard error of estimate = root mean SSE 2651 double fRMSE = sqrt(fSSresid / fDegreesFreedom); 2652 pResMat->PutDouble(fRMSE, 1, 2); 2653 2654 // standard error of slopes 2655 // = RMSE * sqrt(diagonal element of (R' R)^(-1) ) 2656 // standard error of intercept 2657 // = RMSE * sqrt( Xmean * (R' R)^(-1) * Xmean' + 1/N) 2658 // (R' R)^(-1) = R^(-1) * (R')^(-1). Do not calculate it as 2659 // a whole matrix, but iterate over unit vectors. 2660 double fSigmaSlope = 0.0; 2661 double fSigmaIntercept = 0.0; 2662 double fPart; // for Xmean * single column of (R' R)^(-1) 2663 for (SCSIZE col = 0; col < K; col++) 2664 { 2665 //re-use memory of MatZ 2666 pMatZ->FillDouble(0.0,0,0,0,K-1); // Z = unit vector e 2667 pMatZ->PutDouble(1.0, col); 2668 //Solve R' * Z = e 2669 lcl_SolveWithLowerLeftTriangle(pMatX, aVecR, pMatZ, K, false); 2670 // Solve R * Znew = Zold 2671 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pMatZ, K, false); 2672 // now Z is column col in (R' R)^(-1) 2673 fSigmaSlope = fRMSE * sqrt(pMatZ->GetDouble(col)); 2674 pResMat->PutDouble(fSigmaSlope, K-1-col, 1); 2675 // (R' R) ^(-1) is symmetric 2676 if (bConstant) 2677 { 2678 fPart = lcl_GetSumProduct(pMeans, pMatZ, K); 2679 fSigmaIntercept += fPart * pMeans->GetDouble(col); 2680 } 2681 } 2682 if (bConstant) 2683 { 2684 fSigmaIntercept = fRMSE 2685 * sqrt(fSigmaIntercept + 1.0 / static_cast<double>(N)); 2686 pResMat->PutDouble(fSigmaIntercept, K, 1); 2687 } 2688 else 2689 { 2690 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), K, 1); 2691 } 2692 2693 double fR2 = fSSreg / (fSSreg + fSSresid); 2694 pResMat->PutDouble(fR2, 0, 2); 2695 } 2696 } 2697 PushMatrix(pResMat); 2698 } 2699 else // nCase == 3, Y is row, all matrices are transposed 2700 { 2701 ::std::vector< double> aVecR(N); // for QR decomposition 2702 // Enough memory for needed matrices? 2703 ScMatrixRef pMeans = GetNewMat(1, K); // mean of each row 2704 ScMatrixRef pMatZ; // for Q' * Y , inter alia 2705 if (bStats) 2706 pMatZ = pMatY->Clone(); // Y is used in statistic, keep it 2707 else 2708 pMatZ = pMatY; // Y can be overwritten 2709 ScMatrixRef pSlopes = GetNewMat(K,1); // from b1 to bK 2710 if (!pMeans || !pMatZ || !pSlopes) 2711 { 2712 PushError(errCodeOverflow); 2713 return; 2714 } 2715 if (bConstant) 2716 { 2717 lcl_CalculateRowMeans(pMatX, pMeans, N, K); 2718 lcl_CalculateRowsDelta(pMatX, pMeans, N, K); 2719 } 2720 2721 if (!lcl_TCalculateQRdecomposition(pMatX, aVecR, K, N)) 2722 { 2723 PushNoValue(); 2724 return; 2725 } 2726 2727 // Later on we will divide by elements of aVecR, so make sure 2728 // that they aren't zero. 2729 bool bIsSingular=false; 2730 for (SCSIZE row=0; row < K && !bIsSingular; row++) 2731 bIsSingular = bIsSingular || aVecR[row]==0.0; 2732 if (bIsSingular) 2733 { 2734 PushNoValue(); 2735 return; 2736 } 2737 // Z = Q' Y 2738 for (SCSIZE row = 0; row < K; row++) 2739 { 2740 lcl_TApplyHouseholderTransformation(pMatX, row, pMatZ, N); 2741 } 2742 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z 2743 // result Z should have zeros for index>=K; if not, ignore values 2744 for (SCSIZE col = 0; col < K ; col++) 2745 { 2746 pSlopes->PutDouble( pMatZ->GetDouble(col), col); 2747 } 2748 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, true); 2749 double fIntercept = 0.0; 2750 if (bConstant) 2751 fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K); 2752 // Fill first line in result matrix 2753 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, K, 0 ); 2754 for (SCSIZE i = 0; i < K; i++) 2755 pResMat->PutDouble(_bRKP ? exp(pSlopes->GetDouble(i)) 2756 : pSlopes->GetDouble(i) , K-1-i, 0); 2757 2758 2759 if (bStats) 2760 { 2761 double fSSreg = 0.0; 2762 double fSSresid = 0.0; 2763 // re-use memory of Z; 2764 pMatZ->FillDouble(0.0, 0, 0, N-1, 0); 2765 // Z = R * Slopes 2766 lcl_ApplyUpperRightTriangle(pMatX, aVecR, pSlopes, pMatZ, K, true); 2767 // Z = Q * Z, that is Q * R * Slopes = X * Slopes 2768 for (SCSIZE rowp1 = K; rowp1 > 0; rowp1--) 2769 { 2770 lcl_TApplyHouseholderTransformation(pMatX, rowp1-1, pMatZ,N); 2771 } 2772 fSSreg =lcl_GetSumProduct(pMatZ, pMatZ, N); 2773 // re-use Y for residuals, Y = Y-Z 2774 for (SCSIZE col = 0; col < N; col++) 2775 pMatY->PutDouble(pMatY->GetDouble(col) - pMatZ->GetDouble(col), col); 2776 fSSresid = lcl_GetSumProduct(pMatY, pMatY, N); 2777 pResMat->PutDouble(fSSreg, 0, 4); 2778 pResMat->PutDouble(fSSresid, 1, 4); 2779 2780 double fDegreesFreedom =static_cast<double>( (bConstant) ? N-K-1 : N-K ); 2781 pResMat->PutDouble(fDegreesFreedom, 1, 3); 2782 2783 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0) 2784 { // exact fit; incl. case observed values Y are identical 2785 pResMat->PutDouble(0.0, 1, 4); // SSresid 2786 // F = (SSreg/K) / (SSresid/df) = #DIV/0! 2787 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), 0, 3); // F 2788 // RMSE = sqrt(SSresid / df) = sqrt(0 / df) = 0 2789 pResMat->PutDouble(0.0, 1, 2); // RMSE 2790 // SigmaSlope[i] = RMSE * sqrt(matrix[i,i]) = 0 * sqrt(...) = 0 2791 for (SCSIZE i=0; i<K; i++) 2792 pResMat->PutDouble(0.0, K-1-i, 1); 2793 2794 // SigmaIntercept = RMSE * sqrt(...) = 0 2795 if (bConstant) 2796 pResMat->PutDouble(0.0, K, 1); //SigmaIntercept 2797 else 2798 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), K, 1); 2799 2800 // R^2 = SSreg / (SSreg + SSresid) = 1.0 2801 pResMat->PutDouble(1.0, 0, 2); // R^2 2802 } 2803 else 2804 { 2805 double fFstatistic = (fSSreg / static_cast<double>(K)) 2806 / (fSSresid / fDegreesFreedom); 2807 pResMat->PutDouble(fFstatistic, 0, 3); 2808 2809 // standard error of estimate = root mean SSE 2810 double fRMSE = sqrt(fSSresid / fDegreesFreedom); 2811 pResMat->PutDouble(fRMSE, 1, 2); 2812 2813 // standard error of slopes 2814 // = RMSE * sqrt(diagonal element of (R' R)^(-1) ) 2815 // standard error of intercept 2816 // = RMSE * sqrt( Xmean * (R' R)^(-1) * Xmean' + 1/N) 2817 // (R' R)^(-1) = R^(-1) * (R')^(-1). Do not calculate it as 2818 // a whole matrix, but iterate over unit vectors. 2819 // (R' R) ^(-1) is symmetric 2820 double fSigmaSlope = 0.0; 2821 double fSigmaIntercept = 0.0; 2822 double fPart; // for Xmean * single col of (R' R)^(-1) 2823 for (SCSIZE row = 0; row < K; row++) 2824 { 2825 //re-use memory of MatZ 2826 pMatZ->FillDouble(0.0,0,0,K-1,0); // Z = unit vector e 2827 pMatZ->PutDouble(1.0, row); 2828 //Solve R' * Z = e 2829 lcl_SolveWithLowerLeftTriangle(pMatX, aVecR, pMatZ, K, true); 2830 // Solve R * Znew = Zold 2831 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pMatZ, K, true); 2832 // now Z is column col in (R' R)^(-1) 2833 fSigmaSlope = fRMSE * sqrt(pMatZ->GetDouble(row)); 2834 pResMat->PutDouble(fSigmaSlope, K-1-row, 1); 2835 if (bConstant) 2836 { 2837 fPart = lcl_GetSumProduct(pMeans, pMatZ, K); 2838 fSigmaIntercept += fPart * pMeans->GetDouble(row); 2839 } 2840 } 2841 if (bConstant) 2842 { 2843 fSigmaIntercept = fRMSE 2844 * sqrt(fSigmaIntercept + 1.0 / static_cast<double>(N)); 2845 pResMat->PutDouble(fSigmaIntercept, K, 1); 2846 } 2847 else 2848 { 2849 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), K, 1); 2850 } 2851 2852 double fR2 = fSSreg / (fSSreg + fSSresid); 2853 pResMat->PutDouble(fR2, 0, 2); 2854 } 2855 } 2856 PushMatrix(pResMat); 2857 } 2858 } 2859 return; 2860 } 2861 2862 void ScInterpreter::ScTrend() 2863 { 2864 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTrend" ); 2865 CalculateTrendGrowth(false); 2866 } 2867 2868 void ScInterpreter::ScGrowth() 2869 { 2870 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGrowth" ); 2871 CalculateTrendGrowth(true); 2872 } 2873 2874 void ScInterpreter::CalculateTrendGrowth(bool _bGrowth) 2875 { 2876 sal_uInt8 nParamCount = GetByte(); 2877 if ( !MustHaveParamCount( nParamCount, 1, 4 ) ) 2878 return; 2879 2880 // optional fourth parameter 2881 bool bConstant; 2882 if (nParamCount == 4) 2883 bConstant = GetBool(); 2884 else 2885 bConstant = true; 2886 2887 // The third parameter may be missing in ODF, although the fourth parameter 2888 // is present. Default values depend on data not yet read. 2889 ScMatrixRef pMatNewX; 2890 if (nParamCount >= 3) 2891 { 2892 if (IsMissing()) 2893 { 2894 Pop(); 2895 pMatNewX = NULL; 2896 } 2897 else 2898 pMatNewX = GetMatrix(); 2899 } 2900 else 2901 pMatNewX = NULL; 2902 2903 // In ODF1.2 empty second parameter (which is two ;; ) is allowed. 2904 // Defaults will be set in CheckMatrix. 2905 ScMatrixRef pMatX; 2906 if (nParamCount >= 2) 2907 { 2908 if (IsMissing()) 2909 { 2910 Pop(); 2911 pMatX = NULL; 2912 } 2913 else 2914 { 2915 pMatX = GetMatrix(); 2916 } 2917 } 2918 else 2919 pMatX = NULL; 2920 2921 ScMatrixRef pMatY; 2922 pMatY = GetMatrix(); 2923 if (!pMatY) 2924 { 2925 PushIllegalParameter(); 2926 return; 2927 } 2928 2929 // 1 = simple; 2 = multiple with Y as column; 3 = multiple with Y as row 2930 sal_uInt8 nCase; 2931 2932 SCSIZE nCX, nCY; // number of columns 2933 SCSIZE nRX, nRY; // number of rows 2934 SCSIZE K = 0, N = 0; // K=number of variables X, N=number of data samples 2935 if ( !CheckMatrix(_bGrowth,nCase,nCX,nCY,nRX,nRY,K,N,pMatX,pMatY) ) 2936 { 2937 PushIllegalParameter(); 2938 return; 2939 } 2940 2941 // Enough data samples? 2942 if ( (bConstant && (N<K+1)) || (!bConstant && (N<K)) || (N<1) || (K<1) ) 2943 { 2944 PushIllegalParameter(); 2945 return; 2946 } 2947 2948 // Set default pMatNewX if necessary 2949 SCSIZE nCXN, nRXN; 2950 SCSIZE nCountXN; 2951 if (!pMatNewX) 2952 { 2953 nCXN = nCX; 2954 nRXN = nRX; 2955 nCountXN = nCXN * nRXN; 2956 pMatNewX = pMatX->Clone(); // pMatX will be changed to X-meanX 2957 } 2958 else 2959 { 2960 pMatNewX->GetDimensions(nCXN, nRXN); 2961 if ((nCase == 2 && K != nCXN) || (nCase == 3 && K != nRXN)) 2962 { 2963 PushIllegalArgument(); 2964 return; 2965 } 2966 nCountXN = nCXN * nRXN; 2967 for ( SCSIZE i = 0; i < nCountXN; i++ ) 2968 if (!pMatNewX->IsValue(i)) 2969 { 2970 PushIllegalArgument(); 2971 return; 2972 } 2973 } 2974 ScMatrixRef pResMat; // size depends on nCase 2975 if (nCase == 1) 2976 pResMat = GetNewMat(nCXN,nRXN); 2977 else 2978 { 2979 if (nCase==2) 2980 pResMat = GetNewMat(1,nRXN); 2981 else 2982 pResMat = GetNewMat(nCXN,1); 2983 } 2984 if (!pResMat) 2985 { 2986 PushError(errCodeOverflow); 2987 return; 2988 } 2989 // Uses sum(x-MeanX)^2 and not [sum x^2]-N * MeanX^2 in case bConstant. 2990 // Clone constant matrices, so that Mat = Mat - Mean is possible. 2991 double fMeanY = 0.0; 2992 if (bConstant) 2993 { 2994 ScMatrixRef pCopyX = pMatX->CloneIfConst(); 2995 ScMatrixRef pCopyY = pMatY->CloneIfConst(); 2996 if (!pCopyX || !pCopyY) 2997 { 2998 PushError(errStackOverflow); 2999 return; 3000 } 3001 pMatX = pCopyX; 3002 pMatY = pCopyY; 3003 // DeltaY is possible here; DeltaX depends on nCase, so later 3004 fMeanY = lcl_GetMeanOverAll(pMatY, N); 3005 for (SCSIZE i=0; i<N; i++) 3006 { 3007 pMatY->PutDouble( ::rtl::math::approxSub(pMatY->GetDouble(i),fMeanY), i ); 3008 } 3009 } 3010 3011 if (nCase==1) 3012 { 3013 // calculate simple regression 3014 double fMeanX = 0.0; 3015 if (bConstant) 3016 { // Mat = Mat - Mean 3017 fMeanX = lcl_GetMeanOverAll(pMatX, N); 3018 for (SCSIZE i=0; i<N; i++) 3019 { 3020 pMatX->PutDouble( ::rtl::math::approxSub(pMatX->GetDouble(i),fMeanX), i ); 3021 } 3022 } 3023 double fSumXY = lcl_GetSumProduct(pMatX,pMatY,N); 3024 double fSumX2 = lcl_GetSumProduct(pMatX,pMatX,N); 3025 if (fSumX2==0.0) 3026 { 3027 PushNoValue(); // all x-values are identical 3028 return; 3029 } 3030 double fSlope = fSumXY / fSumX2; 3031 double fIntercept = 0.0; 3032 double fHelp; 3033 if (bConstant) 3034 { 3035 fIntercept = fMeanY - fSlope * fMeanX; 3036 for (SCSIZE i = 0; i < nCountXN; i++) 3037 { 3038 fHelp = pMatNewX->GetDouble(i)*fSlope + fIntercept; 3039 pResMat->PutDouble(_bGrowth ? exp(fHelp) : fHelp, i); 3040 } 3041 } 3042 else 3043 { 3044 for (SCSIZE i = 0; i < nCountXN; i++) 3045 { 3046 fHelp = pMatNewX->GetDouble(i)*fSlope; 3047 pResMat->PutDouble(_bGrowth ? exp(fHelp) : fHelp, i); 3048 } 3049 } 3050 } 3051 else // calculate multiple regression; 3052 { 3053 if (nCase ==2) // Y is column 3054 { 3055 ::std::vector< double> aVecR(N); // for QR decomposition 3056 // Enough memory for needed matrices? 3057 ScMatrixRef pMeans = GetNewMat(K, 1); // mean of each column 3058 ScMatrixRef pSlopes = GetNewMat(1,K); // from b1 to bK 3059 if (!pMeans || !pSlopes) 3060 { 3061 PushError(errCodeOverflow); 3062 return; 3063 } 3064 if (bConstant) 3065 { 3066 lcl_CalculateColumnMeans(pMatX, pMeans, K, N); 3067 lcl_CalculateColumnsDelta(pMatX, pMeans, K, N); 3068 } 3069 if (!lcl_CalculateQRdecomposition(pMatX, aVecR, K, N)) 3070 { 3071 PushNoValue(); 3072 return; 3073 } 3074 // Later on we will divide by elements of aVecR, so make sure 3075 // that they aren't zero. 3076 bool bIsSingular=false; 3077 for (SCSIZE row=0; row < K && !bIsSingular; row++) 3078 bIsSingular = bIsSingular || aVecR[row]==0.0; 3079 if (bIsSingular) 3080 { 3081 PushNoValue(); 3082 return; 3083 } 3084 // Z := Q' Y; Y is overwritten with result Z 3085 for (SCSIZE col = 0; col < K; col++) 3086 { 3087 lcl_ApplyHouseholderTransformation(pMatX, col, pMatY, N); 3088 } 3089 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z 3090 // result Z should have zeros for index>=K; if not, ignore values 3091 for (SCSIZE col = 0; col < K ; col++) 3092 { 3093 pSlopes->PutDouble( pMatY->GetDouble(col), col); 3094 } 3095 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, false); 3096 3097 // Fill result matrix 3098 lcl_MFastMult(pMatNewX,pSlopes,pResMat,nRXN,K,1); 3099 if (bConstant) 3100 { 3101 double fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K); 3102 for (SCSIZE row = 0; row < nRXN; row++) 3103 pResMat->PutDouble(pResMat->GetDouble(row)+fIntercept, row); 3104 } 3105 if (_bGrowth) 3106 { 3107 for (SCSIZE i = 0; i < nRXN; i++) 3108 pResMat->PutDouble(exp(pResMat->GetDouble(i)), i); 3109 } 3110 } 3111 else 3112 { // nCase == 3, Y is row, all matrices are transposed 3113 3114 ::std::vector< double> aVecR(N); // for QR decomposition 3115 // Enough memory for needed matrices? 3116 ScMatrixRef pMeans = GetNewMat(1, K); // mean of each row 3117 ScMatrixRef pSlopes = GetNewMat(K,1); // row from b1 to bK 3118 if (!pMeans || !pSlopes) 3119 { 3120 PushError(errCodeOverflow); 3121 return; 3122 } 3123 if (bConstant) 3124 { 3125 lcl_CalculateRowMeans(pMatX, pMeans, N, K); 3126 lcl_CalculateRowsDelta(pMatX, pMeans, N, K); 3127 } 3128 if (!lcl_TCalculateQRdecomposition(pMatX, aVecR, K, N)) 3129 { 3130 PushNoValue(); 3131 return; 3132 } 3133 // Later on we will divide by elements of aVecR, so make sure 3134 // that they aren't zero. 3135 bool bIsSingular=false; 3136 for (SCSIZE row=0; row < K && !bIsSingular; row++) 3137 bIsSingular = bIsSingular || aVecR[row]==0.0; 3138 if (bIsSingular) 3139 { 3140 PushNoValue(); 3141 return; 3142 } 3143 // Z := Q' Y; Y is overwritten with result Z 3144 for (SCSIZE row = 0; row < K; row++) 3145 { 3146 lcl_TApplyHouseholderTransformation(pMatX, row, pMatY, N); 3147 } 3148 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z 3149 // result Z should have zeros for index>=K; if not, ignore values 3150 for (SCSIZE col = 0; col < K ; col++) 3151 { 3152 pSlopes->PutDouble( pMatY->GetDouble(col), col); 3153 } 3154 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, true); 3155 3156 // Fill result matrix 3157 lcl_MFastMult(pSlopes,pMatNewX,pResMat,1,K,nCXN); 3158 if (bConstant) 3159 { 3160 double fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K); 3161 for (SCSIZE col = 0; col < nCXN; col++) 3162 pResMat->PutDouble(pResMat->GetDouble(col)+fIntercept, col); 3163 } 3164 if (_bGrowth) 3165 { 3166 for (SCSIZE i = 0; i < nCXN; i++) 3167 pResMat->PutDouble(exp(pResMat->GetDouble(i)), i); 3168 } 3169 } 3170 } 3171 PushMatrix(pResMat); 3172 return; 3173 } 3174 3175 void ScInterpreter::ScMatRef() 3176 { 3177 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatRef" ); 3178 // Falls Deltarefs drin sind... 3179 Push( (FormulaToken&)*pCur ); 3180 ScAddress aAdr; 3181 PopSingleRef( aAdr ); 3182 ScFormulaCell* pCell = (ScFormulaCell*) GetCell( aAdr ); 3183 if( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) 3184 { 3185 const ScMatrix* pMat = pCell->GetMatrix(); 3186 if( pMat ) 3187 { 3188 SCSIZE nCols, nRows; 3189 pMat->GetDimensions( nCols, nRows ); 3190 SCSIZE nC = static_cast<SCSIZE>(aPos.Col() - aAdr.Col()); 3191 SCSIZE nR = static_cast<SCSIZE>(aPos.Row() - aAdr.Row()); 3192 if ((nCols <= nC && nCols != 1) || (nRows <= nR && nRows != 1)) 3193 PushNA(); 3194 else 3195 { 3196 ScMatValType nMatValType; 3197 const ScMatrixValue* pMatVal = pMat->Get( nC, nR, nMatValType); 3198 if (ScMatrix::IsNonValueType( nMatValType)) 3199 { 3200 if (ScMatrix::IsEmptyPathType( nMatValType)) 3201 { // result of empty sal_False jump path 3202 nFuncFmtType = NUMBERFORMAT_LOGICAL; 3203 PushInt(0); 3204 } 3205 else if (ScMatrix::IsEmptyType( nMatValType)) 3206 { 3207 // Not inherited (really?) and display as empty string, not 0. 3208 PushTempToken( new ScEmptyCellToken( false, true)); 3209 } 3210 else 3211 PushString( pMatVal->GetString() ); 3212 } 3213 else 3214 { 3215 PushDouble(pMatVal->fVal); // handles DoubleError 3216 pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex, aAdr, pCell ); 3217 nFuncFmtType = nCurFmtType; 3218 nFuncFmtIndex = nCurFmtIndex; 3219 } 3220 } 3221 } 3222 else 3223 { 3224 // If not a result matrix, obtain the cell value. 3225 sal_uInt16 nErr = pCell->GetErrCode(); 3226 if (nErr) 3227 PushError( nErr ); 3228 else if( pCell->IsValue() ) 3229 PushDouble( pCell->GetValue() ); 3230 else 3231 { 3232 String aVal; 3233 pCell->GetString( aVal ); 3234 PushString( aVal ); 3235 } 3236 pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex, aAdr, pCell ); 3237 nFuncFmtType = nCurFmtType; 3238 nFuncFmtIndex = nCurFmtIndex; 3239 } 3240 } 3241 else 3242 PushError( errNoRef ); 3243 } 3244 3245 void ScInterpreter::ScInfo() 3246 { 3247 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInfo" ); 3248 if( MustHaveParamCount( GetByte(), 1 ) ) 3249 { 3250 String aStr = GetString(); 3251 ScCellKeywordTranslator::transKeyword(aStr, ScGlobal::GetLocale(), ocInfo); 3252 if( aStr.EqualsAscii( "SYSTEM" ) ) 3253 PushString( String( RTL_CONSTASCII_USTRINGPARAM( SC_INFO_OSVERSION ) ) ); 3254 else if( aStr.EqualsAscii( "OSVERSION" ) ) 3255 PushString( String( RTL_CONSTASCII_USTRINGPARAM( "Windows (32-bit) NT 5.01" ) ) ); 3256 else if( aStr.EqualsAscii( "RELEASE" ) ) 3257 PushString( ::utl::Bootstrap::getBuildIdData( ::rtl::OUString() ) ); 3258 else if( aStr.EqualsAscii( "NUMFILE" ) ) 3259 PushDouble( 1 ); 3260 else if( aStr.EqualsAscii( "RECALC" ) ) 3261 PushString( ScGlobal::GetRscString( pDok->GetAutoCalc() ? STR_RECALC_AUTO : STR_RECALC_MANUAL ) ); 3262 else 3263 PushIllegalArgument(); 3264 } 3265 } 3266