Update ooo320-m1
[ooovba.git] / sc / source / core / tool / interpr5.cxx
blobe7f0511ca4647cc6f4eef1ef801a5ed12fb1ac2c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: interpr5.cxx,v $
10 * $Revision: 1.33.36.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #ifndef INCLUDED_RTL_MATH_HXX
37 #include <rtl/math.hxx>
38 #endif
39 #include <rtl/logfile.hxx>
40 #include <string.h>
41 #include <math.h>
42 #include <stdio.h>
44 #if OSL_DEBUG_LEVEL > 1
45 #include <stdio.h>
46 #endif
47 #include <unotools/bootstrap.hxx>
48 #include <svtools/zforlist.hxx>
50 #include "interpre.hxx"
51 #include "global.hxx"
52 #include "compiler.hxx"
53 #include "cell.hxx"
54 #include "document.hxx"
55 #include "dociter.hxx"
56 #include "scmatrix.hxx"
57 #include "globstr.hrc"
58 #include "cellkeytranslator.hxx"
59 #include "osversiondef.hxx"
61 #include <string.h>
62 #include <math.h>
63 #include <vector>
65 using ::std::vector;
66 using namespace formula;
68 const double fInvEpsilon = 1.0E-7;
70 // -----------------------------------------------------------------------
71 struct MatrixAdd : public ::std::binary_function<double,double,double>
73 inline double operator() (const double& lhs, const double& rhs) const
75 return ::rtl::math::approxAdd( lhs,rhs);
78 struct MatrixSub : public ::std::binary_function<double,double,double>
80 inline double operator() (const double& lhs, const double& rhs) const
82 return ::rtl::math::approxSub( lhs,rhs);
85 struct MatrixMul : public ::std::binary_function<double,double,double>
87 inline double operator() (const double& lhs, const double& rhs) const
89 return lhs * rhs;
92 struct MatrixDiv : public ::std::binary_function<double,double,double>
94 inline double operator() (const double& lhs, const double& rhs) const
96 return ScInterpreter::div( lhs,rhs);
99 struct MatrixPow : public ::std::binary_function<double,double,double>
101 inline double operator() (const double& lhs, const double& rhs) const
103 return ::pow( lhs,rhs);
107 double ScInterpreter::ScGetGCD(double fx, double fy)
109 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::div" );
110 // By ODFF definition GCD(0,a) => a. This is also vital for the code in
111 // ScGCD() to work correctly with a preset fy=0.0
112 if (fy == 0.0)
113 return fx;
114 else if (fx == 0.0)
115 return fy;
116 else
118 double fz = fmod(fx, fy);
119 while (fz > 0.0)
121 fx = fy;
122 fy = fz;
123 fz = fmod(fx, fy);
125 return fy;
129 void ScInterpreter::ScGCD()
131 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGCD" );
132 short nParamCount = GetByte();
133 if ( MustHaveParamCountMin( nParamCount, 1 ) )
135 double fx, fy = 0.0;
136 ScRange aRange;
137 size_t nRefInList = 0;
138 while (!nGlobalError && nParamCount-- > 0)
140 switch (GetStackType())
142 case svDouble :
143 case svString:
144 case svSingleRef:
146 fx = ::rtl::math::approxFloor( GetDouble());
147 if (fx < 0.0)
149 PushIllegalArgument();
150 return;
152 fy = ScGetGCD(fx, fy);
154 break;
155 case svDoubleRef :
156 case svRefList :
158 USHORT nErr = 0;
159 PopDoubleRef( aRange, nParamCount, nRefInList);
160 double nCellVal;
161 ScValueIterator aValIter(pDok, aRange, glSubTotal);
162 if (aValIter.GetFirst(nCellVal, nErr))
166 fx = ::rtl::math::approxFloor( nCellVal);
167 if (fx < 0.0)
169 PushIllegalArgument();
170 return;
172 fy = ScGetGCD(fx, fy);
173 } while (nErr == 0 && aValIter.GetNext(nCellVal, nErr));
175 SetError(nErr);
177 break;
178 case svMatrix :
180 ScMatrixRef pMat = PopMatrix();
181 if (pMat)
183 SCSIZE nC, nR;
184 pMat->GetDimensions(nC, nR);
185 if (nC == 0 || nR == 0)
186 SetError(errIllegalArgument);
187 else
189 SCSIZE nCount = nC * nR;
190 for ( SCSIZE j = 0; j < nCount; j++ )
192 if (!pMat->IsValue(j))
194 PushIllegalArgument();
195 return;
197 fx = ::rtl::math::approxFloor( pMat->GetDouble(j));
198 if (fx < 0.0)
200 PushIllegalArgument();
201 return;
203 fy = ScGetGCD(fx, fy);
208 break;
209 default : SetError(errIllegalParameter); break;
212 PushDouble(fy);
216 void ScInterpreter:: ScLCM()
218 short nParamCount = GetByte();
219 if ( MustHaveParamCountMin( nParamCount, 1 ) )
221 double fx, fy = 1.0;
222 ScRange aRange;
223 size_t nRefInList = 0;
224 while (!nGlobalError && nParamCount-- > 0)
226 switch (GetStackType())
228 case svDouble :
229 case svString:
230 case svSingleRef:
232 fx = ::rtl::math::approxFloor( GetDouble());
233 if (fx < 0.0)
235 PushIllegalArgument();
236 return;
238 if (fx == 0.0 || fy == 0.0)
239 fy = 0.0;
240 else
241 fy = fx * fy / ScGetGCD(fx, fy);
243 break;
244 case svDoubleRef :
245 case svRefList :
247 USHORT nErr = 0;
248 PopDoubleRef( aRange, nParamCount, nRefInList);
249 double nCellVal;
250 ScValueIterator aValIter(pDok, aRange, glSubTotal);
251 if (aValIter.GetFirst(nCellVal, nErr))
255 fx = ::rtl::math::approxFloor( nCellVal);
256 if (fx < 0.0)
258 PushIllegalArgument();
259 return;
261 if (fx == 0.0 || fy == 0.0)
262 fy = 0.0;
263 else
264 fy = fx * fy / ScGetGCD(fx, fy);
265 } while (nErr == 0 && aValIter.GetNext(nCellVal, nErr));
267 SetError(nErr);
269 break;
270 case svMatrix :
272 ScMatrixRef pMat = PopMatrix();
273 if (pMat)
275 SCSIZE nC, nR;
276 pMat->GetDimensions(nC, nR);
277 if (nC == 0 || nR == 0)
278 SetError(errIllegalArgument);
279 else
281 SCSIZE nCount = nC * nR;
282 for ( SCSIZE j = 0; j < nCount; j++ )
284 if (!pMat->IsValue(j))
286 PushIllegalArgument();
287 return;
289 fx = ::rtl::math::approxFloor( pMat->GetDouble(j));
290 if (fx < 0.0)
292 PushIllegalArgument();
293 return;
295 if (fx == 0.0 || fy == 0.0)
296 fy = 0.0;
297 else
298 fy = fx * fy / ScGetGCD(fx, fy);
303 break;
304 default : SetError(errIllegalParameter); break;
307 PushDouble(fy);
311 ScMatrixRef ScInterpreter::GetNewMat(SCSIZE nC, SCSIZE nR)
313 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetNewMat" );
314 ScMatrix* pMat = new ScMatrix( nC, nR);
315 pMat->SetErrorInterpreter( this);
316 SCSIZE nCols, nRows;
317 pMat->GetDimensions( nCols, nRows);
318 if ( nCols != nC || nRows != nR )
319 { // arbitray limit of elements exceeded
320 SetError( errStackOverflow);
321 pMat->Delete();
322 pMat = NULL;
324 return pMat;
327 ScInterpreter::VolatileType ScInterpreter::GetVolatileType() const
329 return meVolaileType;
332 ScMatrixRef ScInterpreter::CreateMatrixFromDoubleRef( const FormulaToken* pToken,
333 SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
334 SCCOL nCol2, SCROW nRow2, SCTAB nTab2 )
336 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CreateMatrixFromDoubleRef" );
337 ScMatrixRef pMat = NULL;
338 if (nTab1 == nTab2 && !nGlobalError)
340 ScTokenMatrixMap::const_iterator aIter;
341 if ( static_cast<SCSIZE>(nRow2 - nRow1 + 1) *
342 static_cast<SCSIZE>(nCol2 - nCol1 + 1) >
343 ScMatrix::GetElementsMax() )
344 SetError(errStackOverflow);
345 else if (pTokenMatrixMap && ((aIter = pTokenMatrixMap->find( pToken))
346 != pTokenMatrixMap->end()))
347 pMat = static_cast<ScToken*>((*aIter).second.get())->GetMatrix();
348 else
350 SCSIZE nMatCols = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
351 SCSIZE nMatRows = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
352 pMat = GetNewMat( nMatCols, nMatRows);
353 if (pMat && !nGlobalError)
355 // Set position where the next entry is expected.
356 SCROW nNextRow = nRow1;
357 SCCOL nNextCol = nCol1;
358 // Set last position as if there was a previous entry.
359 SCROW nThisRow = nRow2;
360 SCCOL nThisCol = nCol1 - 1;
361 ScCellIterator aCellIter( pDok, nCol1, nRow1, nTab1, nCol2,
362 nRow2, nTab2);
363 for (ScBaseCell* pCell = aCellIter.GetFirst(); pCell; pCell =
364 aCellIter.GetNext())
366 nThisCol = aCellIter.GetCol();
367 nThisRow = aCellIter.GetRow();
368 if (nThisCol != nNextCol || nThisRow != nNextRow)
370 // Fill empty between iterator's positions.
371 for ( ; nNextCol <= nThisCol; ++nNextCol)
373 SCSIZE nC = nNextCol - nCol1;
374 SCSIZE nMatStopRow = ((nNextCol < nThisCol) ?
375 nMatRows : nThisRow - nRow1);
376 for (SCSIZE nR = nNextRow - nRow1; nR <
377 nMatStopRow; ++nR)
379 pMat->PutEmpty( nC, nR);
381 nNextRow = nRow1;
384 if (nThisRow == nRow2)
386 nNextCol = nThisCol + 1;
387 nNextRow = nRow1;
389 else
391 nNextCol = nThisCol;
392 nNextRow = nThisRow + 1;
394 if (HasCellEmptyData(pCell))
396 pMat->PutEmpty( static_cast<SCSIZE>(nThisCol-nCol1),
397 static_cast<SCSIZE>(nThisRow-nRow1));
399 else if (HasCellValueData(pCell))
401 ScAddress aAdr( nThisCol, nThisRow, nTab1);
402 double fVal = GetCellValue( aAdr, pCell);
403 if ( nGlobalError )
405 fVal = CreateDoubleError( nGlobalError);
406 nGlobalError = 0;
408 pMat->PutDouble( fVal,
409 static_cast<SCSIZE>(nThisCol-nCol1),
410 static_cast<SCSIZE>(nThisRow-nRow1));
412 else
414 String aStr;
415 GetCellString( aStr, pCell);
416 if ( nGlobalError )
418 double fVal = CreateDoubleError( nGlobalError);
419 nGlobalError = 0;
420 pMat->PutDouble( fVal,
421 static_cast<SCSIZE>(nThisCol-nCol1),
422 static_cast<SCSIZE>(nThisRow-nRow1));
424 else
425 pMat->PutString( aStr,
426 static_cast<SCSIZE>(nThisCol-nCol1),
427 static_cast<SCSIZE>(nThisRow-nRow1));
430 // Fill empty if iterator's last position wasn't the end.
431 if (nThisCol != nCol2 || nThisRow != nRow2)
433 for ( ; nNextCol <= nCol2; ++nNextCol)
435 SCSIZE nC = nNextCol - nCol1;
436 for (SCSIZE nR = nNextRow - nRow1; nR < nMatRows; ++nR)
438 pMat->PutEmpty( nC, nR);
440 nNextRow = nRow1;
443 if (pTokenMatrixMap)
444 pTokenMatrixMap->insert( ScTokenMatrixMap::value_type(
445 pToken, new ScMatrixToken( pMat)));
449 else // not a 2D matrix
450 SetError(errIllegalParameter);
451 return pMat;
455 ScMatrixRef ScInterpreter::GetMatrix()
457 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetMatrix" );
458 ScMatrixRef pMat = NULL;
459 switch (GetRawStackType())
461 case svSingleRef :
463 ScAddress aAdr;
464 PopSingleRef( aAdr );
465 pMat = GetNewMat(1, 1);
466 if (pMat)
468 ScBaseCell* pCell = GetCell( aAdr );
469 if (HasCellEmptyData(pCell))
470 pMat->PutEmpty( 0 );
471 else if (HasCellValueData(pCell))
472 pMat->PutDouble(GetCellValue(aAdr, pCell), 0);
473 else
475 String aStr;
476 GetCellString(aStr, pCell);
477 pMat->PutString(aStr, 0);
481 break;
482 case svDoubleRef:
484 SCCOL nCol1, nCol2;
485 SCROW nRow1, nRow2;
486 SCTAB nTab1, nTab2;
487 const ScToken* p = sp ? static_cast<const ScToken*>(pStack[sp-1]) : NULL;
488 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
489 pMat = CreateMatrixFromDoubleRef( p, nCol1, nRow1, nTab1,
490 nCol2, nRow2, nTab2);
492 break;
493 case svMatrix:
494 pMat = PopMatrix();
495 break;
496 case svError :
497 case svMissing :
498 case svDouble :
500 double fVal = GetDouble();
501 pMat = GetNewMat( 1, 1);
502 if ( pMat )
504 if ( nGlobalError )
506 fVal = CreateDoubleError( nGlobalError);
507 nGlobalError = 0;
509 pMat->PutDouble( fVal, 0);
512 break;
513 case svString :
515 String aStr = GetString();
516 pMat = GetNewMat( 1, 1);
517 if ( pMat )
519 if ( nGlobalError )
521 double fVal = CreateDoubleError( nGlobalError);
522 pMat->PutDouble( fVal, 0);
523 nGlobalError = 0;
525 else
526 pMat->PutString( aStr, 0);
529 break;
530 default:
531 PopError();
532 SetError( errIllegalArgument);
533 break;
535 return pMat;
538 void ScInterpreter::ScMatValue()
540 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatValue" );
541 if ( MustHaveParamCount( GetByte(), 3 ) )
543 // 0 to count-1
544 SCSIZE nR = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble()));
545 SCSIZE nC = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble()));
546 switch (GetStackType())
548 case svSingleRef :
550 ScAddress aAdr;
551 PopSingleRef( aAdr );
552 ScBaseCell* pCell = GetCell( aAdr );
553 if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
555 USHORT nErrCode = ((ScFormulaCell*)pCell)->GetErrCode();
556 if (nErrCode != 0)
557 PushError( nErrCode);
558 else
560 const ScMatrix* pMat = ((ScFormulaCell*)pCell)->GetMatrix();
561 CalculateMatrixValue(pMat,nC,nR);
564 else
565 PushIllegalParameter();
567 break;
568 case svDoubleRef :
570 SCCOL nCol1;
571 SCROW nRow1;
572 SCTAB nTab1;
573 SCCOL nCol2;
574 SCROW nRow2;
575 SCTAB nTab2;
576 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
577 if (nCol2 - nCol1 >= static_cast<SCCOL>(nR) &&
578 nRow2 - nRow1 >= static_cast<SCROW>(nC) &&
579 nTab1 == nTab2)
581 ScAddress aAdr( sal::static_int_cast<SCCOL>( nCol1 + nR ),
582 sal::static_int_cast<SCROW>( nRow1 + nC ), nTab1 );
583 ScBaseCell* pCell = GetCell( aAdr );
584 if (HasCellValueData(pCell))
585 PushDouble(GetCellValue( aAdr, pCell ));
586 else
588 String aStr;
589 GetCellString(aStr, pCell);
590 PushString(aStr);
593 else
594 PushNoValue();
596 break;
597 case svMatrix:
599 ScMatrixRef pMat = PopMatrix();
600 CalculateMatrixValue(pMat,nC,nR);
602 break;
603 default:
604 PopError();
605 PushIllegalParameter();
606 break;
610 void ScInterpreter::CalculateMatrixValue(const ScMatrix* pMat,SCSIZE nC,SCSIZE nR)
612 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateMatrixValue" );
613 if (pMat)
615 SCSIZE nCl, nRw;
616 pMat->GetDimensions(nCl, nRw);
617 if (nC < nCl && nR < nRw)
619 ScMatValType nMatValType;
620 const ScMatrixValue* pMatVal = pMat->Get( nC, nR,nMatValType);
621 if (ScMatrix::IsNonValueType( nMatValType))
622 PushString( pMatVal->GetString() );
623 else
624 PushDouble(pMatVal->fVal);
625 // also handles DoubleError
627 else
628 PushNoValue();
630 else
631 PushNoValue();
634 void ScInterpreter::ScEMat()
636 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEMat" );
637 if ( MustHaveParamCount( GetByte(), 1 ) )
639 SCSIZE nDim = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble()));
640 if ( nDim * nDim > ScMatrix::GetElementsMax() || nDim == 0)
641 PushIllegalArgument();
642 else
644 ScMatrixRef pRMat = GetNewMat(nDim, nDim);
645 if (pRMat)
647 MEMat(pRMat, nDim);
648 PushMatrix(pRMat);
650 else
651 PushIllegalArgument();
656 void ScInterpreter::MEMat(ScMatrix* mM, SCSIZE n)
658 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MEMat" );
659 mM->FillDouble(0.0, 0, 0, n-1, n-1);
660 for (SCSIZE i = 0; i < n; i++)
661 mM->PutDouble(1.0, i, i);
664 void ScInterpreter::MFastMult(ScMatrix* pA, ScMatrix* pB, ScMatrix* pR,
665 SCSIZE n, SCSIZE m, SCSIZE l)
666 // Multipliziert n x m Mat a mit m x l Mat b nach Mat r
668 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MFastMult" );
669 double sum;
670 for (SCSIZE i = 0; i < n; i++)
672 for (SCSIZE j = 0; j < l; j++)
674 sum = 0.0;
675 for (SCSIZE k = 0; k < m; k++)
676 sum += pA->GetDouble(i,k)*pB->GetDouble(k,j);
677 pR->PutDouble(sum, i, j);
683 /* Matrix LUP decomposition according to the pseudocode of "Introduction to
684 * Algorithms" by Cormen, Leiserson, Rivest, Stein.
686 * Added scaling for numeric stability.
688 * Given an n x n nonsingular matrix A, find a permutation matrix P, a unit
689 * lower-triangular matrix L, and an upper-triangular matrix U such that PA=LU.
690 * Compute L and U "in place" in the matrix A, the original content is
691 * destroyed. Note that the diagonal elements of the U triangular matrix
692 * replace the diagonal elements of the L-unit matrix (that are each ==1). The
693 * permutation matrix P is an array, where P[i]=j means that the i-th row of P
694 * contains a 1 in column j. Additionally keep track of the number of
695 * permutations (row exchanges).
697 * Returns 0 if a singular matrix is encountered, else +1 if an even number of
698 * permutations occured, or -1 if odd, which is the sign of the determinant.
699 * This may be used to calculate the determinant by multiplying the sign with
700 * the product of the diagonal elements of the LU matrix.
702 static int lcl_LUP_decompose( ScMatrix* mA, const SCSIZE n,
703 ::std::vector< SCSIZE> & P )
705 int nSign = 1;
706 // Find scale of each row.
707 ::std::vector< double> aScale(n);
708 for (SCSIZE i=0; i < n; ++i)
710 double fMax = 0.0;
711 for (SCSIZE j=0; j < n; ++j)
713 double fTmp = fabs( mA->GetDouble( j, i));
714 if (fMax < fTmp)
715 fMax = fTmp;
717 if (fMax == 0.0)
718 return 0; // singular matrix
719 aScale[i] = 1.0 / fMax;
721 // Represent identity permutation, P[i]=i
722 for (SCSIZE i=0; i < n; ++i)
723 P[i] = i;
724 // "Recursion" on the diagonale.
725 SCSIZE l = n - 1;
726 for (SCSIZE k=0; k < l; ++k)
728 // Implicit pivoting. With the scale found for a row, compare values of
729 // a column and pick largest.
730 double fMax = 0.0;
731 double fScale = aScale[k];
732 SCSIZE kp = k;
733 for (SCSIZE i = k; i < n; ++i)
735 double fTmp = fScale * fabs( mA->GetDouble( k, i));
736 if (fMax < fTmp)
738 fMax = fTmp;
739 kp = i;
742 if (fMax == 0.0)
743 return 0; // singular matrix
744 // Swap rows. The pivot element will be at mA[k,kp] (row,col notation)
745 if (k != kp)
747 // permutations
748 SCSIZE nTmp = P[k];
749 P[k] = P[kp];
750 P[kp] = nTmp;
751 nSign = -nSign;
752 // scales
753 double fTmp = aScale[k];
754 aScale[k] = aScale[kp];
755 aScale[kp] = fTmp;
756 // elements
757 for (SCSIZE i=0; i < n; ++i)
759 double fMatTmp = mA->GetDouble( i, k);
760 mA->PutDouble( mA->GetDouble( i, kp), i, k);
761 mA->PutDouble( fMatTmp, i, kp);
764 // Compute Schur complement.
765 for (SCSIZE i = k+1; i < n; ++i)
767 double fTmp = mA->GetDouble( k, i) / mA->GetDouble( k, k);
768 mA->PutDouble( fTmp, k, i);
769 for (SCSIZE j = k+1; j < n; ++j)
770 mA->PutDouble( mA->GetDouble( j, i) - fTmp * mA->GetDouble( j,
771 k), j, i);
774 #if OSL_DEBUG_LEVEL > 1
775 fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): LU");
776 for (SCSIZE i=0; i < n; ++i)
778 for (SCSIZE j=0; j < n; ++j)
779 fprintf( stderr, "%8.2g ", mA->GetDouble( j, i));
780 fprintf( stderr, "\n%s\n", "");
782 fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): P");
783 for (SCSIZE j=0; j < n; ++j)
784 fprintf( stderr, "%5u ", (unsigned)P[j]);
785 fprintf( stderr, "\n%s\n", "");
786 #endif
787 return nSign;
791 /* Solve a LUP decomposed equation Ax=b. LU is a combined matrix of L and U
792 * triangulars and P the permutation vector as obtained from
793 * lcl_LUP_decompose(). B is the right-hand side input vector, X is used to
794 * return the solution vector.
796 static void lcl_LUP_solve( const ScMatrix* mLU, const SCSIZE n,
797 const ::std::vector< SCSIZE> & P, const ::std::vector< double> & B,
798 ::std::vector< double> & X )
800 SCSIZE nFirst = SCSIZE_MAX;
801 // Ax=b => PAx=Pb, with decomposition LUx=Pb.
802 // Define y=Ux and solve for y in Ly=Pb using forward substitution.
803 for (SCSIZE i=0; i < n; ++i)
805 double fSum = B[P[i]];
806 // Matrix inversion comes with a lot of zeros in the B vectors, we
807 // don't have to do all the computing with results multiplied by zero.
808 // Until then, simply lookout for the position of the first nonzero
809 // value.
810 if (nFirst != SCSIZE_MAX)
812 for (SCSIZE j = nFirst; j < i; ++j)
813 fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === y[j]
815 else if (fSum)
816 nFirst = i;
817 X[i] = fSum; // X[i] === y[i]
819 // Solve for x in Ux=y using back substitution.
820 for (SCSIZE i = n; i--; )
822 double fSum = X[i]; // X[i] === y[i]
823 for (SCSIZE j = i+1; j < n; ++j)
824 fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === x[j]
825 X[i] = fSum / mLU->GetDouble( i, i); // X[i] === x[i]
827 #if OSL_DEBUG_LEVEL >1
828 fprintf( stderr, "\n%s\n", "lcl_LUP_solve():");
829 for (SCSIZE i=0; i < n; ++i)
830 fprintf( stderr, "%8.2g ", X[i]);
831 fprintf( stderr, "%s\n", "");
832 #endif
836 void ScInterpreter::ScMatDet()
838 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatDet" );
839 if ( MustHaveParamCount( GetByte(), 1 ) )
841 ScMatrixRef pMat = GetMatrix();
842 if (!pMat)
844 PushIllegalParameter();
845 return;
847 if ( !pMat->IsNumeric() )
849 PushNoValue();
850 return;
852 SCSIZE nC, nR;
853 pMat->GetDimensions(nC, nR);
854 if ( nC != nR || nC == 0 || (ULONG) nC * nC > ScMatrix::GetElementsMax() )
855 PushIllegalArgument();
856 else
858 // LUP decomposition is done inplace, use copy.
859 ScMatrixRef xLU = pMat->Clone();
860 if (!xLU)
861 PushError( errCodeOverflow);
862 else
864 ::std::vector< SCSIZE> P(nR);
865 int nDetSign = lcl_LUP_decompose( xLU, nR, P);
866 if (!nDetSign)
867 PushInt(0); // singular matrix
868 else
870 // In an LU matrix the determinant is simply the product of
871 // all diagonal elements.
872 double fDet = nDetSign;
873 ScMatrix* pLU = xLU;
874 for (SCSIZE i=0; i < nR; ++i)
875 fDet *= pLU->GetDouble( i, i);
876 PushDouble( fDet);
883 void ScInterpreter::ScMatInv()
885 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatInv" );
886 if ( MustHaveParamCount( GetByte(), 1 ) )
888 ScMatrixRef pMat = GetMatrix();
889 if (!pMat)
891 PushIllegalParameter();
892 return;
894 if ( !pMat->IsNumeric() )
896 PushNoValue();
897 return;
899 SCSIZE nC, nR;
900 pMat->GetDimensions(nC, nR);
901 if ( nC != nR || nC == 0 || (ULONG) nC * nC > ScMatrix::GetElementsMax() )
902 PushIllegalArgument();
903 else
905 // LUP decomposition is done inplace, use copy.
906 ScMatrixRef xLU = pMat->Clone();
907 // The result matrix.
908 ScMatrixRef xY = GetNewMat( nR, nR);
909 if (!xLU || !xY)
910 PushError( errCodeOverflow);
911 else
913 ::std::vector< SCSIZE> P(nR);
914 int nDetSign = lcl_LUP_decompose( xLU, nR, P);
915 if (!nDetSign)
916 PushIllegalArgument();
917 else
919 // Solve equation for each column.
920 ScMatrix* pY = xY;
921 ::std::vector< double> B(nR);
922 ::std::vector< double> X(nR);
923 for (SCSIZE j=0; j < nR; ++j)
925 for (SCSIZE i=0; i < nR; ++i)
926 B[i] = 0.0;
927 B[j] = 1.0;
928 lcl_LUP_solve( xLU, nR, P, B, X);
929 for (SCSIZE i=0; i < nR; ++i)
930 pY->PutDouble( X[i], j, i);
932 #if 0
933 /* Possible checks for ill-condition:
934 * 1. Scale matrix, invert scaled matrix. If there are
935 * elements of the inverted matrix that are several
936 * orders of magnitude greater than 1 =>
937 * ill-conditioned.
938 * Just how much is "several orders"?
939 * 2. Invert the inverted matrix and assess whether the
940 * result is sufficiently close to the original matrix.
941 * If not => ill-conditioned.
942 * Just what is sufficient?
943 * 3. Multiplying the inverse by the original matrix should
944 * produce a result sufficiently close to the identity
945 * matrix.
946 * Just what is sufficient?
948 * The following is #3.
950 ScMatrixRef xR = GetNewMat( nR, nR);
951 if (xR)
953 ScMatrix* pR = xR;
954 MFastMult( pMat, pY, pR, nR, nR, nR);
955 #if OSL_DEBUG_LEVEL > 1
956 fprintf( stderr, "\n%s\n", "ScMatInv(): mult-identity");
957 #endif
958 for (SCSIZE i=0; i < nR; ++i)
960 for (SCSIZE j=0; j < nR; ++j)
962 double fTmp = pR->GetDouble( j, i);
963 #if OSL_DEBUG_LEVEL > 1
964 fprintf( stderr, "%8.2g ", fTmp);
965 #endif
966 if (fabs( fTmp - (i == j)) > fInvEpsilon)
967 SetError( errIllegalArgument);
969 #if OSL_DEBUG_LEVEL > 1
970 fprintf( stderr, "\n%s\n", "");
971 #endif
974 #endif
975 if (nGlobalError)
976 PushError( nGlobalError);
977 else
978 PushMatrix( pY);
985 void ScInterpreter::ScMatMult()
987 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatMult" );
988 if ( MustHaveParamCount( GetByte(), 2 ) )
990 ScMatrixRef pMat2 = GetMatrix();
991 ScMatrixRef pMat1 = GetMatrix();
992 ScMatrixRef pRMat;
993 if (pMat1 && pMat2)
995 if ( pMat1->IsNumeric() && pMat2->IsNumeric() )
997 SCSIZE nC1, nC2;
998 SCSIZE nR1, nR2;
999 pMat1->GetDimensions(nC1, nR1);
1000 pMat2->GetDimensions(nC2, nR2);
1001 if (nC1 != nR2)
1002 PushIllegalArgument();
1003 else
1005 pRMat = GetNewMat(nC2, nR1);
1006 if (pRMat)
1008 double sum;
1009 for (SCSIZE i = 0; i < nR1; i++)
1011 for (SCSIZE j = 0; j < nC2; j++)
1013 sum = 0.0;
1014 for (SCSIZE k = 0; k < nC1; k++)
1016 sum += pMat1->GetDouble(k,i)*pMat2->GetDouble(j,k);
1018 pRMat->PutDouble(sum, j, i);
1021 PushMatrix(pRMat);
1023 else
1024 PushIllegalArgument();
1027 else
1028 PushNoValue();
1030 else
1031 PushIllegalParameter();
1035 void ScInterpreter::ScMatTrans()
1037 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatTrans" );
1038 if ( MustHaveParamCount( GetByte(), 1 ) )
1040 ScMatrixRef pMat = GetMatrix();
1041 ScMatrixRef pRMat;
1042 if (pMat)
1044 SCSIZE nC, nR;
1045 pMat->GetDimensions(nC, nR);
1046 pRMat = GetNewMat(nR, nC);
1047 if ( pRMat )
1049 pMat->MatTrans(*pRMat);
1050 PushMatrix(pRMat);
1052 else
1053 PushIllegalArgument();
1055 else
1056 PushIllegalParameter();
1061 /** Minimum extent of one result matrix dimension.
1062 For a row or column vector to be replicated the larger matrix dimension is
1063 returned, else the smaller dimension.
1065 inline SCSIZE lcl_GetMinExtent( SCSIZE n1, SCSIZE n2 )
1067 if (n1 == 1)
1068 return n2;
1069 else if (n2 == 1)
1070 return n1;
1071 else if (n1 < n2)
1072 return n1;
1073 else
1074 return n2;
1077 template<class _Function>
1078 ScMatrixRef lcl_MatrixCalculation(const _Function& _pOperation,ScMatrix* pMat1, ScMatrix* pMat2,ScInterpreter* _pIterpreter)
1080 SCSIZE nC1, nC2, nMinC;
1081 SCSIZE nR1, nR2, nMinR;
1082 SCSIZE i, j;
1083 pMat1->GetDimensions(nC1, nR1);
1084 pMat2->GetDimensions(nC2, nR2);
1085 nMinC = lcl_GetMinExtent( nC1, nC2);
1086 nMinR = lcl_GetMinExtent( nR1, nR2);
1087 ScMatrixRef xResMat = _pIterpreter->GetNewMat(nMinC, nMinR);
1088 if (xResMat)
1090 ScMatrix* pResMat = xResMat;
1091 for (i = 0; i < nMinC; i++)
1093 for (j = 0; j < nMinR; j++)
1095 if (pMat1->IsValueOrEmpty(i,j) && pMat2->IsValueOrEmpty(i,j))
1097 double d = _pOperation(pMat1->GetDouble(i,j),pMat2->GetDouble(i,j));
1098 pResMat->PutDouble( d, i, j);
1100 else
1101 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, j);
1105 return xResMat;
1108 ScMatrixRef ScInterpreter::MatConcat(ScMatrix* pMat1, ScMatrix* pMat2)
1110 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MatConcat" );
1111 SCSIZE nC1, nC2, nMinC;
1112 SCSIZE nR1, nR2, nMinR;
1113 SCSIZE i, j;
1114 pMat1->GetDimensions(nC1, nR1);
1115 pMat2->GetDimensions(nC2, nR2);
1116 nMinC = lcl_GetMinExtent( nC1, nC2);
1117 nMinR = lcl_GetMinExtent( nR1, nR2);
1118 ScMatrixRef xResMat = GetNewMat(nMinC, nMinR);
1119 if (xResMat)
1121 ScMatrix* pResMat = xResMat;
1122 for (i = 0; i < nMinC; i++)
1124 for (j = 0; j < nMinR; j++)
1126 USHORT nErr = pMat1->GetErrorIfNotString( i, j);
1127 if (!nErr)
1128 nErr = pMat2->GetErrorIfNotString( i, j);
1129 if (nErr)
1130 pResMat->PutError( nErr, i, j);
1131 else
1133 String aTmp( pMat1->GetString( *pFormatter, i, j));
1134 aTmp += pMat2->GetString( *pFormatter, i, j);
1135 pResMat->PutString( aTmp, i, j);
1140 return xResMat;
1144 // fuer DATE, TIME, DATETIME
1145 void lcl_GetDiffDateTimeFmtType( short& nFuncFmt, short nFmt1, short nFmt2 )
1147 if ( nFmt1 != NUMBERFORMAT_UNDEFINED || nFmt2 != NUMBERFORMAT_UNDEFINED )
1149 if ( nFmt1 == nFmt2 )
1151 if ( nFmt1 == NUMBERFORMAT_TIME || nFmt1 == NUMBERFORMAT_DATETIME )
1152 nFuncFmt = NUMBERFORMAT_TIME; // Zeiten ergeben Zeit
1153 // else: nichts besonderes, Zahl (Datum - Datum := Tage)
1155 else if ( nFmt1 == NUMBERFORMAT_UNDEFINED )
1156 nFuncFmt = nFmt2; // z.B. Datum + Tage := Datum
1157 else if ( nFmt2 == NUMBERFORMAT_UNDEFINED )
1158 nFuncFmt = nFmt1;
1159 else
1161 if ( nFmt1 == NUMBERFORMAT_DATE || nFmt2 == NUMBERFORMAT_DATE ||
1162 nFmt1 == NUMBERFORMAT_DATETIME || nFmt2 == NUMBERFORMAT_DATETIME )
1164 if ( nFmt1 == NUMBERFORMAT_TIME || nFmt2 == NUMBERFORMAT_TIME )
1165 nFuncFmt = NUMBERFORMAT_DATETIME; // Datum + Zeit
1172 void ScInterpreter::ScAdd()
1174 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAdd" );
1175 CalculateAddSub(FALSE);
1177 void ScInterpreter::CalculateAddSub(BOOL _bSub)
1179 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateAddSub" );
1180 ScMatrixRef pMat1 = NULL;
1181 ScMatrixRef pMat2 = NULL;
1182 double fVal1 = 0.0, fVal2 = 0.0;
1183 short nFmt1, nFmt2;
1184 nFmt1 = nFmt2 = NUMBERFORMAT_UNDEFINED;
1185 short nFmtCurrencyType = nCurFmtType;
1186 ULONG nFmtCurrencyIndex = nCurFmtIndex;
1187 short nFmtPercentType = nCurFmtType;
1188 if ( GetStackType() == svMatrix )
1189 pMat2 = GetMatrix();
1190 else
1192 fVal2 = GetDouble();
1193 switch ( nCurFmtType )
1195 case NUMBERFORMAT_DATE :
1196 case NUMBERFORMAT_TIME :
1197 case NUMBERFORMAT_DATETIME :
1198 nFmt2 = 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;
1209 if ( GetStackType() == svMatrix )
1210 pMat1 = GetMatrix();
1211 else
1213 fVal1 = GetDouble();
1214 switch ( nCurFmtType )
1216 case NUMBERFORMAT_DATE :
1217 case NUMBERFORMAT_TIME :
1218 case NUMBERFORMAT_DATETIME :
1219 nFmt1 = nCurFmtType;
1220 break;
1221 case NUMBERFORMAT_CURRENCY :
1222 nFmtCurrencyType = nCurFmtType;
1223 nFmtCurrencyIndex = nCurFmtIndex;
1224 break;
1225 case NUMBERFORMAT_PERCENT :
1226 nFmtPercentType = NUMBERFORMAT_PERCENT;
1227 break;
1230 if (pMat1 && pMat2)
1232 ScMatrixRef pResMat;
1233 if ( _bSub )
1235 MatrixSub aSub;
1236 pResMat = lcl_MatrixCalculation(aSub ,pMat1, pMat2,this);
1238 else
1240 MatrixAdd aAdd;
1241 pResMat = lcl_MatrixCalculation(aAdd ,pMat1, pMat2,this);
1244 if (!pResMat)
1245 PushNoValue();
1246 else
1247 PushMatrix(pResMat);
1249 else if (pMat1 || pMat2)
1251 double fVal;
1252 BOOL bFlag;
1253 ScMatrixRef pMat = pMat1;
1254 if (!pMat)
1256 fVal = fVal1;
1257 pMat = pMat2;
1258 bFlag = TRUE; // double - Matrix
1260 else
1262 fVal = fVal2;
1263 bFlag = FALSE; // Matrix - double
1265 SCSIZE nC, nR;
1266 pMat->GetDimensions(nC, nR);
1267 ScMatrixRef pResMat = GetNewMat(nC, nR);
1268 if (pResMat)
1270 SCSIZE nCount = nC * nR;
1271 if (bFlag || !_bSub )
1273 for ( SCSIZE i = 0; i < nCount; i++ )
1275 if (pMat->IsValue(i))
1276 pResMat->PutDouble( _bSub ? ::rtl::math::approxSub( fVal, pMat->GetDouble(i)) : ::rtl::math::approxAdd( pMat->GetDouble(i), fVal), i);
1277 else
1278 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1279 } // for ( SCSIZE i = 0; i < nCount; i++ )
1280 } // if (bFlag || !_bSub )
1281 else
1283 for ( SCSIZE i = 0; i < nCount; i++ )
1284 { if (pMat->IsValue(i))
1285 pResMat->PutDouble( ::rtl::math::approxSub( pMat->GetDouble(i), fVal), i);
1286 else
1287 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1288 } // for ( SCSIZE i = 0; i < nCount; i++ )
1290 PushMatrix(pResMat);
1292 else
1293 PushIllegalArgument();
1295 else if ( _bSub )
1296 PushDouble( ::rtl::math::approxSub( fVal1, fVal2 ) );
1297 else
1298 PushDouble( ::rtl::math::approxAdd( fVal1, fVal2 ) );
1299 if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY )
1301 nFuncFmtType = nFmtCurrencyType;
1302 nFuncFmtIndex = nFmtCurrencyIndex;
1304 else
1306 lcl_GetDiffDateTimeFmtType( nFuncFmtType, nFmt1, nFmt2 );
1307 if ( nFmtPercentType == NUMBERFORMAT_PERCENT && nFuncFmtType == NUMBERFORMAT_NUMBER )
1308 nFuncFmtType = NUMBERFORMAT_PERCENT;
1312 void ScInterpreter::ScAmpersand()
1314 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAmpersand" );
1315 ScMatrixRef pMat1 = NULL;
1316 ScMatrixRef pMat2 = NULL;
1317 String sStr1, sStr2;
1318 if ( GetStackType() == svMatrix )
1319 pMat2 = GetMatrix();
1320 else
1321 sStr2 = GetString();
1322 if ( GetStackType() == svMatrix )
1323 pMat1 = GetMatrix();
1324 else
1325 sStr1 = GetString();
1326 if (pMat1 && pMat2)
1328 ScMatrixRef pResMat = MatConcat(pMat1, pMat2);
1329 if (!pResMat)
1330 PushNoValue();
1331 else
1332 PushMatrix(pResMat);
1334 else if (pMat1 || pMat2)
1336 String sStr;
1337 BOOL bFlag;
1338 ScMatrixRef pMat = pMat1;
1339 if (!pMat)
1341 sStr = sStr1;
1342 pMat = pMat2;
1343 bFlag = TRUE; // double - Matrix
1345 else
1347 sStr = sStr2;
1348 bFlag = FALSE; // Matrix - double
1350 SCSIZE nC, nR;
1351 pMat->GetDimensions(nC, nR);
1352 ScMatrixRef pResMat = GetNewMat(nC, nR);
1353 if (pResMat)
1355 SCSIZE nCount = nC * nR;
1356 if (nGlobalError)
1358 for ( SCSIZE i = 0; i < nCount; i++ )
1359 pResMat->PutError( nGlobalError, i);
1361 else if (bFlag)
1363 for ( SCSIZE i = 0; i < nCount; i++ )
1365 USHORT nErr = pMat->GetErrorIfNotString( i);
1366 if (nErr)
1367 pResMat->PutError( nErr, i);
1368 else
1370 String aTmp( sStr);
1371 aTmp += pMat->GetString( *pFormatter, i);
1372 pResMat->PutString( aTmp, i);
1376 else
1378 for ( SCSIZE i = 0; i < nCount; i++ )
1380 USHORT nErr = pMat->GetErrorIfNotString( i);
1381 if (nErr)
1382 pResMat->PutError( nErr, i);
1383 else
1385 String aTmp( pMat->GetString( *pFormatter, i));
1386 aTmp += sStr;
1387 pResMat->PutString( aTmp, i);
1391 PushMatrix(pResMat);
1393 else
1394 PushIllegalArgument();
1396 else
1398 if ( CheckStringResultLen( sStr1, sStr2 ) )
1399 sStr1 += sStr2;
1400 PushString(sStr1);
1404 void ScInterpreter::ScSub()
1406 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSub" );
1407 CalculateAddSub(TRUE);
1410 void ScInterpreter::ScMul()
1412 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMul" );
1413 ScMatrixRef pMat1 = NULL;
1414 ScMatrixRef pMat2 = NULL;
1415 double fVal1 = 0.0, fVal2 = 0.0;
1416 short nFmtCurrencyType = nCurFmtType;
1417 ULONG nFmtCurrencyIndex = nCurFmtIndex;
1418 if ( GetStackType() == svMatrix )
1419 pMat2 = GetMatrix();
1420 else
1422 fVal2 = GetDouble();
1423 switch ( nCurFmtType )
1425 case NUMBERFORMAT_CURRENCY :
1426 nFmtCurrencyType = nCurFmtType;
1427 nFmtCurrencyIndex = nCurFmtIndex;
1428 break;
1431 if ( GetStackType() == svMatrix )
1432 pMat1 = GetMatrix();
1433 else
1435 fVal1 = GetDouble();
1436 switch ( nCurFmtType )
1438 case NUMBERFORMAT_CURRENCY :
1439 nFmtCurrencyType = nCurFmtType;
1440 nFmtCurrencyIndex = nCurFmtIndex;
1441 break;
1444 if (pMat1 && pMat2)
1446 MatrixMul aMul;
1447 ScMatrixRef pResMat = lcl_MatrixCalculation(aMul,pMat1, pMat2,this);
1448 if (!pResMat)
1449 PushNoValue();
1450 else
1451 PushMatrix(pResMat);
1453 else if (pMat1 || pMat2)
1455 double fVal;
1456 ScMatrixRef pMat = pMat1;
1457 if (!pMat)
1459 fVal = fVal1;
1460 pMat = pMat2;
1462 else
1463 fVal = fVal2;
1464 SCSIZE nC, nR;
1465 pMat->GetDimensions(nC, nR);
1466 ScMatrixRef pResMat = GetNewMat(nC, nR);
1467 if (pResMat)
1469 SCSIZE nCount = nC * nR;
1470 for ( SCSIZE i = 0; i < nCount; i++ )
1471 if (pMat->IsValue(i))
1472 pResMat->PutDouble(pMat->GetDouble(i)*fVal, i);
1473 else
1474 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1475 PushMatrix(pResMat);
1477 else
1478 PushIllegalArgument();
1480 else
1481 PushDouble(fVal1 * fVal2);
1482 if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY )
1484 nFuncFmtType = nFmtCurrencyType;
1485 nFuncFmtIndex = nFmtCurrencyIndex;
1489 void ScInterpreter::ScDiv()
1491 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDiv" );
1492 ScMatrixRef pMat1 = NULL;
1493 ScMatrixRef pMat2 = NULL;
1494 double fVal1 = 0.0, fVal2 = 0.0;
1495 short nFmtCurrencyType = nCurFmtType;
1496 ULONG nFmtCurrencyIndex = nCurFmtIndex;
1497 short nFmtCurrencyType2 = NUMBERFORMAT_UNDEFINED;
1498 if ( GetStackType() == svMatrix )
1499 pMat2 = GetMatrix();
1500 else
1502 fVal2 = GetDouble();
1503 // hier kein Currency uebernehmen, 123kg/456DM sind nicht DM
1504 nFmtCurrencyType2 = nCurFmtType;
1506 if ( GetStackType() == svMatrix )
1507 pMat1 = GetMatrix();
1508 else
1510 fVal1 = GetDouble();
1511 switch ( nCurFmtType )
1513 case NUMBERFORMAT_CURRENCY :
1514 nFmtCurrencyType = nCurFmtType;
1515 nFmtCurrencyIndex = nCurFmtIndex;
1516 break;
1519 if (pMat1 && pMat2)
1521 MatrixDiv aDiv;
1522 ScMatrixRef pResMat = lcl_MatrixCalculation(aDiv,pMat1, pMat2,this);
1523 if (!pResMat)
1524 PushNoValue();
1525 else
1526 PushMatrix(pResMat);
1528 else if (pMat1 || pMat2)
1530 double fVal;
1531 BOOL bFlag;
1532 ScMatrixRef pMat = pMat1;
1533 if (!pMat)
1535 fVal = fVal1;
1536 pMat = pMat2;
1537 bFlag = TRUE; // double - Matrix
1539 else
1541 fVal = fVal2;
1542 bFlag = FALSE; // Matrix - double
1544 SCSIZE nC, nR;
1545 pMat->GetDimensions(nC, nR);
1546 ScMatrixRef pResMat = GetNewMat(nC, nR);
1547 if (pResMat)
1549 SCSIZE nCount = nC * nR;
1550 if (bFlag)
1551 { for ( SCSIZE i = 0; i < nCount; i++ )
1552 if (pMat->IsValue(i))
1553 pResMat->PutDouble( div( fVal, pMat->GetDouble(i)), i);
1554 else
1555 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1557 else
1558 { for ( SCSIZE i = 0; i < nCount; i++ )
1559 if (pMat->IsValue(i))
1560 pResMat->PutDouble( div( pMat->GetDouble(i), fVal), i);
1561 else
1562 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1564 PushMatrix(pResMat);
1566 else
1567 PushIllegalArgument();
1569 else
1571 PushDouble( div( fVal1, fVal2) );
1573 if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY && nFmtCurrencyType2 != NUMBERFORMAT_CURRENCY )
1574 { // auch DM/DM ist nicht DM bzw. DEM/EUR nicht DEM
1575 nFuncFmtType = nFmtCurrencyType;
1576 nFuncFmtIndex = nFmtCurrencyIndex;
1580 void ScInterpreter::ScPower()
1582 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPower" );
1583 if ( MustHaveParamCount( GetByte(), 2 ) )
1584 ScPow();
1587 void ScInterpreter::ScPow()
1589 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPow" );
1590 ScMatrixRef pMat1 = NULL;
1591 ScMatrixRef pMat2 = NULL;
1592 double fVal1 = 0.0, fVal2 = 0.0;
1593 if ( GetStackType() == svMatrix )
1594 pMat2 = GetMatrix();
1595 else
1596 fVal2 = GetDouble();
1597 if ( GetStackType() == svMatrix )
1598 pMat1 = GetMatrix();
1599 else
1600 fVal1 = GetDouble();
1601 if (pMat1 && pMat2)
1603 MatrixPow aPow;
1604 ScMatrixRef pResMat = lcl_MatrixCalculation(aPow,pMat1, pMat2,this);
1605 if (!pResMat)
1606 PushNoValue();
1607 else
1608 PushMatrix(pResMat);
1610 else if (pMat1 || pMat2)
1612 double fVal;
1613 BOOL bFlag;
1614 ScMatrixRef pMat = pMat1;
1615 if (!pMat)
1617 fVal = fVal1;
1618 pMat = pMat2;
1619 bFlag = TRUE; // double - Matrix
1621 else
1623 fVal = fVal2;
1624 bFlag = FALSE; // Matrix - double
1626 SCSIZE nC, nR;
1627 pMat->GetDimensions(nC, nR);
1628 ScMatrixRef pResMat = GetNewMat(nC, nR);
1629 if (pResMat)
1631 SCSIZE nCount = nC * nR;
1632 if (bFlag)
1633 { for ( SCSIZE i = 0; i < nCount; i++ )
1634 if (pMat->IsValue(i))
1635 pResMat->PutDouble(pow(fVal,pMat->GetDouble(i)), i);
1636 else
1637 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1639 else
1640 { for ( SCSIZE i = 0; i < nCount; i++ )
1641 if (pMat->IsValue(i))
1642 pResMat->PutDouble(pow(pMat->GetDouble(i),fVal), i);
1643 else
1644 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1646 PushMatrix(pResMat);
1648 else
1649 PushIllegalArgument();
1651 else
1652 PushDouble(pow(fVal1,fVal2));
1655 void ScInterpreter::ScSumProduct()
1657 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumProduct" );
1658 BYTE nParamCount = GetByte();
1659 if ( !MustHaveParamCount( nParamCount, 1, 30 ) )
1660 return;
1662 ScMatrixRef pMat1 = NULL;
1663 ScMatrixRef pMat2 = NULL;
1664 ScMatrixRef pMat = NULL;
1665 pMat2 = GetMatrix();
1666 if (!pMat2)
1668 PushIllegalParameter();
1669 return;
1671 SCSIZE nC, nC1;
1672 SCSIZE nR, nR1;
1673 pMat2->GetDimensions(nC, nR);
1674 pMat = pMat2;
1675 MatrixMul aMul;
1676 for (USHORT i = 1; i < nParamCount; i++)
1678 pMat1 = GetMatrix();
1679 if (!pMat1)
1681 PushIllegalParameter();
1682 return;
1684 pMat1->GetDimensions(nC1, nR1);
1685 if (nC1 != nC || nR1 != nR)
1687 PushNoValue();
1688 return;
1690 ScMatrixRef pResMat = lcl_MatrixCalculation(aMul,pMat1, pMat,this);
1691 if (!pResMat)
1693 PushNoValue();
1694 return;
1696 else
1697 pMat = pResMat;
1699 double fSum = 0.0;
1700 SCSIZE nCount = pMat->GetElementCount();
1701 for (SCSIZE j = 0; j < nCount; j++)
1703 if (!pMat->IsString(j))
1704 fSum += pMat->GetDouble(j);
1706 PushDouble(fSum);
1709 void ScInterpreter::ScSumX2MY2()
1711 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumX2MY2" );
1712 CalculateSumX2MY2SumX2DY2(FALSE);
1714 void ScInterpreter::CalculateSumX2MY2SumX2DY2(BOOL _bSumX2DY2)
1716 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateSumX2MY2SumX2DY2" );
1717 if ( !MustHaveParamCount( GetByte(), 2 ) )
1718 return;
1720 ScMatrixRef pMat1 = NULL;
1721 ScMatrixRef pMat2 = NULL;
1722 SCSIZE i, j;
1723 pMat2 = GetMatrix();
1724 pMat1 = GetMatrix();
1725 if (!pMat2 || !pMat1)
1727 PushIllegalParameter();
1728 return;
1730 SCSIZE nC1, nC2;
1731 SCSIZE nR1, nR2;
1732 pMat2->GetDimensions(nC2, nR2);
1733 pMat1->GetDimensions(nC1, nR1);
1734 if (nC1 != nC2 || nR1 != nR2)
1736 PushNoValue();
1737 return;
1739 double fVal, fSum = 0.0;
1740 for (i = 0; i < nC1; i++)
1741 for (j = 0; j < nR1; j++)
1742 if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
1744 fVal = pMat1->GetDouble(i,j);
1745 fSum += fVal * fVal;
1746 fVal = pMat2->GetDouble(i,j);
1747 if ( _bSumX2DY2 )
1748 fSum += fVal * fVal;
1749 else
1750 fSum -= fVal * fVal;
1752 PushDouble(fSum);
1755 void ScInterpreter::ScSumX2DY2()
1757 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumX2DY2" );
1758 CalculateSumX2MY2SumX2DY2(TRUE);
1761 void ScInterpreter::ScSumXMY2()
1763 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumXMY2" );
1764 if ( !MustHaveParamCount( GetByte(), 2 ) )
1765 return;
1767 ScMatrixRef pMat1 = NULL;
1768 ScMatrixRef pMat2 = NULL;
1769 pMat2 = GetMatrix();
1770 pMat1 = GetMatrix();
1771 if (!pMat2 || !pMat1)
1773 PushIllegalParameter();
1774 return;
1776 SCSIZE nC1, nC2;
1777 SCSIZE nR1, nR2;
1778 pMat2->GetDimensions(nC2, nR2);
1779 pMat1->GetDimensions(nC1, nR1);
1780 if (nC1 != nC2 || nR1 != nR2)
1782 PushNoValue();
1783 return;
1784 } // if (nC1 != nC2 || nR1 != nR2)
1785 MatrixSub aSub;
1786 ScMatrixRef pResMat = lcl_MatrixCalculation(aSub,pMat1, pMat2,this);
1787 if (!pResMat)
1789 PushNoValue();
1791 else
1793 double fVal, fSum = 0.0;
1794 SCSIZE nCount = pResMat->GetElementCount();
1795 for (SCSIZE i = 0; i < nCount; i++)
1796 if (!pResMat->IsString(i))
1798 fVal = pResMat->GetDouble(i);
1799 fSum += fVal * fVal;
1801 PushDouble(fSum);
1805 void ScInterpreter::ScFrequency()
1807 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFrequency" );
1808 if ( !MustHaveParamCount( GetByte(), 2 ) )
1809 return;
1811 vector<double> aBinArray;
1812 vector<long> aBinIndexOrder;
1814 GetSortArray(1, aBinArray, &aBinIndexOrder);
1815 SCSIZE nBinSize = aBinArray.size();
1816 if (nGlobalError)
1818 PushNoValue();
1819 return;
1822 vector<double> aDataArray;
1823 GetSortArray(1, aDataArray);
1824 SCSIZE nDataSize = aDataArray.size();
1826 if (aDataArray.empty() || nGlobalError)
1828 PushNoValue();
1829 return;
1831 ScMatrixRef pResMat = GetNewMat(1, nBinSize+1);
1832 if (!pResMat)
1834 PushIllegalArgument();
1835 return;
1838 if (nBinSize != aBinIndexOrder.size())
1840 PushIllegalArgument();
1841 return;
1844 SCSIZE j;
1845 SCSIZE i = 0;
1846 for (j = 0; j < nBinSize; ++j)
1848 SCSIZE nCount = 0;
1849 while (i < nDataSize && aDataArray[i] <= aBinArray[j])
1851 ++nCount;
1852 ++i;
1854 pResMat->PutDouble(static_cast<double>(nCount), aBinIndexOrder[j]);
1856 pResMat->PutDouble(static_cast<double>(nDataSize-i), j);
1857 PushMatrix(pResMat);
1860 BOOL ScInterpreter::RGetVariances( ScMatrix* pV, ScMatrix* pX,
1861 SCSIZE nC, SCSIZE nR, BOOL bSwapColRow, BOOL bZeroConstant )
1862 { // multiple Regression: Varianzen der Koeffizienten
1863 // bSwapColRow==TRUE : Koeffizienten in Zeilen statt Spalten angeordnet
1864 SCSIZE i, j, k;
1865 double sum;
1866 ScMatrixRef pC = GetNewMat(nC, nC);
1867 if ( !pC )
1868 return FALSE;
1869 // X transformiert mit X multipziert, X'X Matrix
1870 if ( !bZeroConstant )
1871 { // in der X-Designmatrix existiert ein gedachtes X0j==1
1872 if ( bSwapColRow )
1874 for ( i=0; i<nC; i++ )
1876 for ( j=0; j<nC; j++ )
1878 sum = 0.0;
1879 for ( k=0; k<nR; k++ )
1881 sum += (j==0 ? 1 : pX->GetDouble(k,j-1))
1882 * (i==0 ? 1 : pX->GetDouble(k,i-1));
1884 pC->PutDouble(sum, i, j);
1888 else
1890 for ( i=0; i<nC; i++ )
1892 for ( j=0; j<nC; j++ )
1894 sum = 0.0;
1895 for ( k=0; k<nR; k++ )
1897 sum += (j==0 ? 1 : pX->GetDouble(j-1,k))
1898 * (i==0 ? 1 : pX->GetDouble(i-1,k));
1900 pC->PutDouble(sum, i, j);
1905 else
1907 if ( bSwapColRow )
1909 for ( i=0; i<nC; i++ )
1911 for ( j=0; j<nC; j++ )
1913 sum = 0.0;
1914 for ( k=0; k<nR; k++ )
1916 sum += pX->GetDouble(k,j) * pX->GetDouble(k,i);
1918 pC->PutDouble(sum, i, j);
1922 else
1924 for ( i=0; i<nC; i++ )
1926 for ( j=0; j<nC; j++ )
1928 sum = 0.0;
1929 for ( k=0; k<nR; k++ )
1931 sum += pX->GetDouble(j,k) * pX->GetDouble(i,k);
1933 pC->PutDouble(sum, i, j);
1938 // X'X Inverse
1939 BOOL bOk = TRUE;
1940 USHORT nErr = nGlobalError;
1941 PushMatrix(pC);
1942 BYTE nTmp = cPar;
1943 cPar = 1;
1944 ScMatInv();
1945 cPar = nTmp;
1946 if ( nGlobalError )
1948 nGlobalError = nErr;
1949 bOk = FALSE;
1951 else
1953 // #i61216# ScMatInv no longer modifies the original matrix, so just calling Pop() doesn't work
1954 pC = PopMatrix();
1955 if ( pC.Is() )
1957 // Varianzen auf der Diagonalen, andere sind Kovarianzen
1958 for (i = 0; i < nC; i++)
1959 pV->PutDouble(pC->GetDouble(i, i), i);
1962 return bOk;
1964 // -----------------------------------------------------------------------------
1965 void ScInterpreter::Calculate(ScMatrixRef& pResMat,ScMatrixRef& pE,ScMatrixRef& pQ,ScMatrixRef& pV,ScMatrixRef& pMatX,BOOL bConstant,SCSIZE N,SCSIZE M,BYTE nCase)
1967 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RGetVariances" );
1968 // pE[0] := Sigma i=1...n (Yi)
1969 // pE[k] := Sigma i=1...n (Xki*Yi)
1970 // pE[M+1] := Sigma i=1...n (Yi**2)
1971 // pQ[0,M+1]:= B
1972 // pQ[k,M+1]:= Mk
1973 double fSQR, fSQT, fSQE;
1974 fSQT = pE->GetDouble(M+1)
1975 - pE->GetDouble(0) * pE->GetDouble(0) / (double)N;
1976 fSQR = pE->GetDouble(M+1);
1977 SCSIZE i, j;
1978 for (i = 0; i < M+1; i++)
1979 fSQR -= pQ->GetDouble(i, M+1) * pE->GetDouble(i);
1980 fSQE = fSQT-fSQR;
1981 // r2 (Bestimmtheitsmass, 0...1)
1982 if (fSQT == 0.0)
1983 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 2);
1984 else
1985 pResMat->PutDouble (fSQE/fSQT, 0, 2);
1986 // ssReg (Regressions-Quadratsumme)
1987 pResMat->PutDouble(fSQE, 0, 4);
1988 // ssResid (Residual-Quadratsumme, Summe der Abweichungsquadrate)
1989 pResMat->PutDouble(fSQR, 1, 4);
1990 for (i = 2; i < 5; i++)
1991 for (j = 2; j < M+1; j++)
1992 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), j, i);
1993 if (bConstant)
1995 if (N-M-1 == 0)
1997 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2);
1998 for (i = 0; i < M+1; i++)
1999 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, 1);
2001 else
2003 double fSE2 = fSQR/(N-M-1);
2004 // sey (Standardfehler des Schaetzwertes y)
2005 pResMat->PutDouble(sqrt(fSE2), 1, 2);
2006 // sen...se1 (Standardfehler der Koeffizienten mn...m1)
2007 // seb (Standardfehler der Konstanten b)
2008 if ( RGetVariances( pV, pMatX, M+1, N, nCase != 2, FALSE ) )
2010 for (i = 0; i < M+1; i++)
2011 pResMat->PutDouble( sqrt(fSE2 * pV->GetDouble(i)), M-i, 1 );
2013 else
2015 for (i = 0; i < M+1; i++)
2016 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 1);
2019 // F (F-Statistik)
2020 if (fSQR == 0.0)
2021 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3);
2022 else
2023 pResMat->PutDouble(((double)(N-M-1))*fSQE/fSQR/((double)M),0, 3);
2024 // df (Freiheitsgrad)
2025 pResMat->PutDouble(((double)(N-M-1)), 1, 3);
2027 else
2029 if (N-M == 0)
2031 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2);
2032 for (i = 0; i < M+1; i++)
2033 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, 1);
2035 else
2037 double fSE2 = fSQR/(N-M);
2038 pResMat->PutDouble(sqrt(fSE2), 1, 2);
2039 if ( RGetVariances( pV, pMatX, M, N, nCase != 2, TRUE ) )
2041 for (i = 0; i < M; i++)
2042 pResMat->PutDouble( sqrt(fSE2 * pV->GetDouble(i)), M-i-1, 1 );
2043 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), M, 1);
2045 else
2047 for (i = 0; i < M+1; i++)
2048 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 1);
2051 if (fSQR == 0.0)
2052 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3);
2053 else
2054 pResMat->PutDouble(((double)(N-M))*fSQE/fSQR/((double)M),0, 3);
2055 pResMat->PutDouble(((double)(N-M)), 1, 3);
2059 void ScInterpreter::ScRGP()
2061 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRGP" );
2062 CalulateRGPRKP(FALSE);
2064 bool ScInterpreter::CheckMatrix(BOOL _bLOG,BOOL _bTrendGrowth,BYTE& nCase,SCSIZE& nCX,SCSIZE& nCY,SCSIZE& nRX,SCSIZE& nRY,SCSIZE& M,SCSIZE& N,ScMatrixRef& pMatX,ScMatrixRef& pMatY)
2066 nCX = 0;
2067 nCY = 0;
2068 nRX = 0;
2069 nRY = 0;
2070 M = 0;
2071 N = 0;
2072 pMatY->GetDimensions(nCY, nRY);
2073 const SCSIZE nCountY = nCY * nRY;
2074 for ( SCSIZE i = 0; i < nCountY; i++ )
2076 if (!pMatY->IsValue(i))
2078 PushIllegalArgument();
2079 return false;
2080 } // if (!pMatY->IsValue(i))
2081 } // for ( SCSIZE i = 0; i < nCountY; i++ )
2082 if ( _bLOG )
2084 for (SCSIZE nElem = 0; nElem < nCountY; nElem++)
2086 const double fVal = pMatY->GetDouble(nElem);
2087 if (fVal <= 0.0)
2089 PushIllegalArgument();
2090 return false;
2092 else
2093 pMatY->PutDouble(log(fVal), nElem);
2094 } // for (nElem = 0; nElem < nCountY; nElem++)
2095 } // if ( _bRKP )
2098 if (pMatX)
2100 pMatX->GetDimensions(nCX, nRX);
2101 const SCSIZE nCountX = nCX * nRX;
2102 for ( SCSIZE i = 0; i < nCountX; i++ )
2103 if (!pMatX->IsValue(i))
2105 PushIllegalArgument();
2106 return false;
2108 if (nCX == nCY && nRX == nRY)
2109 nCase = 1; // einfache Regression
2110 else if (nCY != 1 && nRY != 1)
2112 PushIllegalArgument();
2113 return false;
2115 else if (nCY == 1)
2117 if (nRX != nRY)
2119 PushIllegalArgument();
2120 return false;
2122 else
2124 nCase = 2; // zeilenweise
2125 N = nRY;
2126 M = nCX;
2129 else if (nCX != nCY)
2131 PushIllegalArgument();
2132 return false;
2134 else
2136 nCase = 3; // spaltenweise
2137 N = nCY;
2138 M = nRX;
2141 else
2143 pMatX = GetNewMat(nCY, nRY);
2144 if ( _bTrendGrowth )
2146 nCX = nCY;
2147 nRX = nRY;
2149 if (!pMatX)
2151 PushIllegalArgument();
2152 return false;
2154 for ( SCSIZE i = 1; i <= nCountY; i++ )
2155 pMatX->PutDouble((double)i, i-1);
2156 nCase = 1;
2158 return true;
2160 void ScInterpreter::CalulateRGPRKP(BOOL _bRKP)
2162 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CheckMatrix" );
2163 BYTE nParamCount = GetByte();
2164 if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
2165 return;
2166 BOOL bConstant, bStats;
2167 if (nParamCount == 4)
2168 bStats = GetBool();
2169 else
2170 bStats = FALSE;
2171 if (nParamCount >= 3)
2172 bConstant = GetBool();
2173 else
2174 bConstant = TRUE;
2175 ScMatrixRef pMatX;
2176 ScMatrixRef pMatY;
2177 if (nParamCount >= 2)
2178 pMatX = GetMatrix();
2179 else
2180 pMatX = NULL;
2181 pMatY = GetMatrix();
2182 if (!pMatY)
2184 PushIllegalParameter();
2185 return;
2186 } // if (!pMatY)
2187 BYTE nCase; // 1 = normal, 2,3 = mehrfach
2188 SCSIZE nCX, nCY;
2189 SCSIZE nRX, nRY;
2190 SCSIZE M = 0, N = 0;
2191 if ( !CheckMatrix(_bRKP,FALSE,nCase,nCX,nCY,nRX,nRY,M,N,pMatX,pMatY) )
2192 return;
2194 ScMatrixRef pResMat;
2195 if (nCase == 1)
2197 if (!bStats)
2198 pResMat = GetNewMat(2,1);
2199 else
2200 pResMat = GetNewMat(2,5);
2201 if (!pResMat)
2203 PushIllegalArgument();
2204 return;
2206 double fCount = 0.0;
2207 double fSumX = 0.0;
2208 double fSumSqrX = 0.0;
2209 double fSumY = 0.0;
2210 double fSumSqrY = 0.0;
2211 double fSumXY = 0.0;
2212 double fValX, fValY;
2213 for (SCSIZE i = 0; i < nCY; i++)
2214 for (SCSIZE j = 0; j < nRY; j++)
2216 fValX = pMatX->GetDouble(i,j);
2217 fValY = pMatY->GetDouble(i,j);
2218 fSumX += fValX;
2219 fSumSqrX += fValX * fValX;
2220 fSumY += fValY;
2221 fSumSqrY += fValY * fValY;
2222 fSumXY += fValX*fValY;
2223 fCount++;
2225 if (fCount < 1.0)
2226 PushNoValue();
2227 else
2229 double f1 = fCount*fSumXY-fSumX*fSumY;
2230 double fX = fCount*fSumSqrX-fSumX*fSumX;
2231 double b, m;
2232 if (bConstant)
2234 b = fSumY/fCount - f1/fX*fSumX/fCount;
2235 m = f1/fX;
2237 else
2239 b = 0.0;
2240 m = fSumXY/fSumSqrX;
2242 pResMat->PutDouble(_bRKP ? exp(m) : m, 0, 0);
2243 pResMat->PutDouble(_bRKP ? exp(b) : b, 1, 0);
2244 if (bStats)
2246 double fY = fCount*fSumSqrY-fSumY*fSumY;
2247 double fSyx = fSumSqrY-b*fSumY-m*fSumXY;
2248 double fR2 = f1*f1/(fX*fY);
2249 pResMat->PutDouble (fR2, 0, 2);
2250 if (fCount < 3.0)
2252 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 1 );
2253 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 1 );
2254 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2 );
2255 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3 );
2257 else
2259 pResMat->PutDouble(sqrt(fSyx*fCount/(fX*(fCount-2.0))), 0, 1);
2260 pResMat->PutDouble(sqrt(fSyx*fSumSqrX/fX/(fCount-2.0)), 1, 1);
2261 pResMat->PutDouble(
2262 sqrt((fCount*fSumSqrY - fSumY*fSumY - f1*f1/fX)/
2263 (fCount*(fCount-2.0))), 1, 2);
2264 if (fR2 == 1.0)
2265 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3 );
2266 else
2267 pResMat->PutDouble(fR2*(fCount-2.0)/(1.0-fR2), 0, 3);
2269 pResMat->PutDouble(((double)(nCY*nRY))-2.0, 1, 3);
2270 pResMat->PutDouble(fY/fCount-fSyx, 0, 4);
2271 pResMat->PutDouble(fSyx, 1, 4);
2274 } // if (nCase == 1)
2275 if ( nCase != 1 )
2277 SCSIZE i, j, k;
2278 if (!bStats)
2279 pResMat = GetNewMat(M+1,1);
2280 else
2281 pResMat = GetNewMat(M+1,5);
2282 if (!pResMat)
2284 PushIllegalArgument();
2285 return;
2287 ScMatrixRef pQ = GetNewMat(M+1, M+2);
2288 ScMatrixRef pE = GetNewMat(M+2, 1);
2289 ScMatrixRef pV = GetNewMat(M+1, 1);
2290 pE->PutDouble(0.0, M+1);
2291 pQ->FillDouble(0.0, 0, 0, M, M+1);
2292 if (nCase == 2)
2294 for (k = 0; k < N; k++)
2296 double Yk = pMatY->GetDouble(k);
2297 pE->PutDouble( pE->GetDouble(M+1)+Yk*Yk, M+1 );
2298 double sumYk = pQ->GetDouble(0, M+1) + Yk;
2299 pQ->PutDouble( sumYk, 0, M+1 );
2300 pE->PutDouble( sumYk, 0 );
2301 for (i = 0; i < M; i++)
2303 double Xik = pMatX->GetDouble(i,k);
2304 double sumXik = pQ->GetDouble(0, i+1) + Xik;
2305 pQ->PutDouble( sumXik, 0, i+1);
2306 pQ->PutDouble( sumXik, i+1, 0);
2307 double sumXikYk = pQ->GetDouble(i+1, M+1) + Xik * Yk;
2308 pQ->PutDouble( sumXikYk, i+1, M+1);
2309 pE->PutDouble( sumXikYk, i+1);
2310 for (j = i; j < M; j++)
2312 const double fVal = pMatX->GetDouble(j,k);
2313 double sumXikXjk = pQ->GetDouble(j+1, i+1) +
2314 Xik * fVal;
2315 pQ->PutDouble( sumXikXjk, j+1, i+1);
2316 pQ->PutDouble( sumXikXjk, i+1, j+1);
2321 else
2323 for (k = 0; k < N; k++)
2325 double Yk = pMatY->GetDouble(k);
2326 pE->PutDouble( pE->GetDouble(M+1)+Yk*Yk, M+1 );
2327 double sumYk = pQ->GetDouble(0, M+1) + Yk;
2328 pQ->PutDouble( sumYk, 0, M+1 );
2329 pE->PutDouble( sumYk, 0 );
2330 for (i = 0; i < M; i++)
2332 double Xki = pMatX->GetDouble(k,i);
2333 double sumXki = pQ->GetDouble(0, i+1) + Xki;
2334 pQ->PutDouble( sumXki, 0, i+1);
2335 pQ->PutDouble( sumXki, i+1, 0);
2336 double sumXkiYk = pQ->GetDouble(i+1, M+1) + Xki * Yk;
2337 pQ->PutDouble( sumXkiYk, i+1, M+1);
2338 pE->PutDouble( sumXkiYk, i+1);
2339 for (j = i; j < M; j++)
2341 const double fVal = pMatX->GetDouble(k,j);
2342 double sumXkiXkj = pQ->GetDouble(j+1, i+1) +
2343 Xki * fVal;
2344 pQ->PutDouble( sumXkiXkj, j+1, i+1);
2345 pQ->PutDouble( sumXkiXkj, i+1, j+1);
2350 if ( !Calculate4(_bRKP,pResMat,pQ,bConstant,N,M) )
2351 return;
2353 if (bStats)
2354 Calculate(pResMat,pE,pQ,pV,pMatX,bConstant,N,M,nCase);
2356 PushMatrix(pResMat);
2359 void ScInterpreter::ScRKP()
2361 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRKP" );
2362 CalulateRGPRKP(TRUE);
2364 // -----------------------------------------------------------------------------
2365 bool ScInterpreter::Calculate4(BOOL _bExp,ScMatrixRef& pResMat,ScMatrixRef& pQ,BOOL bConstant,SCSIZE N,SCSIZE M)
2367 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Calculate4" );
2368 pQ->PutDouble((double)N, 0, 0);
2369 if (bConstant)
2371 SCSIZE S, L;
2372 for (S = 0; S < M+1; S++)
2374 SCSIZE i = S;
2375 while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
2376 i++;
2377 if (i >= M+1)
2379 PushNoValue();
2380 return false;
2382 double fVal;
2383 for (L = 0; L < M+2; L++)
2385 fVal = pQ->GetDouble(S, L);
2386 pQ->PutDouble(pQ->GetDouble(i, L), S, L);
2387 pQ->PutDouble(fVal, i, L);
2389 fVal = 1.0/pQ->GetDouble(S, S);
2390 for (L = 0; L < M+2; L++)
2391 pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
2392 for (i = 0; i < M+1; i++)
2394 if (i != S)
2396 fVal = -pQ->GetDouble(i, S);
2397 for (L = 0; L < M+2; L++)
2398 pQ->PutDouble(
2399 pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
2404 else
2406 if ( !Calculate3(M,pQ) )
2407 return false;
2410 for (SCSIZE i = 0; i < M+1; i++)
2412 const double d = pQ->GetDouble(M-i,M+1);
2413 pResMat->PutDouble(_bExp ? exp(d) : d, i, 0);
2414 } // for (SCSIZE i = 0; i < M+1; i++)
2415 return true;
2418 ScMatrixRef ScInterpreter::Calculate2(const BOOL bConstant,const SCSIZE M ,const SCSIZE N,ScMatrixRef& pMatX,ScMatrixRef& pMatY,BYTE nCase)
2420 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Calculate2" );
2421 SCSIZE i, j, k;
2422 ScMatrixRef pQ = GetNewMat(M+1, M+2);
2423 ScMatrixRef pE = GetNewMat(M+2, 1);
2424 pE->PutDouble(0.0, M+1);
2425 pQ->FillDouble(0.0, 0, 0, M, M+1);
2426 if (nCase == 2)
2428 for (k = 0; k < N; k++)
2430 pE->PutDouble(
2431 pE->GetDouble(M+1)+pMatY->GetDouble(k)*pMatY->GetDouble(k), M+1);
2432 pQ->PutDouble(pQ->GetDouble(0, M+1) + pMatY->GetDouble(k), 0, M+1);
2433 pE->PutDouble(pQ->GetDouble(0, M+1), 0);
2434 for (i = 0; i < M; i++)
2436 pQ->PutDouble(pQ->GetDouble(0, i+1)+pMatX->GetDouble(i,k), 0, i+1);
2437 pQ->PutDouble(pQ->GetDouble(0, i+1), i+1, 0);
2438 pQ->PutDouble(pQ->GetDouble(i+1, M+1) +
2439 pMatX->GetDouble(i,k)*pMatY->GetDouble(k), i+1, M+1);
2440 pE->PutDouble(pQ->GetDouble(i+1, M+1), i+1);
2441 for (j = i; j < M; j++)
2443 pQ->PutDouble(pQ->GetDouble(j+1, i+1) +
2444 pMatX->GetDouble(i,k)*pMatX->GetDouble(j,k), j+1, i+1);
2445 pQ->PutDouble(pQ->GetDouble(j+1, i+1), i+1, j+1);
2450 else
2452 for (k = 0; k < N; k++)
2454 pE->PutDouble(
2455 pE->GetDouble(M+1)+pMatY->GetDouble(k)*pMatY->GetDouble(k), M+1);
2456 pQ->PutDouble(pQ->GetDouble(0, M+1) + pMatY->GetDouble(k), 0, M+1);
2457 pE->PutDouble(pQ->GetDouble(0, M+1), 0);
2458 for (i = 0; i < M; i++)
2460 pQ->PutDouble(pQ->GetDouble(0, i+1)+pMatX->GetDouble(k,i), 0, i+1);
2461 pQ->PutDouble(pQ->GetDouble(0, i+1), i+1, 0);
2462 pQ->PutDouble(pQ->GetDouble(i+1, M+1) +
2463 pMatX->GetDouble(k,i)*pMatY->GetDouble(k), i+1, M+1);
2464 pE->PutDouble(pQ->GetDouble(i+1, M+1), i+1);
2465 for (j = i; j < M; j++)
2467 pQ->PutDouble(pQ->GetDouble(j+1, i+1) +
2468 pMatX->GetDouble(k, i)*pMatX->GetDouble(k, j), j+1, i+1);
2469 pQ->PutDouble(pQ->GetDouble(j+1, i+1), i+1, j+1);
2474 pQ->PutDouble((double)N, 0, 0);
2475 if (bConstant)
2477 SCSIZE S, L;
2478 for (S = 0; S < M+1; S++)
2480 i = S;
2481 while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
2482 i++;
2483 if (i >= M+1)
2485 PushNoValue();
2486 return ScMatrixRef();
2488 double fVal;
2489 for (L = 0; L < M+2; L++)
2491 fVal = pQ->GetDouble(S, L);
2492 pQ->PutDouble(pQ->GetDouble(i, L), S, L);
2493 pQ->PutDouble(fVal, i, L);
2495 fVal = 1.0/pQ->GetDouble(S, S);
2496 for (L = 0; L < M+2; L++)
2497 pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
2498 for (i = 0; i < M+1; i++)
2500 if (i != S)
2502 fVal = -pQ->GetDouble(i, S);
2503 for (L = 0; L < M+2; L++)
2504 pQ->PutDouble(
2505 pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
2510 else
2512 if ( !Calculate3(M,pQ) )
2513 return ScMatrixRef();
2515 return pQ;
2517 bool ScInterpreter::Calculate3(const SCSIZE M ,ScMatrixRef& pQ)
2519 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Calculate3" );
2520 SCSIZE S, L;
2521 for (S = 1; S < M+1; S++)
2523 SCSIZE i = S;
2524 while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
2525 i++;
2526 if (i >= M+1)
2528 PushNoValue();
2529 return ScMatrixRef();
2531 double fVal;
2532 for (L = 1; L < M+2; L++)
2534 fVal = pQ->GetDouble(S, L);
2535 pQ->PutDouble(pQ->GetDouble(i, L), S, L);
2536 pQ->PutDouble(fVal, i, L);
2538 fVal = 1.0/pQ->GetDouble(S, S);
2539 for (L = 1; L < M+2; L++)
2540 pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
2541 for (i = 1; i < M+1; i++)
2543 if (i != S)
2545 fVal = -pQ->GetDouble(i, S);
2546 for (L = 1; L < M+2; L++)
2547 pQ->PutDouble(
2548 pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
2551 pQ->PutDouble(0.0, 0, M+1);
2552 } // for (S = 1; S < M+1; S++)
2553 return true;
2556 void ScInterpreter::ScTrend()
2558 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTrend" );
2559 CalculateTrendGrowth(FALSE);
2561 void ScInterpreter::CalculateTrendGrowth(BOOL _bGrowth)
2563 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateTrendGrowth" );
2564 BYTE nParamCount = GetByte();
2565 if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
2566 return;
2567 BOOL bConstant;
2568 if (nParamCount == 4)
2569 bConstant = GetBool();
2570 else
2571 bConstant = TRUE;
2572 ScMatrixRef pMatX;
2573 ScMatrixRef pMatY;
2574 ScMatrixRef pMatNewX;
2575 if (nParamCount >= 3)
2576 pMatNewX = GetMatrix();
2577 else
2578 pMatNewX = NULL;
2579 if (nParamCount >= 2)
2580 pMatX = GetMatrix();
2581 else
2582 pMatX = NULL;
2583 pMatY = GetMatrix();
2584 if (!pMatY)
2586 PushIllegalParameter();
2587 return;
2588 } // if (!pMatY)
2590 BYTE nCase; // 1 = normal, 2,3 = mehrfach
2591 SCSIZE nCX, nCY;
2592 SCSIZE nRX, nRY;
2593 SCSIZE M = 0, N = 0;
2594 if ( !CheckMatrix(_bGrowth,TRUE,nCase,nCX,nCY,nRX,nRY,M,N,pMatX,pMatY) )
2595 return;
2598 SCSIZE nCXN, nRXN;
2599 SCSIZE nCountXN;
2600 if (!pMatNewX)
2602 nCXN = nCX;
2603 nRXN = nRX;
2604 nCountXN = nCXN * nRXN;
2605 pMatNewX = pMatX;
2607 else
2609 pMatNewX->GetDimensions(nCXN, nRXN);
2610 if ((nCase == 2 && nCX != nCXN) || (nCase == 3 && nRX != nRXN))
2612 PushIllegalArgument();
2613 return;
2615 nCountXN = nCXN * nRXN;
2616 for ( SCSIZE i = 0; i < nCountXN; i++ )
2617 if (!pMatNewX->IsValue(i))
2619 PushIllegalArgument();
2620 return;
2623 ScMatrixRef pResMat;
2624 if (nCase == 1)
2626 double fCount = 0.0;
2627 double fSumX = 0.0;
2628 double fSumSqrX = 0.0;
2629 double fSumY = 0.0;
2630 double fSumSqrY = 0.0;
2631 double fSumXY = 0.0;
2632 double fValX, fValY;
2633 SCSIZE i;
2634 for (i = 0; i < nCY; i++)
2635 for (SCSIZE j = 0; j < nRY; j++)
2637 fValX = pMatX->GetDouble(i,j);
2638 fValY = pMatY->GetDouble(i,j);
2639 fSumX += fValX;
2640 fSumSqrX += fValX * fValX;
2641 fSumY += fValY;
2642 fSumSqrY += fValY * fValY;
2643 fSumXY += fValX*fValY;
2644 fCount++;
2646 if (fCount < 1.0)
2648 PushNoValue();
2649 return;
2651 else
2653 double f1 = fCount*fSumXY-fSumX*fSumY;
2654 double fX = fCount*fSumSqrX-fSumX*fSumX;
2655 double b, m;
2656 if (bConstant)
2658 b = fSumY/fCount - f1/fX*fSumX/fCount;
2659 m = f1/fX;
2661 else
2663 b = 0.0;
2664 m = fSumXY/fSumSqrX;
2666 pResMat = GetNewMat(nCXN, nRXN);
2667 if (!pResMat)
2669 PushIllegalArgument();
2670 return;
2672 for (i = 0; i < nCountXN; i++)
2674 const double d = pMatNewX->GetDouble(i)*m+b;
2675 pResMat->PutDouble(_bGrowth ? exp(d) : d, i);
2679 else
2681 ScMatrixRef pQ = Calculate2(bConstant,M ,N,pMatX,pMatY,nCase);
2682 if ( !pQ.Is() )
2683 return;
2684 if (nCase == 2)
2686 pResMat = GetNewMat(1, nRXN);
2687 if (!pResMat)
2689 PushIllegalArgument();
2690 return;
2692 double fVal;
2693 for (SCSIZE i = 0; i < nRXN; i++)
2695 fVal = pQ->GetDouble(0, M+1);
2696 for (SCSIZE j = 0; j < M; j++)
2697 fVal += pQ->GetDouble(j+1, M+1)*pMatNewX->GetDouble(j, i);
2698 pResMat->PutDouble(_bGrowth ? exp(fVal) : fVal, i);
2701 else
2703 pResMat = GetNewMat(nCXN, 1);
2704 if (!pResMat)
2706 PushIllegalArgument();
2707 return;
2709 double fVal;
2710 for (SCSIZE i = 0; i < nCXN; i++)
2712 fVal = pQ->GetDouble(0, M+1);
2713 for (SCSIZE j = 0; j < M; j++)
2714 fVal += pQ->GetDouble(j+1, M+1)*pMatNewX->GetDouble(i, j);
2715 pResMat->PutDouble(_bGrowth ? exp(fVal) : fVal, i);
2719 PushMatrix(pResMat);
2722 void ScInterpreter::ScGrowth()
2724 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGrowth" );
2725 CalculateTrendGrowth(TRUE);
2728 void ScInterpreter::ScMatRef()
2730 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatRef" );
2731 // Falls Deltarefs drin sind...
2732 Push( (FormulaToken&)*pCur );
2733 ScAddress aAdr;
2734 PopSingleRef( aAdr );
2735 ScFormulaCell* pCell = (ScFormulaCell*) GetCell( aAdr );
2736 if( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
2738 const ScMatrix* pMat = pCell->GetMatrix();
2739 if( pMat )
2741 SCSIZE nCols, nRows;
2742 pMat->GetDimensions( nCols, nRows );
2743 SCSIZE nC = static_cast<SCSIZE>(aPos.Col() - aAdr.Col());
2744 SCSIZE nR = static_cast<SCSIZE>(aPos.Row() - aAdr.Row());
2745 if ((nCols <= nC && nCols != 1) || (nRows <= nR && nRows != 1))
2746 PushNA();
2747 else
2749 ScMatValType nMatValType;
2750 const ScMatrixValue* pMatVal = pMat->Get( nC, nR, nMatValType);
2751 if (ScMatrix::IsNonValueType( nMatValType))
2753 if (ScMatrix::IsEmptyPathType( nMatValType))
2754 { // result of empty FALSE jump path
2755 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2756 PushInt(0);
2758 else if (ScMatrix::IsEmptyType( nMatValType))
2760 // Not inherited (really?) and display as empty string, not 0.
2761 PushTempToken( new ScEmptyCellToken( false, true));
2763 else
2764 PushString( pMatVal->GetString() );
2766 else
2768 PushDouble(pMatVal->fVal); // handles DoubleError
2769 pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex, aAdr, pCell );
2770 nFuncFmtType = nCurFmtType;
2771 nFuncFmtIndex = nCurFmtIndex;
2775 else
2777 // If not a result matrix, obtain the cell value.
2778 USHORT nErr = pCell->GetErrCode();
2779 if (nErr)
2780 PushError( nErr );
2781 else if( pCell->IsValue() )
2782 PushDouble( pCell->GetValue() );
2783 else
2785 String aVal;
2786 pCell->GetString( aVal );
2787 PushString( aVal );
2789 pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex, aAdr, pCell );
2790 nFuncFmtType = nCurFmtType;
2791 nFuncFmtIndex = nCurFmtIndex;
2794 else
2795 PushError( errNoRef );
2798 void ScInterpreter::ScInfo()
2800 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInfo" );
2801 if( MustHaveParamCount( GetByte(), 1 ) )
2803 String aStr = GetString();
2804 ScCellKeywordTranslator::transKeyword(aStr, ScGlobal::GetLocale(), ocInfo);
2805 if( aStr.EqualsAscii( "SYSTEM" ) )
2806 PushString( String( RTL_CONSTASCII_USTRINGPARAM( SC_INFO_OSVERSION ) ) );
2807 else if( aStr.EqualsAscii( "OSVERSION" ) )
2808 PushString( String( RTL_CONSTASCII_USTRINGPARAM( "Windows (32-bit) NT 5.01" ) ) );
2809 else if( aStr.EqualsAscii( "RELEASE" ) )
2810 PushString( ::utl::Bootstrap::getBuildIdData( ::rtl::OUString() ) );
2811 else if( aStr.EqualsAscii( "NUMFILE" ) )
2812 PushDouble( 1 );
2813 else if( aStr.EqualsAscii( "RECALC" ) )
2814 PushString( ScGlobal::GetRscString( pDok->GetAutoCalc() ? STR_RECALC_AUTO : STR_RECALC_MANUAL ) );
2815 else
2816 PushIllegalArgument();