update dev300-m58
[ooovba.git] / sc / source / core / tool / interpr5.cxx
blob9417c0e30738dc6224c202701d8fb583ba29403b
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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "ScInterpreter::ScAdd" );
1175 CalculateAddSub(FALSE);
1177 void ScInterpreter::CalculateAddSub(BOOL _bSub)
1179 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "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(true, true);
1193 if (nGlobalError)
1195 PushError(nGlobalError);
1196 return;
1198 switch ( nCurFmtType )
1200 case NUMBERFORMAT_DATE :
1201 case NUMBERFORMAT_TIME :
1202 case NUMBERFORMAT_DATETIME :
1203 nFmt2 = nCurFmtType;
1204 break;
1205 case NUMBERFORMAT_CURRENCY :
1206 nFmtCurrencyType = nCurFmtType;
1207 nFmtCurrencyIndex = nCurFmtIndex;
1208 break;
1209 case NUMBERFORMAT_PERCENT :
1210 nFmtPercentType = NUMBERFORMAT_PERCENT;
1211 break;
1214 if ( GetStackType() == svMatrix )
1215 pMat1 = GetMatrix();
1216 else
1218 fVal1 = GetDouble(true, true);
1219 if (nGlobalError)
1221 PushError(nGlobalError);
1222 return;
1224 switch ( nCurFmtType )
1226 case NUMBERFORMAT_DATE :
1227 case NUMBERFORMAT_TIME :
1228 case NUMBERFORMAT_DATETIME :
1229 nFmt1 = nCurFmtType;
1230 break;
1231 case NUMBERFORMAT_CURRENCY :
1232 nFmtCurrencyType = nCurFmtType;
1233 nFmtCurrencyIndex = nCurFmtIndex;
1234 break;
1235 case NUMBERFORMAT_PERCENT :
1236 nFmtPercentType = NUMBERFORMAT_PERCENT;
1237 break;
1240 if (pMat1 && pMat2)
1242 ScMatrixRef pResMat;
1243 if ( _bSub )
1245 MatrixSub aSub;
1246 pResMat = lcl_MatrixCalculation(aSub ,pMat1, pMat2,this);
1248 else
1250 MatrixAdd aAdd;
1251 pResMat = lcl_MatrixCalculation(aAdd ,pMat1, pMat2,this);
1254 if (!pResMat)
1255 PushNoValue();
1256 else
1257 PushMatrix(pResMat);
1259 else if (pMat1 || pMat2)
1261 double fVal;
1262 BOOL bFlag;
1263 ScMatrixRef pMat = pMat1;
1264 if (!pMat)
1266 fVal = fVal1;
1267 pMat = pMat2;
1268 bFlag = TRUE; // double - Matrix
1270 else
1272 fVal = fVal2;
1273 bFlag = FALSE; // Matrix - double
1275 SCSIZE nC, nR;
1276 pMat->GetDimensions(nC, nR);
1277 ScMatrixRef pResMat = GetNewMat(nC, nR);
1278 if (pResMat)
1280 SCSIZE nCount = nC * nR;
1281 if (bFlag || !_bSub )
1283 for ( SCSIZE i = 0; i < nCount; i++ )
1285 if (pMat->IsValue(i))
1286 pResMat->PutDouble( _bSub ? ::rtl::math::approxSub( fVal, pMat->GetDouble(i)) : ::rtl::math::approxAdd( pMat->GetDouble(i), fVal), i);
1287 else
1288 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1289 } // for ( SCSIZE i = 0; i < nCount; i++ )
1290 } // if (bFlag || !_bSub )
1291 else
1293 for ( SCSIZE i = 0; i < nCount; i++ )
1294 { if (pMat->IsValue(i))
1295 pResMat->PutDouble( ::rtl::math::approxSub( pMat->GetDouble(i), fVal), i);
1296 else
1297 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1298 } // for ( SCSIZE i = 0; i < nCount; i++ )
1300 PushMatrix(pResMat);
1302 else
1303 PushIllegalArgument();
1305 else if ( _bSub )
1306 PushDouble( ::rtl::math::approxSub( fVal1, fVal2 ) );
1307 else
1308 PushDouble( ::rtl::math::approxAdd( fVal1, fVal2 ) );
1309 if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY )
1311 nFuncFmtType = nFmtCurrencyType;
1312 nFuncFmtIndex = nFmtCurrencyIndex;
1314 else
1316 lcl_GetDiffDateTimeFmtType( nFuncFmtType, nFmt1, nFmt2 );
1317 if ( nFmtPercentType == NUMBERFORMAT_PERCENT && nFuncFmtType == NUMBERFORMAT_NUMBER )
1318 nFuncFmtType = NUMBERFORMAT_PERCENT;
1322 void ScInterpreter::ScAmpersand()
1324 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAmpersand" );
1325 ScMatrixRef pMat1 = NULL;
1326 ScMatrixRef pMat2 = NULL;
1327 String sStr1, sStr2;
1328 if ( GetStackType() == svMatrix )
1329 pMat2 = GetMatrix();
1330 else
1331 sStr2 = GetString();
1332 if ( GetStackType() == svMatrix )
1333 pMat1 = GetMatrix();
1334 else
1335 sStr1 = GetString();
1336 if (pMat1 && pMat2)
1338 ScMatrixRef pResMat = MatConcat(pMat1, pMat2);
1339 if (!pResMat)
1340 PushNoValue();
1341 else
1342 PushMatrix(pResMat);
1344 else if (pMat1 || pMat2)
1346 String sStr;
1347 BOOL bFlag;
1348 ScMatrixRef pMat = pMat1;
1349 if (!pMat)
1351 sStr = sStr1;
1352 pMat = pMat2;
1353 bFlag = TRUE; // double - Matrix
1355 else
1357 sStr = sStr2;
1358 bFlag = FALSE; // Matrix - double
1360 SCSIZE nC, nR;
1361 pMat->GetDimensions(nC, nR);
1362 ScMatrixRef pResMat = GetNewMat(nC, nR);
1363 if (pResMat)
1365 SCSIZE nCount = nC * nR;
1366 if (nGlobalError)
1368 for ( SCSIZE i = 0; i < nCount; i++ )
1369 pResMat->PutError( nGlobalError, i);
1371 else if (bFlag)
1373 for ( SCSIZE i = 0; i < nCount; i++ )
1375 USHORT nErr = pMat->GetErrorIfNotString( i);
1376 if (nErr)
1377 pResMat->PutError( nErr, i);
1378 else
1380 String aTmp( sStr);
1381 aTmp += pMat->GetString( *pFormatter, i);
1382 pResMat->PutString( aTmp, i);
1386 else
1388 for ( SCSIZE i = 0; i < nCount; i++ )
1390 USHORT nErr = pMat->GetErrorIfNotString( i);
1391 if (nErr)
1392 pResMat->PutError( nErr, i);
1393 else
1395 String aTmp( pMat->GetString( *pFormatter, i));
1396 aTmp += sStr;
1397 pResMat->PutString( aTmp, i);
1401 PushMatrix(pResMat);
1403 else
1404 PushIllegalArgument();
1406 else
1408 if ( CheckStringResultLen( sStr1, sStr2 ) )
1409 sStr1 += sStr2;
1410 PushString(sStr1);
1414 void ScInterpreter::ScSub()
1416 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSub" );
1417 CalculateAddSub(TRUE);
1420 void ScInterpreter::ScMul()
1422 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMul" );
1423 ScMatrixRef pMat1 = NULL;
1424 ScMatrixRef pMat2 = NULL;
1425 double fVal1 = 0.0, fVal2 = 0.0;
1426 short nFmtCurrencyType = nCurFmtType;
1427 ULONG nFmtCurrencyIndex = nCurFmtIndex;
1428 if ( GetStackType() == svMatrix )
1429 pMat2 = GetMatrix();
1430 else
1432 fVal2 = GetDouble(true, true);
1433 if (nGlobalError)
1435 PushError(nGlobalError);
1436 return;
1438 switch ( nCurFmtType )
1440 case NUMBERFORMAT_CURRENCY :
1441 nFmtCurrencyType = nCurFmtType;
1442 nFmtCurrencyIndex = nCurFmtIndex;
1443 break;
1446 if ( GetStackType() == svMatrix )
1447 pMat1 = GetMatrix();
1448 else
1450 fVal1 = GetDouble(true, true);
1451 if (nGlobalError)
1453 PushError(nGlobalError);
1454 return;
1456 switch ( nCurFmtType )
1458 case NUMBERFORMAT_CURRENCY :
1459 nFmtCurrencyType = nCurFmtType;
1460 nFmtCurrencyIndex = nCurFmtIndex;
1461 break;
1464 if (pMat1 && pMat2)
1466 MatrixMul aMul;
1467 ScMatrixRef pResMat = lcl_MatrixCalculation(aMul,pMat1, pMat2,this);
1468 if (!pResMat)
1469 PushNoValue();
1470 else
1471 PushMatrix(pResMat);
1473 else if (pMat1 || pMat2)
1475 double fVal;
1476 ScMatrixRef pMat = pMat1;
1477 if (!pMat)
1479 fVal = fVal1;
1480 pMat = pMat2;
1482 else
1483 fVal = fVal2;
1484 SCSIZE nC, nR;
1485 pMat->GetDimensions(nC, nR);
1486 ScMatrixRef pResMat = GetNewMat(nC, nR);
1487 if (pResMat)
1489 SCSIZE nCount = nC * nR;
1490 for ( SCSIZE i = 0; i < nCount; i++ )
1491 if (pMat->IsValue(i))
1492 pResMat->PutDouble(pMat->GetDouble(i)*fVal, i);
1493 else
1494 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1495 PushMatrix(pResMat);
1497 else
1498 PushIllegalArgument();
1500 else
1501 PushDouble(fVal1 * fVal2);
1502 if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY )
1504 nFuncFmtType = nFmtCurrencyType;
1505 nFuncFmtIndex = nFmtCurrencyIndex;
1509 void ScInterpreter::ScDiv()
1511 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDiv" );
1512 ScMatrixRef pMat1 = NULL;
1513 ScMatrixRef pMat2 = NULL;
1514 double fVal1 = 0.0, fVal2 = 0.0;
1515 short nFmtCurrencyType = nCurFmtType;
1516 ULONG nFmtCurrencyIndex = nCurFmtIndex;
1517 short nFmtCurrencyType2 = NUMBERFORMAT_UNDEFINED;
1518 if ( GetStackType() == svMatrix )
1519 pMat2 = GetMatrix();
1520 else
1522 fVal2 = GetDouble(true, true);
1523 if (nGlobalError)
1525 PushError(nGlobalError);
1526 return;
1528 // hier kein Currency uebernehmen, 123kg/456DM sind nicht DM
1529 nFmtCurrencyType2 = nCurFmtType;
1531 if ( GetStackType() == svMatrix )
1532 pMat1 = GetMatrix();
1533 else
1535 fVal1 = GetDouble(true, true);
1536 if (nGlobalError)
1538 PushError(nGlobalError);
1539 return;
1541 switch ( nCurFmtType )
1543 case NUMBERFORMAT_CURRENCY :
1544 nFmtCurrencyType = nCurFmtType;
1545 nFmtCurrencyIndex = nCurFmtIndex;
1546 break;
1549 if (pMat1 && pMat2)
1551 MatrixDiv aDiv;
1552 ScMatrixRef pResMat = lcl_MatrixCalculation(aDiv,pMat1, pMat2,this);
1553 if (!pResMat)
1554 PushNoValue();
1555 else
1556 PushMatrix(pResMat);
1558 else if (pMat1 || pMat2)
1560 double fVal;
1561 BOOL bFlag;
1562 ScMatrixRef pMat = pMat1;
1563 if (!pMat)
1565 fVal = fVal1;
1566 pMat = pMat2;
1567 bFlag = TRUE; // double - Matrix
1569 else
1571 fVal = fVal2;
1572 bFlag = FALSE; // Matrix - double
1574 SCSIZE nC, nR;
1575 pMat->GetDimensions(nC, nR);
1576 ScMatrixRef pResMat = GetNewMat(nC, nR);
1577 if (pResMat)
1579 SCSIZE nCount = nC * nR;
1580 if (bFlag)
1581 { for ( SCSIZE i = 0; i < nCount; i++ )
1582 if (pMat->IsValue(i))
1583 pResMat->PutDouble( div( fVal, pMat->GetDouble(i)), i);
1584 else
1585 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1587 else
1588 { for ( SCSIZE i = 0; i < nCount; i++ )
1589 if (pMat->IsValue(i))
1590 pResMat->PutDouble( div( pMat->GetDouble(i), fVal), i);
1591 else
1592 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1594 PushMatrix(pResMat);
1596 else
1597 PushIllegalArgument();
1599 else
1601 PushDouble( div( fVal1, fVal2) );
1603 if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY && nFmtCurrencyType2 != NUMBERFORMAT_CURRENCY )
1604 { // auch DM/DM ist nicht DM bzw. DEM/EUR nicht DEM
1605 nFuncFmtType = nFmtCurrencyType;
1606 nFuncFmtIndex = nFmtCurrencyIndex;
1610 void ScInterpreter::ScPower()
1612 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPower" );
1613 if ( MustHaveParamCount( GetByte(), 2 ) )
1614 ScPow();
1617 void ScInterpreter::ScPow()
1619 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPow" );
1620 ScMatrixRef pMat1 = NULL;
1621 ScMatrixRef pMat2 = NULL;
1622 double fVal1 = 0.0, fVal2 = 0.0;
1623 if ( GetStackType() == svMatrix )
1624 pMat2 = GetMatrix();
1625 else
1626 fVal2 = GetDouble();
1627 if ( GetStackType() == svMatrix )
1628 pMat1 = GetMatrix();
1629 else
1630 fVal1 = GetDouble();
1631 if (pMat1 && pMat2)
1633 MatrixPow aPow;
1634 ScMatrixRef pResMat = lcl_MatrixCalculation(aPow,pMat1, pMat2,this);
1635 if (!pResMat)
1636 PushNoValue();
1637 else
1638 PushMatrix(pResMat);
1640 else if (pMat1 || pMat2)
1642 double fVal;
1643 BOOL bFlag;
1644 ScMatrixRef pMat = pMat1;
1645 if (!pMat)
1647 fVal = fVal1;
1648 pMat = pMat2;
1649 bFlag = TRUE; // double - Matrix
1651 else
1653 fVal = fVal2;
1654 bFlag = FALSE; // Matrix - double
1656 SCSIZE nC, nR;
1657 pMat->GetDimensions(nC, nR);
1658 ScMatrixRef pResMat = GetNewMat(nC, nR);
1659 if (pResMat)
1661 SCSIZE nCount = nC * nR;
1662 if (bFlag)
1663 { for ( SCSIZE i = 0; i < nCount; i++ )
1664 if (pMat->IsValue(i))
1665 pResMat->PutDouble(pow(fVal,pMat->GetDouble(i)), i);
1666 else
1667 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1669 else
1670 { for ( SCSIZE i = 0; i < nCount; i++ )
1671 if (pMat->IsValue(i))
1672 pResMat->PutDouble(pow(pMat->GetDouble(i),fVal), i);
1673 else
1674 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
1676 PushMatrix(pResMat);
1678 else
1679 PushIllegalArgument();
1681 else
1682 PushDouble(pow(fVal1,fVal2));
1685 void ScInterpreter::ScSumProduct()
1687 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSumProduct" );
1688 BYTE nParamCount = GetByte();
1689 if ( !MustHaveParamCount( nParamCount, 1, 30 ) )
1690 return;
1692 ScMatrixRef pMat1 = NULL;
1693 ScMatrixRef pMat2 = NULL;
1694 ScMatrixRef pMat = NULL;
1695 pMat2 = GetMatrix();
1696 if (!pMat2)
1698 PushIllegalParameter();
1699 return;
1701 SCSIZE nC, nC1;
1702 SCSIZE nR, nR1;
1703 pMat2->GetDimensions(nC, nR);
1704 pMat = pMat2;
1705 MatrixMul aMul;
1706 for (USHORT i = 1; i < nParamCount; i++)
1708 pMat1 = GetMatrix();
1709 if (!pMat1)
1711 PushIllegalParameter();
1712 return;
1714 pMat1->GetDimensions(nC1, nR1);
1715 if (nC1 != nC || nR1 != nR)
1717 PushNoValue();
1718 return;
1720 ScMatrixRef pResMat = lcl_MatrixCalculation(aMul,pMat1, pMat,this);
1721 if (!pResMat)
1723 PushNoValue();
1724 return;
1726 else
1727 pMat = pResMat;
1729 double fSum = 0.0;
1730 SCSIZE nCount = pMat->GetElementCount();
1731 for (SCSIZE j = 0; j < nCount; j++)
1733 if (!pMat->IsString(j))
1734 fSum += pMat->GetDouble(j);
1736 PushDouble(fSum);
1739 void ScInterpreter::ScSumX2MY2()
1741 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSumX2MY2" );
1742 CalculateSumX2MY2SumX2DY2(FALSE);
1744 void ScInterpreter::CalculateSumX2MY2SumX2DY2(BOOL _bSumX2DY2)
1746 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateSumX2MY2SumX2DY2" );
1747 if ( !MustHaveParamCount( GetByte(), 2 ) )
1748 return;
1750 ScMatrixRef pMat1 = NULL;
1751 ScMatrixRef pMat2 = NULL;
1752 SCSIZE i, j;
1753 pMat2 = GetMatrix();
1754 pMat1 = GetMatrix();
1755 if (!pMat2 || !pMat1)
1757 PushIllegalParameter();
1758 return;
1760 SCSIZE nC1, nC2;
1761 SCSIZE nR1, nR2;
1762 pMat2->GetDimensions(nC2, nR2);
1763 pMat1->GetDimensions(nC1, nR1);
1764 if (nC1 != nC2 || nR1 != nR2)
1766 PushNoValue();
1767 return;
1769 double fVal, fSum = 0.0;
1770 for (i = 0; i < nC1; i++)
1771 for (j = 0; j < nR1; j++)
1772 if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
1774 fVal = pMat1->GetDouble(i,j);
1775 fSum += fVal * fVal;
1776 fVal = pMat2->GetDouble(i,j);
1777 if ( _bSumX2DY2 )
1778 fSum += fVal * fVal;
1779 else
1780 fSum -= fVal * fVal;
1782 PushDouble(fSum);
1785 void ScInterpreter::ScSumX2DY2()
1787 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSumX2DY2" );
1788 CalculateSumX2MY2SumX2DY2(TRUE);
1791 void ScInterpreter::ScSumXMY2()
1793 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSumXMY2" );
1794 if ( !MustHaveParamCount( GetByte(), 2 ) )
1795 return;
1797 ScMatrixRef pMat1 = NULL;
1798 ScMatrixRef pMat2 = NULL;
1799 pMat2 = GetMatrix();
1800 pMat1 = GetMatrix();
1801 if (!pMat2 || !pMat1)
1803 PushIllegalParameter();
1804 return;
1806 SCSIZE nC1, nC2;
1807 SCSIZE nR1, nR2;
1808 pMat2->GetDimensions(nC2, nR2);
1809 pMat1->GetDimensions(nC1, nR1);
1810 if (nC1 != nC2 || nR1 != nR2)
1812 PushNoValue();
1813 return;
1814 } // if (nC1 != nC2 || nR1 != nR2)
1815 MatrixSub aSub;
1816 ScMatrixRef pResMat = lcl_MatrixCalculation(aSub,pMat1, pMat2,this);
1817 if (!pResMat)
1819 PushNoValue();
1821 else
1823 double fVal, fSum = 0.0;
1824 SCSIZE nCount = pResMat->GetElementCount();
1825 for (SCSIZE i = 0; i < nCount; i++)
1826 if (!pResMat->IsString(i))
1828 fVal = pResMat->GetDouble(i);
1829 fSum += fVal * fVal;
1831 PushDouble(fSum);
1835 void ScInterpreter::ScFrequency()
1837 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFrequency" );
1838 if ( !MustHaveParamCount( GetByte(), 2 ) )
1839 return;
1841 vector<double> aBinArray;
1842 vector<long> aBinIndexOrder;
1844 GetSortArray(1, aBinArray, &aBinIndexOrder);
1845 SCSIZE nBinSize = aBinArray.size();
1846 if (nGlobalError)
1848 PushNoValue();
1849 return;
1852 vector<double> aDataArray;
1853 GetSortArray(1, aDataArray);
1854 SCSIZE nDataSize = aDataArray.size();
1856 if (aDataArray.empty() || nGlobalError)
1858 PushNoValue();
1859 return;
1861 ScMatrixRef pResMat = GetNewMat(1, nBinSize+1);
1862 if (!pResMat)
1864 PushIllegalArgument();
1865 return;
1868 if (nBinSize != aBinIndexOrder.size())
1870 PushIllegalArgument();
1871 return;
1874 SCSIZE j;
1875 SCSIZE i = 0;
1876 for (j = 0; j < nBinSize; ++j)
1878 SCSIZE nCount = 0;
1879 while (i < nDataSize && aDataArray[i] <= aBinArray[j])
1881 ++nCount;
1882 ++i;
1884 pResMat->PutDouble(static_cast<double>(nCount), aBinIndexOrder[j]);
1886 pResMat->PutDouble(static_cast<double>(nDataSize-i), j);
1887 PushMatrix(pResMat);
1890 BOOL ScInterpreter::RGetVariances( ScMatrix* pV, ScMatrix* pX,
1891 SCSIZE nC, SCSIZE nR, BOOL bSwapColRow, BOOL bZeroConstant )
1892 { // multiple Regression: Varianzen der Koeffizienten
1893 // bSwapColRow==TRUE : Koeffizienten in Zeilen statt Spalten angeordnet
1894 SCSIZE i, j, k;
1895 double sum;
1896 ScMatrixRef pC = GetNewMat(nC, nC);
1897 if ( !pC )
1898 return FALSE;
1899 // X transformiert mit X multipziert, X'X Matrix
1900 if ( !bZeroConstant )
1901 { // in der X-Designmatrix existiert ein gedachtes X0j==1
1902 if ( bSwapColRow )
1904 for ( i=0; i<nC; i++ )
1906 for ( j=0; j<nC; j++ )
1908 sum = 0.0;
1909 for ( k=0; k<nR; k++ )
1911 sum += (j==0 ? 1 : pX->GetDouble(k,j-1))
1912 * (i==0 ? 1 : pX->GetDouble(k,i-1));
1914 pC->PutDouble(sum, i, j);
1918 else
1920 for ( i=0; i<nC; i++ )
1922 for ( j=0; j<nC; j++ )
1924 sum = 0.0;
1925 for ( k=0; k<nR; k++ )
1927 sum += (j==0 ? 1 : pX->GetDouble(j-1,k))
1928 * (i==0 ? 1 : pX->GetDouble(i-1,k));
1930 pC->PutDouble(sum, i, j);
1935 else
1937 if ( bSwapColRow )
1939 for ( i=0; i<nC; i++ )
1941 for ( j=0; j<nC; j++ )
1943 sum = 0.0;
1944 for ( k=0; k<nR; k++ )
1946 sum += pX->GetDouble(k,j) * pX->GetDouble(k,i);
1948 pC->PutDouble(sum, i, j);
1952 else
1954 for ( i=0; i<nC; i++ )
1956 for ( j=0; j<nC; j++ )
1958 sum = 0.0;
1959 for ( k=0; k<nR; k++ )
1961 sum += pX->GetDouble(j,k) * pX->GetDouble(i,k);
1963 pC->PutDouble(sum, i, j);
1968 // X'X Inverse
1969 BOOL bOk = TRUE;
1970 USHORT nErr = nGlobalError;
1971 PushMatrix(pC);
1972 BYTE nTmp = cPar;
1973 cPar = 1;
1974 ScMatInv();
1975 cPar = nTmp;
1976 if ( nGlobalError )
1978 nGlobalError = nErr;
1979 bOk = FALSE;
1981 else
1983 // #i61216# ScMatInv no longer modifies the original matrix, so just calling Pop() doesn't work
1984 pC = PopMatrix();
1985 if ( pC.Is() )
1987 // Varianzen auf der Diagonalen, andere sind Kovarianzen
1988 for (i = 0; i < nC; i++)
1989 pV->PutDouble(pC->GetDouble(i, i), i);
1992 return bOk;
1994 // -----------------------------------------------------------------------------
1995 void ScInterpreter::Calculate(ScMatrixRef& pResMat,ScMatrixRef& pE,ScMatrixRef& pQ,ScMatrixRef& pV,ScMatrixRef& pMatX,BOOL bConstant,SCSIZE N,SCSIZE M,BYTE nCase)
1997 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::RGetVariances" );
1998 // pE[0] := Sigma i=1...n (Yi)
1999 // pE[k] := Sigma i=1...n (Xki*Yi)
2000 // pE[M+1] := Sigma i=1...n (Yi**2)
2001 // pQ[0,M+1]:= B
2002 // pQ[k,M+1]:= Mk
2003 double fSQR, fSQT, fSQE;
2004 fSQT = pE->GetDouble(M+1)
2005 - pE->GetDouble(0) * pE->GetDouble(0) / (double)N;
2006 fSQR = pE->GetDouble(M+1);
2007 SCSIZE i, j;
2008 for (i = 0; i < M+1; i++)
2009 fSQR -= pQ->GetDouble(i, M+1) * pE->GetDouble(i);
2010 fSQE = fSQT-fSQR;
2011 // r2 (Bestimmtheitsmass, 0...1)
2012 if (fSQT == 0.0)
2013 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 2);
2014 else
2015 pResMat->PutDouble (fSQE/fSQT, 0, 2);
2016 // ssReg (Regressions-Quadratsumme)
2017 pResMat->PutDouble(fSQE, 0, 4);
2018 // ssResid (Residual-Quadratsumme, Summe der Abweichungsquadrate)
2019 pResMat->PutDouble(fSQR, 1, 4);
2020 for (i = 2; i < 5; i++)
2021 for (j = 2; j < M+1; j++)
2022 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), j, i);
2023 if (bConstant)
2025 if (N-M-1 == 0)
2027 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2);
2028 for (i = 0; i < M+1; i++)
2029 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, 1);
2031 else
2033 double fSE2 = fSQR/(N-M-1);
2034 // sey (Standardfehler des Schaetzwertes y)
2035 pResMat->PutDouble(sqrt(fSE2), 1, 2);
2036 // sen...se1 (Standardfehler der Koeffizienten mn...m1)
2037 // seb (Standardfehler der Konstanten b)
2038 if ( RGetVariances( pV, pMatX, M+1, N, nCase != 2, FALSE ) )
2040 for (i = 0; i < M+1; i++)
2041 pResMat->PutDouble( sqrt(fSE2 * pV->GetDouble(i)), M-i, 1 );
2043 else
2045 for (i = 0; i < M+1; i++)
2046 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 1);
2049 // F (F-Statistik)
2050 if (fSQR == 0.0)
2051 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3);
2052 else
2053 pResMat->PutDouble(((double)(N-M-1))*fSQE/fSQR/((double)M),0, 3);
2054 // df (Freiheitsgrad)
2055 pResMat->PutDouble(((double)(N-M-1)), 1, 3);
2057 else
2059 if (N-M == 0)
2061 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2);
2062 for (i = 0; i < M+1; i++)
2063 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, 1);
2065 else
2067 double fSE2 = fSQR/(N-M);
2068 pResMat->PutDouble(sqrt(fSE2), 1, 2);
2069 if ( RGetVariances( pV, pMatX, M, N, nCase != 2, TRUE ) )
2071 for (i = 0; i < M; i++)
2072 pResMat->PutDouble( sqrt(fSE2 * pV->GetDouble(i)), M-i-1, 1 );
2073 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), M, 1);
2075 else
2077 for (i = 0; i < M+1; i++)
2078 pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 1);
2081 if (fSQR == 0.0)
2082 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3);
2083 else
2084 pResMat->PutDouble(((double)(N-M))*fSQE/fSQR/((double)M),0, 3);
2085 pResMat->PutDouble(((double)(N-M)), 1, 3);
2089 void ScInterpreter::ScRGP()
2091 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRGP" );
2092 CalulateRGPRKP(FALSE);
2094 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)
2096 nCX = 0;
2097 nCY = 0;
2098 nRX = 0;
2099 nRY = 0;
2100 M = 0;
2101 N = 0;
2102 pMatY->GetDimensions(nCY, nRY);
2103 const SCSIZE nCountY = nCY * nRY;
2104 for ( SCSIZE i = 0; i < nCountY; i++ )
2106 if (!pMatY->IsValue(i))
2108 PushIllegalArgument();
2109 return false;
2110 } // if (!pMatY->IsValue(i))
2111 } // for ( SCSIZE i = 0; i < nCountY; i++ )
2112 if ( _bLOG )
2114 for (SCSIZE nElem = 0; nElem < nCountY; nElem++)
2116 const double fVal = pMatY->GetDouble(nElem);
2117 if (fVal <= 0.0)
2119 PushIllegalArgument();
2120 return false;
2122 else
2123 pMatY->PutDouble(log(fVal), nElem);
2124 } // for (nElem = 0; nElem < nCountY; nElem++)
2125 } // if ( _bRKP )
2128 if (pMatX)
2130 pMatX->GetDimensions(nCX, nRX);
2131 const SCSIZE nCountX = nCX * nRX;
2132 for ( SCSIZE i = 0; i < nCountX; i++ )
2133 if (!pMatX->IsValue(i))
2135 PushIllegalArgument();
2136 return false;
2138 if (nCX == nCY && nRX == nRY)
2139 nCase = 1; // einfache Regression
2140 else if (nCY != 1 && nRY != 1)
2142 PushIllegalArgument();
2143 return false;
2145 else if (nCY == 1)
2147 if (nRX != nRY)
2149 PushIllegalArgument();
2150 return false;
2152 else
2154 nCase = 2; // zeilenweise
2155 N = nRY;
2156 M = nCX;
2159 else if (nCX != nCY)
2161 PushIllegalArgument();
2162 return false;
2164 else
2166 nCase = 3; // spaltenweise
2167 N = nCY;
2168 M = nRX;
2171 else
2173 pMatX = GetNewMat(nCY, nRY);
2174 if ( _bTrendGrowth )
2176 nCX = nCY;
2177 nRX = nRY;
2179 if (!pMatX)
2181 PushIllegalArgument();
2182 return false;
2184 for ( SCSIZE i = 1; i <= nCountY; i++ )
2185 pMatX->PutDouble((double)i, i-1);
2186 nCase = 1;
2188 return true;
2190 void ScInterpreter::CalulateRGPRKP(BOOL _bRKP)
2192 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CheckMatrix" );
2193 BYTE nParamCount = GetByte();
2194 if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
2195 return;
2196 BOOL bConstant, bStats;
2197 if (nParamCount == 4)
2198 bStats = GetBool();
2199 else
2200 bStats = FALSE;
2201 if (nParamCount >= 3)
2202 bConstant = GetBool();
2203 else
2204 bConstant = TRUE;
2205 ScMatrixRef pMatX;
2206 ScMatrixRef pMatY;
2207 if (nParamCount >= 2)
2208 pMatX = GetMatrix();
2209 else
2210 pMatX = NULL;
2211 pMatY = GetMatrix();
2212 if (!pMatY)
2214 PushIllegalParameter();
2215 return;
2216 } // if (!pMatY)
2217 BYTE nCase; // 1 = normal, 2,3 = mehrfach
2218 SCSIZE nCX, nCY;
2219 SCSIZE nRX, nRY;
2220 SCSIZE M = 0, N = 0;
2221 if ( !CheckMatrix(_bRKP,FALSE,nCase,nCX,nCY,nRX,nRY,M,N,pMatX,pMatY) )
2222 return;
2224 ScMatrixRef pResMat;
2225 if (nCase == 1)
2227 if (!bStats)
2228 pResMat = GetNewMat(2,1);
2229 else
2230 pResMat = GetNewMat(2,5);
2231 if (!pResMat)
2233 PushIllegalArgument();
2234 return;
2236 double fCount = 0.0;
2237 double fSumX = 0.0;
2238 double fSumSqrX = 0.0;
2239 double fSumY = 0.0;
2240 double fSumSqrY = 0.0;
2241 double fSumXY = 0.0;
2242 double fValX, fValY;
2243 for (SCSIZE i = 0; i < nCY; i++)
2244 for (SCSIZE j = 0; j < nRY; j++)
2246 fValX = pMatX->GetDouble(i,j);
2247 fValY = pMatY->GetDouble(i,j);
2248 fSumX += fValX;
2249 fSumSqrX += fValX * fValX;
2250 fSumY += fValY;
2251 fSumSqrY += fValY * fValY;
2252 fSumXY += fValX*fValY;
2253 fCount++;
2255 if (fCount < 1.0)
2256 PushNoValue();
2257 else
2259 double f1 = fCount*fSumXY-fSumX*fSumY;
2260 double fX = fCount*fSumSqrX-fSumX*fSumX;
2261 double b, m;
2262 if (bConstant)
2264 b = fSumY/fCount - f1/fX*fSumX/fCount;
2265 m = f1/fX;
2267 else
2269 b = 0.0;
2270 m = fSumXY/fSumSqrX;
2272 pResMat->PutDouble(_bRKP ? exp(m) : m, 0, 0);
2273 pResMat->PutDouble(_bRKP ? exp(b) : b, 1, 0);
2274 if (bStats)
2276 double fY = fCount*fSumSqrY-fSumY*fSumY;
2277 double fSyx = fSumSqrY-b*fSumY-m*fSumXY;
2278 double fR2 = f1*f1/(fX*fY);
2279 pResMat->PutDouble (fR2, 0, 2);
2280 if (fCount < 3.0)
2282 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 1 );
2283 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 1 );
2284 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2 );
2285 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3 );
2287 else
2289 pResMat->PutDouble(sqrt(fSyx*fCount/(fX*(fCount-2.0))), 0, 1);
2290 pResMat->PutDouble(sqrt(fSyx*fSumSqrX/fX/(fCount-2.0)), 1, 1);
2291 pResMat->PutDouble(
2292 sqrt((fCount*fSumSqrY - fSumY*fSumY - f1*f1/fX)/
2293 (fCount*(fCount-2.0))), 1, 2);
2294 if (fR2 == 1.0)
2295 pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3 );
2296 else
2297 pResMat->PutDouble(fR2*(fCount-2.0)/(1.0-fR2), 0, 3);
2299 pResMat->PutDouble(((double)(nCY*nRY))-2.0, 1, 3);
2300 pResMat->PutDouble(fY/fCount-fSyx, 0, 4);
2301 pResMat->PutDouble(fSyx, 1, 4);
2304 } // if (nCase == 1)
2305 if ( nCase != 1 )
2307 SCSIZE i, j, k;
2308 if (!bStats)
2309 pResMat = GetNewMat(M+1,1);
2310 else
2311 pResMat = GetNewMat(M+1,5);
2312 if (!pResMat)
2314 PushIllegalArgument();
2315 return;
2317 ScMatrixRef pQ = GetNewMat(M+1, M+2);
2318 ScMatrixRef pE = GetNewMat(M+2, 1);
2319 ScMatrixRef pV = GetNewMat(M+1, 1);
2320 pE->PutDouble(0.0, M+1);
2321 pQ->FillDouble(0.0, 0, 0, M, M+1);
2322 if (nCase == 2)
2324 for (k = 0; k < N; k++)
2326 double Yk = pMatY->GetDouble(k);
2327 pE->PutDouble( pE->GetDouble(M+1)+Yk*Yk, M+1 );
2328 double sumYk = pQ->GetDouble(0, M+1) + Yk;
2329 pQ->PutDouble( sumYk, 0, M+1 );
2330 pE->PutDouble( sumYk, 0 );
2331 for (i = 0; i < M; i++)
2333 double Xik = pMatX->GetDouble(i,k);
2334 double sumXik = pQ->GetDouble(0, i+1) + Xik;
2335 pQ->PutDouble( sumXik, 0, i+1);
2336 pQ->PutDouble( sumXik, i+1, 0);
2337 double sumXikYk = pQ->GetDouble(i+1, M+1) + Xik * Yk;
2338 pQ->PutDouble( sumXikYk, i+1, M+1);
2339 pE->PutDouble( sumXikYk, i+1);
2340 for (j = i; j < M; j++)
2342 const double fVal = pMatX->GetDouble(j,k);
2343 double sumXikXjk = pQ->GetDouble(j+1, i+1) +
2344 Xik * fVal;
2345 pQ->PutDouble( sumXikXjk, j+1, i+1);
2346 pQ->PutDouble( sumXikXjk, i+1, j+1);
2351 else
2353 for (k = 0; k < N; k++)
2355 double Yk = pMatY->GetDouble(k);
2356 pE->PutDouble( pE->GetDouble(M+1)+Yk*Yk, M+1 );
2357 double sumYk = pQ->GetDouble(0, M+1) + Yk;
2358 pQ->PutDouble( sumYk, 0, M+1 );
2359 pE->PutDouble( sumYk, 0 );
2360 for (i = 0; i < M; i++)
2362 double Xki = pMatX->GetDouble(k,i);
2363 double sumXki = pQ->GetDouble(0, i+1) + Xki;
2364 pQ->PutDouble( sumXki, 0, i+1);
2365 pQ->PutDouble( sumXki, i+1, 0);
2366 double sumXkiYk = pQ->GetDouble(i+1, M+1) + Xki * Yk;
2367 pQ->PutDouble( sumXkiYk, i+1, M+1);
2368 pE->PutDouble( sumXkiYk, i+1);
2369 for (j = i; j < M; j++)
2371 const double fVal = pMatX->GetDouble(k,j);
2372 double sumXkiXkj = pQ->GetDouble(j+1, i+1) +
2373 Xki * fVal;
2374 pQ->PutDouble( sumXkiXkj, j+1, i+1);
2375 pQ->PutDouble( sumXkiXkj, i+1, j+1);
2380 if ( !Calculate4(_bRKP,pResMat,pQ,bConstant,N,M) )
2381 return;
2383 if (bStats)
2384 Calculate(pResMat,pE,pQ,pV,pMatX,bConstant,N,M,nCase);
2386 PushMatrix(pResMat);
2389 void ScInterpreter::ScRKP()
2391 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRKP" );
2392 CalulateRGPRKP(TRUE);
2394 // -----------------------------------------------------------------------------
2395 bool ScInterpreter::Calculate4(BOOL _bExp,ScMatrixRef& pResMat,ScMatrixRef& pQ,BOOL bConstant,SCSIZE N,SCSIZE M)
2397 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::Calculate4" );
2398 pQ->PutDouble((double)N, 0, 0);
2399 if (bConstant)
2401 SCSIZE S, L;
2402 for (S = 0; S < M+1; S++)
2404 SCSIZE i = S;
2405 while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
2406 i++;
2407 if (i >= M+1)
2409 PushNoValue();
2410 return false;
2412 double fVal;
2413 for (L = 0; L < M+2; L++)
2415 fVal = pQ->GetDouble(S, L);
2416 pQ->PutDouble(pQ->GetDouble(i, L), S, L);
2417 pQ->PutDouble(fVal, i, L);
2419 fVal = 1.0/pQ->GetDouble(S, S);
2420 for (L = 0; L < M+2; L++)
2421 pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
2422 for (i = 0; i < M+1; i++)
2424 if (i != S)
2426 fVal = -pQ->GetDouble(i, S);
2427 for (L = 0; L < M+2; L++)
2428 pQ->PutDouble(
2429 pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
2434 else
2436 if ( !Calculate3(M,pQ) )
2437 return false;
2440 for (SCSIZE i = 0; i < M+1; i++)
2442 const double d = pQ->GetDouble(M-i,M+1);
2443 pResMat->PutDouble(_bExp ? exp(d) : d, i, 0);
2444 } // for (SCSIZE i = 0; i < M+1; i++)
2445 return true;
2448 ScMatrixRef ScInterpreter::Calculate2(const BOOL bConstant,const SCSIZE M ,const SCSIZE N,ScMatrixRef& pMatX,ScMatrixRef& pMatY,BYTE nCase)
2450 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::Calculate2" );
2451 SCSIZE i, j, k;
2452 ScMatrixRef pQ = GetNewMat(M+1, M+2);
2453 ScMatrixRef pE = GetNewMat(M+2, 1);
2454 pE->PutDouble(0.0, M+1);
2455 pQ->FillDouble(0.0, 0, 0, M, M+1);
2456 if (nCase == 2)
2458 for (k = 0; k < N; k++)
2460 pE->PutDouble(
2461 pE->GetDouble(M+1)+pMatY->GetDouble(k)*pMatY->GetDouble(k), M+1);
2462 pQ->PutDouble(pQ->GetDouble(0, M+1) + pMatY->GetDouble(k), 0, M+1);
2463 pE->PutDouble(pQ->GetDouble(0, M+1), 0);
2464 for (i = 0; i < M; i++)
2466 pQ->PutDouble(pQ->GetDouble(0, i+1)+pMatX->GetDouble(i,k), 0, i+1);
2467 pQ->PutDouble(pQ->GetDouble(0, i+1), i+1, 0);
2468 pQ->PutDouble(pQ->GetDouble(i+1, M+1) +
2469 pMatX->GetDouble(i,k)*pMatY->GetDouble(k), i+1, M+1);
2470 pE->PutDouble(pQ->GetDouble(i+1, M+1), i+1);
2471 for (j = i; j < M; j++)
2473 pQ->PutDouble(pQ->GetDouble(j+1, i+1) +
2474 pMatX->GetDouble(i,k)*pMatX->GetDouble(j,k), j+1, i+1);
2475 pQ->PutDouble(pQ->GetDouble(j+1, i+1), i+1, j+1);
2480 else
2482 for (k = 0; k < N; k++)
2484 pE->PutDouble(
2485 pE->GetDouble(M+1)+pMatY->GetDouble(k)*pMatY->GetDouble(k), M+1);
2486 pQ->PutDouble(pQ->GetDouble(0, M+1) + pMatY->GetDouble(k), 0, M+1);
2487 pE->PutDouble(pQ->GetDouble(0, M+1), 0);
2488 for (i = 0; i < M; i++)
2490 pQ->PutDouble(pQ->GetDouble(0, i+1)+pMatX->GetDouble(k,i), 0, i+1);
2491 pQ->PutDouble(pQ->GetDouble(0, i+1), i+1, 0);
2492 pQ->PutDouble(pQ->GetDouble(i+1, M+1) +
2493 pMatX->GetDouble(k,i)*pMatY->GetDouble(k), i+1, M+1);
2494 pE->PutDouble(pQ->GetDouble(i+1, M+1), i+1);
2495 for (j = i; j < M; j++)
2497 pQ->PutDouble(pQ->GetDouble(j+1, i+1) +
2498 pMatX->GetDouble(k, i)*pMatX->GetDouble(k, j), j+1, i+1);
2499 pQ->PutDouble(pQ->GetDouble(j+1, i+1), i+1, j+1);
2504 pQ->PutDouble((double)N, 0, 0);
2505 if (bConstant)
2507 SCSIZE S, L;
2508 for (S = 0; S < M+1; S++)
2510 i = S;
2511 while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
2512 i++;
2513 if (i >= M+1)
2515 PushNoValue();
2516 return ScMatrixRef();
2518 double fVal;
2519 for (L = 0; L < M+2; L++)
2521 fVal = pQ->GetDouble(S, L);
2522 pQ->PutDouble(pQ->GetDouble(i, L), S, L);
2523 pQ->PutDouble(fVal, i, L);
2525 fVal = 1.0/pQ->GetDouble(S, S);
2526 for (L = 0; L < M+2; L++)
2527 pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
2528 for (i = 0; i < M+1; i++)
2530 if (i != S)
2532 fVal = -pQ->GetDouble(i, S);
2533 for (L = 0; L < M+2; L++)
2534 pQ->PutDouble(
2535 pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
2540 else
2542 if ( !Calculate3(M,pQ) )
2543 return ScMatrixRef();
2545 return pQ;
2547 bool ScInterpreter::Calculate3(const SCSIZE M ,ScMatrixRef& pQ)
2549 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::Calculate3" );
2550 SCSIZE S, L;
2551 for (S = 1; S < M+1; S++)
2553 SCSIZE i = S;
2554 while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
2555 i++;
2556 if (i >= M+1)
2558 PushNoValue();
2559 return ScMatrixRef();
2561 double fVal;
2562 for (L = 1; L < M+2; L++)
2564 fVal = pQ->GetDouble(S, L);
2565 pQ->PutDouble(pQ->GetDouble(i, L), S, L);
2566 pQ->PutDouble(fVal, i, L);
2568 fVal = 1.0/pQ->GetDouble(S, S);
2569 for (L = 1; L < M+2; L++)
2570 pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
2571 for (i = 1; i < M+1; i++)
2573 if (i != S)
2575 fVal = -pQ->GetDouble(i, S);
2576 for (L = 1; L < M+2; L++)
2577 pQ->PutDouble(
2578 pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
2581 pQ->PutDouble(0.0, 0, M+1);
2582 } // for (S = 1; S < M+1; S++)
2583 return true;
2586 void ScInterpreter::ScTrend()
2588 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTrend" );
2589 CalculateTrendGrowth(FALSE);
2591 void ScInterpreter::CalculateTrendGrowth(BOOL _bGrowth)
2593 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateTrendGrowth" );
2594 BYTE nParamCount = GetByte();
2595 if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
2596 return;
2597 BOOL bConstant;
2598 if (nParamCount == 4)
2599 bConstant = GetBool();
2600 else
2601 bConstant = TRUE;
2602 ScMatrixRef pMatX;
2603 ScMatrixRef pMatY;
2604 ScMatrixRef pMatNewX;
2605 if (nParamCount >= 3)
2606 pMatNewX = GetMatrix();
2607 else
2608 pMatNewX = NULL;
2609 if (nParamCount >= 2)
2610 pMatX = GetMatrix();
2611 else
2612 pMatX = NULL;
2613 pMatY = GetMatrix();
2614 if (!pMatY)
2616 PushIllegalParameter();
2617 return;
2618 } // if (!pMatY)
2620 BYTE nCase; // 1 = normal, 2,3 = mehrfach
2621 SCSIZE nCX, nCY;
2622 SCSIZE nRX, nRY;
2623 SCSIZE M = 0, N = 0;
2624 if ( !CheckMatrix(_bGrowth,TRUE,nCase,nCX,nCY,nRX,nRY,M,N,pMatX,pMatY) )
2625 return;
2628 SCSIZE nCXN, nRXN;
2629 SCSIZE nCountXN;
2630 if (!pMatNewX)
2632 nCXN = nCX;
2633 nRXN = nRX;
2634 nCountXN = nCXN * nRXN;
2635 pMatNewX = pMatX;
2637 else
2639 pMatNewX->GetDimensions(nCXN, nRXN);
2640 if ((nCase == 2 && nCX != nCXN) || (nCase == 3 && nRX != nRXN))
2642 PushIllegalArgument();
2643 return;
2645 nCountXN = nCXN * nRXN;
2646 for ( SCSIZE i = 0; i < nCountXN; i++ )
2647 if (!pMatNewX->IsValue(i))
2649 PushIllegalArgument();
2650 return;
2653 ScMatrixRef pResMat;
2654 if (nCase == 1)
2656 double fCount = 0.0;
2657 double fSumX = 0.0;
2658 double fSumSqrX = 0.0;
2659 double fSumY = 0.0;
2660 double fSumSqrY = 0.0;
2661 double fSumXY = 0.0;
2662 double fValX, fValY;
2663 SCSIZE i;
2664 for (i = 0; i < nCY; i++)
2665 for (SCSIZE j = 0; j < nRY; j++)
2667 fValX = pMatX->GetDouble(i,j);
2668 fValY = pMatY->GetDouble(i,j);
2669 fSumX += fValX;
2670 fSumSqrX += fValX * fValX;
2671 fSumY += fValY;
2672 fSumSqrY += fValY * fValY;
2673 fSumXY += fValX*fValY;
2674 fCount++;
2676 if (fCount < 1.0)
2678 PushNoValue();
2679 return;
2681 else
2683 double f1 = fCount*fSumXY-fSumX*fSumY;
2684 double fX = fCount*fSumSqrX-fSumX*fSumX;
2685 double b, m;
2686 if (bConstant)
2688 b = fSumY/fCount - f1/fX*fSumX/fCount;
2689 m = f1/fX;
2691 else
2693 b = 0.0;
2694 m = fSumXY/fSumSqrX;
2696 pResMat = GetNewMat(nCXN, nRXN);
2697 if (!pResMat)
2699 PushIllegalArgument();
2700 return;
2702 for (i = 0; i < nCountXN; i++)
2704 const double d = pMatNewX->GetDouble(i)*m+b;
2705 pResMat->PutDouble(_bGrowth ? exp(d) : d, i);
2709 else
2711 ScMatrixRef pQ = Calculate2(bConstant,M ,N,pMatX,pMatY,nCase);
2712 if ( !pQ.Is() )
2713 return;
2714 if (nCase == 2)
2716 pResMat = GetNewMat(1, nRXN);
2717 if (!pResMat)
2719 PushIllegalArgument();
2720 return;
2722 double fVal;
2723 for (SCSIZE i = 0; i < nRXN; i++)
2725 fVal = pQ->GetDouble(0, M+1);
2726 for (SCSIZE j = 0; j < M; j++)
2727 fVal += pQ->GetDouble(j+1, M+1)*pMatNewX->GetDouble(j, i);
2728 pResMat->PutDouble(_bGrowth ? exp(fVal) : fVal, i);
2731 else
2733 pResMat = GetNewMat(nCXN, 1);
2734 if (!pResMat)
2736 PushIllegalArgument();
2737 return;
2739 double fVal;
2740 for (SCSIZE i = 0; i < nCXN; i++)
2742 fVal = pQ->GetDouble(0, M+1);
2743 for (SCSIZE j = 0; j < M; j++)
2744 fVal += pQ->GetDouble(j+1, M+1)*pMatNewX->GetDouble(i, j);
2745 pResMat->PutDouble(_bGrowth ? exp(fVal) : fVal, i);
2749 PushMatrix(pResMat);
2752 void ScInterpreter::ScGrowth()
2754 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGrowth" );
2755 CalculateTrendGrowth(TRUE);
2758 void ScInterpreter::ScMatRef()
2760 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMatRef" );
2761 // Falls Deltarefs drin sind...
2762 Push( (FormulaToken&)*pCur );
2763 ScAddress aAdr;
2764 PopSingleRef( aAdr );
2765 ScFormulaCell* pCell = (ScFormulaCell*) GetCell( aAdr );
2766 if( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
2768 const ScMatrix* pMat = pCell->GetMatrix();
2769 if( pMat )
2771 SCSIZE nCols, nRows;
2772 pMat->GetDimensions( nCols, nRows );
2773 SCSIZE nC = static_cast<SCSIZE>(aPos.Col() - aAdr.Col());
2774 SCSIZE nR = static_cast<SCSIZE>(aPos.Row() - aAdr.Row());
2775 if ((nCols <= nC && nCols != 1) || (nRows <= nR && nRows != 1))
2776 PushNA();
2777 else
2779 ScMatValType nMatValType;
2780 const ScMatrixValue* pMatVal = pMat->Get( nC, nR, nMatValType);
2781 if (ScMatrix::IsNonValueType( nMatValType))
2783 if (ScMatrix::IsEmptyPathType( nMatValType))
2784 { // result of empty FALSE jump path
2785 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2786 PushInt(0);
2788 else if (ScMatrix::IsEmptyType( nMatValType))
2790 // Not inherited (really?) and display as empty string, not 0.
2791 PushTempToken( new ScEmptyCellToken( false, true));
2793 else
2794 PushString( pMatVal->GetString() );
2796 else
2798 PushDouble(pMatVal->fVal); // handles DoubleError
2799 pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex, aAdr, pCell );
2800 nFuncFmtType = nCurFmtType;
2801 nFuncFmtIndex = nCurFmtIndex;
2805 else
2807 // If not a result matrix, obtain the cell value.
2808 USHORT nErr = pCell->GetErrCode();
2809 if (nErr)
2810 PushError( nErr );
2811 else if( pCell->IsValue() )
2812 PushDouble( pCell->GetValue() );
2813 else
2815 String aVal;
2816 pCell->GetString( aVal );
2817 PushString( aVal );
2819 pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex, aAdr, pCell );
2820 nFuncFmtType = nCurFmtType;
2821 nFuncFmtIndex = nCurFmtIndex;
2824 else
2825 PushError( errNoRef );
2828 void ScInterpreter::ScInfo()
2830 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScInfo" );
2831 if( MustHaveParamCount( GetByte(), 1 ) )
2833 String aStr = GetString();
2834 ScCellKeywordTranslator::transKeyword(aStr, ScGlobal::GetLocale(), ocInfo);
2835 if( aStr.EqualsAscii( "SYSTEM" ) )
2836 PushString( String( RTL_CONSTASCII_USTRINGPARAM( SC_INFO_OSVERSION ) ) );
2837 else if( aStr.EqualsAscii( "OSVERSION" ) )
2838 PushString( String( RTL_CONSTASCII_USTRINGPARAM( "Windows (32-bit) NT 5.01" ) ) );
2839 else if( aStr.EqualsAscii( "RELEASE" ) )
2840 PushString( ::utl::Bootstrap::getBuildIdData( ::rtl::OUString() ) );
2841 else if( aStr.EqualsAscii( "NUMFILE" ) )
2842 PushDouble( 1 );
2843 else if( aStr.EqualsAscii( "RECALC" ) )
2844 PushString( ScGlobal::GetRscString( pDok->GetAutoCalc() ? STR_RECALC_AUTO : STR_RECALC_MANUAL ) );
2845 else
2846 PushIllegalArgument();