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>
39 #include <rtl/logfile.hxx>
44 #if OSL_DEBUG_LEVEL > 1
47 #include <unotools/bootstrap.hxx>
48 #include <svtools/zforlist.hxx>
50 #include "interpre.hxx"
52 #include "compiler.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"
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
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
118 double fz
= fmod(fx
, 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 ) )
137 size_t nRefInList
= 0;
138 while (!nGlobalError
&& nParamCount
-- > 0)
140 switch (GetStackType())
146 fx
= ::rtl::math::approxFloor( GetDouble());
149 PushIllegalArgument();
152 fy
= ScGetGCD(fx
, fy
);
159 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
161 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
162 if (aValIter
.GetFirst(nCellVal
, nErr
))
166 fx
= ::rtl::math::approxFloor( nCellVal
);
169 PushIllegalArgument();
172 fy
= ScGetGCD(fx
, fy
);
173 } while (nErr
== 0 && aValIter
.GetNext(nCellVal
, nErr
));
180 ScMatrixRef pMat
= PopMatrix();
184 pMat
->GetDimensions(nC
, nR
);
185 if (nC
== 0 || nR
== 0)
186 SetError(errIllegalArgument
);
189 SCSIZE nCount
= nC
* nR
;
190 for ( SCSIZE j
= 0; j
< nCount
; j
++ )
192 if (!pMat
->IsValue(j
))
194 PushIllegalArgument();
197 fx
= ::rtl::math::approxFloor( pMat
->GetDouble(j
));
200 PushIllegalArgument();
203 fy
= ScGetGCD(fx
, fy
);
209 default : SetError(errIllegalParameter
); break;
216 void ScInterpreter:: ScLCM()
218 short nParamCount
= GetByte();
219 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
223 size_t nRefInList
= 0;
224 while (!nGlobalError
&& nParamCount
-- > 0)
226 switch (GetStackType())
232 fx
= ::rtl::math::approxFloor( GetDouble());
235 PushIllegalArgument();
238 if (fx
== 0.0 || fy
== 0.0)
241 fy
= fx
* fy
/ ScGetGCD(fx
, fy
);
248 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
250 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
251 if (aValIter
.GetFirst(nCellVal
, nErr
))
255 fx
= ::rtl::math::approxFloor( nCellVal
);
258 PushIllegalArgument();
261 if (fx
== 0.0 || fy
== 0.0)
264 fy
= fx
* fy
/ ScGetGCD(fx
, fy
);
265 } while (nErr
== 0 && aValIter
.GetNext(nCellVal
, nErr
));
272 ScMatrixRef pMat
= PopMatrix();
276 pMat
->GetDimensions(nC
, nR
);
277 if (nC
== 0 || nR
== 0)
278 SetError(errIllegalArgument
);
281 SCSIZE nCount
= nC
* nR
;
282 for ( SCSIZE j
= 0; j
< nCount
; j
++ )
284 if (!pMat
->IsValue(j
))
286 PushIllegalArgument();
289 fx
= ::rtl::math::approxFloor( pMat
->GetDouble(j
));
292 PushIllegalArgument();
295 if (fx
== 0.0 || fy
== 0.0)
298 fy
= fx
* fy
/ ScGetGCD(fx
, fy
);
304 default : SetError(errIllegalParameter
); break;
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);
317 pMat
->GetDimensions( nCols
, nRows
);
318 if ( nCols
!= nC
|| nRows
!= nR
)
319 { // arbitray limit of elements exceeded
320 SetError( errStackOverflow
);
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();
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
,
363 for (ScBaseCell
* pCell
= aCellIter
.GetFirst(); pCell
; pCell
=
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
<
379 pMat
->PutEmpty( nC
, nR
);
384 if (nThisRow
== nRow2
)
386 nNextCol
= nThisCol
+ 1;
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
);
405 fVal
= CreateDoubleError( nGlobalError
);
408 pMat
->PutDouble( fVal
,
409 static_cast<SCSIZE
>(nThisCol
-nCol1
),
410 static_cast<SCSIZE
>(nThisRow
-nRow1
));
415 GetCellString( aStr
, pCell
);
418 double fVal
= CreateDoubleError( nGlobalError
);
420 pMat
->PutDouble( fVal
,
421 static_cast<SCSIZE
>(nThisCol
-nCol1
),
422 static_cast<SCSIZE
>(nThisRow
-nRow1
));
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
);
444 pTokenMatrixMap
->insert( ScTokenMatrixMap::value_type(
445 pToken
, new ScMatrixToken( pMat
)));
449 else // not a 2D matrix
450 SetError(errIllegalParameter
);
455 ScMatrixRef
ScInterpreter::GetMatrix()
457 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetMatrix" );
458 ScMatrixRef pMat
= NULL
;
459 switch (GetRawStackType())
464 PopSingleRef( aAdr
);
465 pMat
= GetNewMat(1, 1);
468 ScBaseCell
* pCell
= GetCell( aAdr
);
469 if (HasCellEmptyData(pCell
))
471 else if (HasCellValueData(pCell
))
472 pMat
->PutDouble(GetCellValue(aAdr
, pCell
), 0);
476 GetCellString(aStr
, pCell
);
477 pMat
->PutString(aStr
, 0);
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
);
500 double fVal
= GetDouble();
501 pMat
= GetNewMat( 1, 1);
506 fVal
= CreateDoubleError( nGlobalError
);
509 pMat
->PutDouble( fVal
, 0);
515 String aStr
= GetString();
516 pMat
= GetNewMat( 1, 1);
521 double fVal
= CreateDoubleError( nGlobalError
);
522 pMat
->PutDouble( fVal
, 0);
526 pMat
->PutString( aStr
, 0);
532 SetError( errIllegalArgument
);
538 void ScInterpreter::ScMatValue()
540 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMatValue" );
541 if ( MustHaveParamCount( GetByte(), 3 ) )
544 SCSIZE nR
= static_cast<SCSIZE
>(::rtl::math::approxFloor(GetDouble()));
545 SCSIZE nC
= static_cast<SCSIZE
>(::rtl::math::approxFloor(GetDouble()));
546 switch (GetStackType())
551 PopSingleRef( aAdr
);
552 ScBaseCell
* pCell
= GetCell( aAdr
);
553 if (pCell
&& pCell
->GetCellType() == CELLTYPE_FORMULA
)
555 USHORT nErrCode
= ((ScFormulaCell
*)pCell
)->GetErrCode();
557 PushError( nErrCode
);
560 const ScMatrix
* pMat
= ((ScFormulaCell
*)pCell
)->GetMatrix();
561 CalculateMatrixValue(pMat
,nC
,nR
);
565 PushIllegalParameter();
576 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
577 if (nCol2
- nCol1
>= static_cast<SCCOL
>(nR
) &&
578 nRow2
- nRow1
>= static_cast<SCROW
>(nC
) &&
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
));
589 GetCellString(aStr
, pCell
);
599 ScMatrixRef pMat
= PopMatrix();
600 CalculateMatrixValue(pMat
,nC
,nR
);
605 PushIllegalParameter();
610 void ScInterpreter::CalculateMatrixValue(const ScMatrix
* pMat
,SCSIZE nC
,SCSIZE nR
)
612 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateMatrixValue" );
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() );
624 PushDouble(pMatVal
->fVal
);
625 // also handles DoubleError
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();
644 ScMatrixRef pRMat
= GetNewMat(nDim
, nDim
);
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" );
670 for (SCSIZE i
= 0; i
< n
; i
++)
672 for (SCSIZE j
= 0; j
< l
; j
++)
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
)
706 // Find scale of each row.
707 ::std::vector
< double> aScale(n
);
708 for (SCSIZE i
=0; i
< n
; ++i
)
711 for (SCSIZE j
=0; j
< n
; ++j
)
713 double fTmp
= fabs( mA
->GetDouble( j
, i
));
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
)
724 // "Recursion" on the diagonale.
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.
731 double fScale
= aScale
[k
];
733 for (SCSIZE i
= k
; i
< n
; ++i
)
735 double fTmp
= fScale
* fabs( mA
->GetDouble( k
, i
));
743 return 0; // singular matrix
744 // Swap rows. The pivot element will be at mA[k,kp] (row,col notation)
753 double fTmp
= aScale
[k
];
754 aScale
[k
] = aScale
[kp
];
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
,
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", "");
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
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]
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", "");
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();
844 PushIllegalParameter();
847 if ( !pMat
->IsNumeric() )
853 pMat
->GetDimensions(nC
, nR
);
854 if ( nC
!= nR
|| nC
== 0 || (ULONG
) nC
* nC
> ScMatrix::GetElementsMax() )
855 PushIllegalArgument();
858 // LUP decomposition is done inplace, use copy.
859 ScMatrixRef xLU
= pMat
->Clone();
861 PushError( errCodeOverflow
);
864 ::std::vector
< SCSIZE
> P(nR
);
865 int nDetSign
= lcl_LUP_decompose( xLU
, nR
, P
);
867 PushInt(0); // singular matrix
870 // In an LU matrix the determinant is simply the product of
871 // all diagonal elements.
872 double fDet
= nDetSign
;
874 for (SCSIZE i
=0; i
< nR
; ++i
)
875 fDet
*= pLU
->GetDouble( i
, i
);
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();
891 PushIllegalParameter();
894 if ( !pMat
->IsNumeric() )
900 pMat
->GetDimensions(nC
, nR
);
901 if ( nC
!= nR
|| nC
== 0 || (ULONG
) nC
* nC
> ScMatrix::GetElementsMax() )
902 PushIllegalArgument();
905 // LUP decomposition is done inplace, use copy.
906 ScMatrixRef xLU
= pMat
->Clone();
907 // The result matrix.
908 ScMatrixRef xY
= GetNewMat( nR
, nR
);
910 PushError( errCodeOverflow
);
913 ::std::vector
< SCSIZE
> P(nR
);
914 int nDetSign
= lcl_LUP_decompose( xLU
, nR
, P
);
916 PushIllegalArgument();
919 // Solve equation for each column.
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
)
928 lcl_LUP_solve( xLU
, nR
, P
, B
, X
);
929 for (SCSIZE i
=0; i
< nR
; ++i
)
930 pY
->PutDouble( X
[i
], j
, i
);
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 =>
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
946 * Just what is sufficient?
948 * The following is #3.
950 ScMatrixRef xR
= GetNewMat( nR
, nR
);
954 MFastMult( pMat
, pY
, pR
, nR
, nR
, nR
);
955 #if OSL_DEBUG_LEVEL > 1
956 fprintf( stderr
, "\n%s\n", "ScMatInv(): mult-identity");
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
);
966 if (fabs( fTmp
- (i
== j
)) > fInvEpsilon
)
967 SetError( errIllegalArgument
);
969 #if OSL_DEBUG_LEVEL > 1
970 fprintf( stderr
, "\n%s\n", "");
976 PushError( nGlobalError
);
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();
995 if ( pMat1
->IsNumeric() && pMat2
->IsNumeric() )
999 pMat1
->GetDimensions(nC1
, nR1
);
1000 pMat2
->GetDimensions(nC2
, nR2
);
1002 PushIllegalArgument();
1005 pRMat
= GetNewMat(nC2
, nR1
);
1009 for (SCSIZE i
= 0; i
< nR1
; i
++)
1011 for (SCSIZE j
= 0; j
< nC2
; j
++)
1014 for (SCSIZE k
= 0; k
< nC1
; k
++)
1016 sum
+= pMat1
->GetDouble(k
,i
)*pMat2
->GetDouble(j
,k
);
1018 pRMat
->PutDouble(sum
, j
, i
);
1024 PushIllegalArgument();
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();
1045 pMat
->GetDimensions(nC
, nR
);
1046 pRMat
= GetNewMat(nR
, nC
);
1049 pMat
->MatTrans(*pRMat
);
1053 PushIllegalArgument();
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
)
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
;
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
);
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
);
1101 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), i
, j
);
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
;
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
);
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
);
1128 nErr
= pMat2
->GetErrorIfNotString( i
, j
);
1130 pResMat
->PutError( nErr
, i
, j
);
1133 String
aTmp( pMat1
->GetString( *pFormatter
, i
, j
));
1134 aTmp
+= pMat2
->GetString( *pFormatter
, i
, j
);
1135 pResMat
->PutString( aTmp
, i
, j
);
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
)
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;
1184 nFmt1
= nFmt2
= NUMBERFORMAT_UNDEFINED
;
1185 short nFmtCurrencyType
= nCurFmtType
;
1186 ULONG nFmtCurrencyIndex
= nCurFmtIndex
;
1187 short nFmtPercentType
= nCurFmtType
;
1188 if ( GetStackType() == svMatrix
)
1189 pMat2
= GetMatrix();
1192 fVal2
= GetDouble(true, true);
1195 PushError(nGlobalError
);
1198 switch ( nCurFmtType
)
1200 case NUMBERFORMAT_DATE
:
1201 case NUMBERFORMAT_TIME
:
1202 case NUMBERFORMAT_DATETIME
:
1203 nFmt2
= nCurFmtType
;
1205 case NUMBERFORMAT_CURRENCY
:
1206 nFmtCurrencyType
= nCurFmtType
;
1207 nFmtCurrencyIndex
= nCurFmtIndex
;
1209 case NUMBERFORMAT_PERCENT
:
1210 nFmtPercentType
= NUMBERFORMAT_PERCENT
;
1214 if ( GetStackType() == svMatrix
)
1215 pMat1
= GetMatrix();
1218 fVal1
= GetDouble(true, true);
1221 PushError(nGlobalError
);
1224 switch ( nCurFmtType
)
1226 case NUMBERFORMAT_DATE
:
1227 case NUMBERFORMAT_TIME
:
1228 case NUMBERFORMAT_DATETIME
:
1229 nFmt1
= nCurFmtType
;
1231 case NUMBERFORMAT_CURRENCY
:
1232 nFmtCurrencyType
= nCurFmtType
;
1233 nFmtCurrencyIndex
= nCurFmtIndex
;
1235 case NUMBERFORMAT_PERCENT
:
1236 nFmtPercentType
= NUMBERFORMAT_PERCENT
;
1242 ScMatrixRef pResMat
;
1246 pResMat
= lcl_MatrixCalculation(aSub
,pMat1
, pMat2
,this);
1251 pResMat
= lcl_MatrixCalculation(aAdd
,pMat1
, pMat2
,this);
1257 PushMatrix(pResMat
);
1259 else if (pMat1
|| pMat2
)
1263 ScMatrixRef pMat
= pMat1
;
1268 bFlag
= TRUE
; // double - Matrix
1273 bFlag
= FALSE
; // Matrix - double
1276 pMat
->GetDimensions(nC
, nR
);
1277 ScMatrixRef pResMat
= GetNewMat(nC
, nR
);
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
);
1288 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), i
);
1289 } // for ( SCSIZE i = 0; i < nCount; i++ )
1290 } // if (bFlag || !_bSub )
1293 for ( SCSIZE i
= 0; i
< nCount
; i
++ )
1294 { if (pMat
->IsValue(i
))
1295 pResMat
->PutDouble( ::rtl::math::approxSub( pMat
->GetDouble(i
), fVal
), i
);
1297 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), i
);
1298 } // for ( SCSIZE i = 0; i < nCount; i++ )
1300 PushMatrix(pResMat
);
1303 PushIllegalArgument();
1306 PushDouble( ::rtl::math::approxSub( fVal1
, fVal2
) );
1308 PushDouble( ::rtl::math::approxAdd( fVal1
, fVal2
) );
1309 if ( nFmtCurrencyType
== NUMBERFORMAT_CURRENCY
)
1311 nFuncFmtType
= nFmtCurrencyType
;
1312 nFuncFmtIndex
= nFmtCurrencyIndex
;
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();
1331 sStr2
= GetString();
1332 if ( GetStackType() == svMatrix
)
1333 pMat1
= GetMatrix();
1335 sStr1
= GetString();
1338 ScMatrixRef pResMat
= MatConcat(pMat1
, pMat2
);
1342 PushMatrix(pResMat
);
1344 else if (pMat1
|| pMat2
)
1348 ScMatrixRef pMat
= pMat1
;
1353 bFlag
= TRUE
; // double - Matrix
1358 bFlag
= FALSE
; // Matrix - double
1361 pMat
->GetDimensions(nC
, nR
);
1362 ScMatrixRef pResMat
= GetNewMat(nC
, nR
);
1365 SCSIZE nCount
= nC
* nR
;
1368 for ( SCSIZE i
= 0; i
< nCount
; i
++ )
1369 pResMat
->PutError( nGlobalError
, i
);
1373 for ( SCSIZE i
= 0; i
< nCount
; i
++ )
1375 USHORT nErr
= pMat
->GetErrorIfNotString( i
);
1377 pResMat
->PutError( nErr
, i
);
1381 aTmp
+= pMat
->GetString( *pFormatter
, i
);
1382 pResMat
->PutString( aTmp
, i
);
1388 for ( SCSIZE i
= 0; i
< nCount
; i
++ )
1390 USHORT nErr
= pMat
->GetErrorIfNotString( i
);
1392 pResMat
->PutError( nErr
, i
);
1395 String
aTmp( pMat
->GetString( *pFormatter
, i
));
1397 pResMat
->PutString( aTmp
, i
);
1401 PushMatrix(pResMat
);
1404 PushIllegalArgument();
1408 if ( CheckStringResultLen( sStr1
, sStr2
) )
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();
1432 fVal2
= GetDouble(true, true);
1435 PushError(nGlobalError
);
1438 switch ( nCurFmtType
)
1440 case NUMBERFORMAT_CURRENCY
:
1441 nFmtCurrencyType
= nCurFmtType
;
1442 nFmtCurrencyIndex
= nCurFmtIndex
;
1446 if ( GetStackType() == svMatrix
)
1447 pMat1
= GetMatrix();
1450 fVal1
= GetDouble(true, true);
1453 PushError(nGlobalError
);
1456 switch ( nCurFmtType
)
1458 case NUMBERFORMAT_CURRENCY
:
1459 nFmtCurrencyType
= nCurFmtType
;
1460 nFmtCurrencyIndex
= nCurFmtIndex
;
1467 ScMatrixRef pResMat
= lcl_MatrixCalculation(aMul
,pMat1
, pMat2
,this);
1471 PushMatrix(pResMat
);
1473 else if (pMat1
|| pMat2
)
1476 ScMatrixRef pMat
= pMat1
;
1485 pMat
->GetDimensions(nC
, nR
);
1486 ScMatrixRef pResMat
= GetNewMat(nC
, nR
);
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
);
1494 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), i
);
1495 PushMatrix(pResMat
);
1498 PushIllegalArgument();
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();
1522 fVal2
= GetDouble(true, true);
1525 PushError(nGlobalError
);
1528 // hier kein Currency uebernehmen, 123kg/456DM sind nicht DM
1529 nFmtCurrencyType2
= nCurFmtType
;
1531 if ( GetStackType() == svMatrix
)
1532 pMat1
= GetMatrix();
1535 fVal1
= GetDouble(true, true);
1538 PushError(nGlobalError
);
1541 switch ( nCurFmtType
)
1543 case NUMBERFORMAT_CURRENCY
:
1544 nFmtCurrencyType
= nCurFmtType
;
1545 nFmtCurrencyIndex
= nCurFmtIndex
;
1552 ScMatrixRef pResMat
= lcl_MatrixCalculation(aDiv
,pMat1
, pMat2
,this);
1556 PushMatrix(pResMat
);
1558 else if (pMat1
|| pMat2
)
1562 ScMatrixRef pMat
= pMat1
;
1567 bFlag
= TRUE
; // double - Matrix
1572 bFlag
= FALSE
; // Matrix - double
1575 pMat
->GetDimensions(nC
, nR
);
1576 ScMatrixRef pResMat
= GetNewMat(nC
, nR
);
1579 SCSIZE nCount
= nC
* nR
;
1581 { for ( SCSIZE i
= 0; i
< nCount
; i
++ )
1582 if (pMat
->IsValue(i
))
1583 pResMat
->PutDouble( div( fVal
, pMat
->GetDouble(i
)), i
);
1585 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), i
);
1588 { for ( SCSIZE i
= 0; i
< nCount
; i
++ )
1589 if (pMat
->IsValue(i
))
1590 pResMat
->PutDouble( div( pMat
->GetDouble(i
), fVal
), i
);
1592 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), i
);
1594 PushMatrix(pResMat
);
1597 PushIllegalArgument();
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 ) )
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();
1626 fVal2
= GetDouble();
1627 if ( GetStackType() == svMatrix
)
1628 pMat1
= GetMatrix();
1630 fVal1
= GetDouble();
1634 ScMatrixRef pResMat
= lcl_MatrixCalculation(aPow
,pMat1
, pMat2
,this);
1638 PushMatrix(pResMat
);
1640 else if (pMat1
|| pMat2
)
1644 ScMatrixRef pMat
= pMat1
;
1649 bFlag
= TRUE
; // double - Matrix
1654 bFlag
= FALSE
; // Matrix - double
1657 pMat
->GetDimensions(nC
, nR
);
1658 ScMatrixRef pResMat
= GetNewMat(nC
, nR
);
1661 SCSIZE nCount
= nC
* nR
;
1663 { for ( SCSIZE i
= 0; i
< nCount
; i
++ )
1664 if (pMat
->IsValue(i
))
1665 pResMat
->PutDouble(pow(fVal
,pMat
->GetDouble(i
)), i
);
1667 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), i
);
1670 { for ( SCSIZE i
= 0; i
< nCount
; i
++ )
1671 if (pMat
->IsValue(i
))
1672 pResMat
->PutDouble(pow(pMat
->GetDouble(i
),fVal
), i
);
1674 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), i
);
1676 PushMatrix(pResMat
);
1679 PushIllegalArgument();
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 ) )
1692 ScMatrixRef pMat1
= NULL
;
1693 ScMatrixRef pMat2
= NULL
;
1694 ScMatrixRef pMat
= NULL
;
1695 pMat2
= GetMatrix();
1698 PushIllegalParameter();
1703 pMat2
->GetDimensions(nC
, nR
);
1706 for (USHORT i
= 1; i
< nParamCount
; i
++)
1708 pMat1
= GetMatrix();
1711 PushIllegalParameter();
1714 pMat1
->GetDimensions(nC1
, nR1
);
1715 if (nC1
!= nC
|| nR1
!= nR
)
1720 ScMatrixRef pResMat
= lcl_MatrixCalculation(aMul
,pMat1
, pMat
,this);
1730 SCSIZE nCount
= pMat
->GetElementCount();
1731 for (SCSIZE j
= 0; j
< nCount
; j
++)
1733 if (!pMat
->IsString(j
))
1734 fSum
+= pMat
->GetDouble(j
);
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 ) )
1750 ScMatrixRef pMat1
= NULL
;
1751 ScMatrixRef pMat2
= NULL
;
1753 pMat2
= GetMatrix();
1754 pMat1
= GetMatrix();
1755 if (!pMat2
|| !pMat1
)
1757 PushIllegalParameter();
1762 pMat2
->GetDimensions(nC2
, nR2
);
1763 pMat1
->GetDimensions(nC1
, nR1
);
1764 if (nC1
!= nC2
|| nR1
!= nR2
)
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
);
1778 fSum
+= fVal
* fVal
;
1780 fSum
-= fVal
* fVal
;
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 ) )
1797 ScMatrixRef pMat1
= NULL
;
1798 ScMatrixRef pMat2
= NULL
;
1799 pMat2
= GetMatrix();
1800 pMat1
= GetMatrix();
1801 if (!pMat2
|| !pMat1
)
1803 PushIllegalParameter();
1808 pMat2
->GetDimensions(nC2
, nR2
);
1809 pMat1
->GetDimensions(nC1
, nR1
);
1810 if (nC1
!= nC2
|| nR1
!= nR2
)
1814 } // if (nC1 != nC2 || nR1 != nR2)
1816 ScMatrixRef pResMat
= lcl_MatrixCalculation(aSub
,pMat1
, pMat2
,this);
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
;
1835 void ScInterpreter::ScFrequency()
1837 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFrequency" );
1838 if ( !MustHaveParamCount( GetByte(), 2 ) )
1841 vector
<double> aBinArray
;
1842 vector
<long> aBinIndexOrder
;
1844 GetSortArray(1, aBinArray
, &aBinIndexOrder
);
1845 SCSIZE nBinSize
= aBinArray
.size();
1852 vector
<double> aDataArray
;
1853 GetSortArray(1, aDataArray
);
1854 SCSIZE nDataSize
= aDataArray
.size();
1856 if (aDataArray
.empty() || nGlobalError
)
1861 ScMatrixRef pResMat
= GetNewMat(1, nBinSize
+1);
1864 PushIllegalArgument();
1868 if (nBinSize
!= aBinIndexOrder
.size())
1870 PushIllegalArgument();
1876 for (j
= 0; j
< nBinSize
; ++j
)
1879 while (i
< nDataSize
&& aDataArray
[i
] <= aBinArray
[j
])
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
1896 ScMatrixRef pC
= GetNewMat(nC
, nC
);
1899 // X transformiert mit X multipziert, X'X Matrix
1900 if ( !bZeroConstant
)
1901 { // in der X-Designmatrix existiert ein gedachtes X0j==1
1904 for ( i
=0; i
<nC
; i
++ )
1906 for ( j
=0; j
<nC
; j
++ )
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
);
1920 for ( i
=0; i
<nC
; i
++ )
1922 for ( j
=0; j
<nC
; j
++ )
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
);
1939 for ( i
=0; i
<nC
; i
++ )
1941 for ( j
=0; j
<nC
; j
++ )
1944 for ( k
=0; k
<nR
; k
++ )
1946 sum
+= pX
->GetDouble(k
,j
) * pX
->GetDouble(k
,i
);
1948 pC
->PutDouble(sum
, i
, j
);
1954 for ( i
=0; i
<nC
; i
++ )
1956 for ( j
=0; j
<nC
; j
++ )
1959 for ( k
=0; k
<nR
; k
++ )
1961 sum
+= pX
->GetDouble(j
,k
) * pX
->GetDouble(i
,k
);
1963 pC
->PutDouble(sum
, i
, j
);
1970 USHORT nErr
= nGlobalError
;
1978 nGlobalError
= nErr
;
1983 // #i61216# ScMatInv no longer modifies the original matrix, so just calling Pop() doesn't work
1987 // Varianzen auf der Diagonalen, andere sind Kovarianzen
1988 for (i
= 0; i
< nC
; i
++)
1989 pV
->PutDouble(pC
->GetDouble(i
, i
), i
);
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)
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);
2008 for (i
= 0; i
< M
+1; i
++)
2009 fSQR
-= pQ
->GetDouble(i
, M
+1) * pE
->GetDouble(i
);
2011 // r2 (Bestimmtheitsmass, 0...1)
2013 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), 0, 2);
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
);
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);
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 );
2045 for (i
= 0; i
< M
+1; i
++)
2046 pResMat
->PutString(ScGlobal::GetRscString(STR_NV_STR
), i
, 1);
2051 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), 0, 3);
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);
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);
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);
2077 for (i
= 0; i
< M
+1; i
++)
2078 pResMat
->PutString(ScGlobal::GetRscString(STR_NV_STR
), i
, 1);
2082 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), 0, 3);
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
)
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();
2110 } // if (!pMatY->IsValue(i))
2111 } // for ( SCSIZE i = 0; i < nCountY; i++ )
2114 for (SCSIZE nElem
= 0; nElem
< nCountY
; nElem
++)
2116 const double fVal
= pMatY
->GetDouble(nElem
);
2119 PushIllegalArgument();
2123 pMatY
->PutDouble(log(fVal
), nElem
);
2124 } // for (nElem = 0; nElem < nCountY; nElem++)
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();
2138 if (nCX
== nCY
&& nRX
== nRY
)
2139 nCase
= 1; // einfache Regression
2140 else if (nCY
!= 1 && nRY
!= 1)
2142 PushIllegalArgument();
2149 PushIllegalArgument();
2154 nCase
= 2; // zeilenweise
2159 else if (nCX
!= nCY
)
2161 PushIllegalArgument();
2166 nCase
= 3; // spaltenweise
2173 pMatX
= GetNewMat(nCY
, nRY
);
2174 if ( _bTrendGrowth
)
2181 PushIllegalArgument();
2184 for ( SCSIZE i
= 1; i
<= nCountY
; i
++ )
2185 pMatX
->PutDouble((double)i
, i
-1);
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 ) )
2196 BOOL bConstant
, bStats
;
2197 if (nParamCount
== 4)
2201 if (nParamCount
>= 3)
2202 bConstant
= GetBool();
2207 if (nParamCount
>= 2)
2208 pMatX
= GetMatrix();
2211 pMatY
= GetMatrix();
2214 PushIllegalParameter();
2217 BYTE nCase
; // 1 = normal, 2,3 = mehrfach
2220 SCSIZE M
= 0, N
= 0;
2221 if ( !CheckMatrix(_bRKP
,FALSE
,nCase
,nCX
,nCY
,nRX
,nRY
,M
,N
,pMatX
,pMatY
) )
2224 ScMatrixRef pResMat
;
2228 pResMat
= GetNewMat(2,1);
2230 pResMat
= GetNewMat(2,5);
2233 PushIllegalArgument();
2236 double fCount
= 0.0;
2238 double fSumSqrX
= 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
);
2249 fSumSqrX
+= fValX
* fValX
;
2251 fSumSqrY
+= fValY
* fValY
;
2252 fSumXY
+= fValX
*fValY
;
2259 double f1
= fCount
*fSumXY
-fSumX
*fSumY
;
2260 double fX
= fCount
*fSumSqrX
-fSumX
*fSumX
;
2264 b
= fSumY
/fCount
- f1
/fX
*fSumX
/fCount
;
2270 m
= fSumXY
/fSumSqrX
;
2272 pResMat
->PutDouble(_bRKP
? exp(m
) : m
, 0, 0);
2273 pResMat
->PutDouble(_bRKP
? exp(b
) : b
, 1, 0);
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);
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 );
2289 pResMat
->PutDouble(sqrt(fSyx
*fCount
/(fX
*(fCount
-2.0))), 0, 1);
2290 pResMat
->PutDouble(sqrt(fSyx
*fSumSqrX
/fX
/(fCount
-2.0)), 1, 1);
2292 sqrt((fCount
*fSumSqrY
- fSumY
*fSumY
- f1
*f1
/fX
)/
2293 (fCount
*(fCount
-2.0))), 1, 2);
2295 pResMat
->PutString(ScGlobal::GetRscString(STR_NO_VALUE
), 0, 3 );
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)
2309 pResMat
= GetNewMat(M
+1,1);
2311 pResMat
= GetNewMat(M
+1,5);
2314 PushIllegalArgument();
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);
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) +
2345 pQ
->PutDouble( sumXikXjk
, j
+1, i
+1);
2346 pQ
->PutDouble( sumXikXjk
, i
+1, j
+1);
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) +
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
) )
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);
2402 for (S
= 0; S
< M
+1; S
++)
2405 while (i
< M
+1 && pQ
->GetDouble(i
, S
) == 0.0)
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
++)
2426 fVal
= -pQ
->GetDouble(i
, S
);
2427 for (L
= 0; L
< M
+2; L
++)
2429 pQ
->GetDouble(i
,L
)+fVal
*pQ
->GetDouble(S
,L
),i
,L
);
2436 if ( !Calculate3(M
,pQ
) )
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++)
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" );
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);
2458 for (k
= 0; k
< N
; k
++)
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);
2482 for (k
= 0; k
< N
; k
++)
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);
2508 for (S
= 0; S
< M
+1; S
++)
2511 while (i
< M
+1 && pQ
->GetDouble(i
, S
) == 0.0)
2516 return ScMatrixRef();
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
++)
2532 fVal
= -pQ
->GetDouble(i
, S
);
2533 for (L
= 0; L
< M
+2; L
++)
2535 pQ
->GetDouble(i
,L
)+fVal
*pQ
->GetDouble(S
,L
),i
,L
);
2542 if ( !Calculate3(M
,pQ
) )
2543 return ScMatrixRef();
2547 bool ScInterpreter::Calculate3(const SCSIZE M
,ScMatrixRef
& pQ
)
2549 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::Calculate3" );
2551 for (S
= 1; S
< M
+1; S
++)
2554 while (i
< M
+1 && pQ
->GetDouble(i
, S
) == 0.0)
2559 return ScMatrixRef();
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
++)
2575 fVal
= -pQ
->GetDouble(i
, S
);
2576 for (L
= 1; L
< M
+2; L
++)
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++)
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 ) )
2598 if (nParamCount
== 4)
2599 bConstant
= GetBool();
2604 ScMatrixRef pMatNewX
;
2605 if (nParamCount
>= 3)
2606 pMatNewX
= GetMatrix();
2609 if (nParamCount
>= 2)
2610 pMatX
= GetMatrix();
2613 pMatY
= GetMatrix();
2616 PushIllegalParameter();
2620 BYTE nCase
; // 1 = normal, 2,3 = mehrfach
2623 SCSIZE M
= 0, N
= 0;
2624 if ( !CheckMatrix(_bGrowth
,TRUE
,nCase
,nCX
,nCY
,nRX
,nRY
,M
,N
,pMatX
,pMatY
) )
2634 nCountXN
= nCXN
* nRXN
;
2639 pMatNewX
->GetDimensions(nCXN
, nRXN
);
2640 if ((nCase
== 2 && nCX
!= nCXN
) || (nCase
== 3 && nRX
!= nRXN
))
2642 PushIllegalArgument();
2645 nCountXN
= nCXN
* nRXN
;
2646 for ( SCSIZE i
= 0; i
< nCountXN
; i
++ )
2647 if (!pMatNewX
->IsValue(i
))
2649 PushIllegalArgument();
2653 ScMatrixRef pResMat
;
2656 double fCount
= 0.0;
2658 double fSumSqrX
= 0.0;
2660 double fSumSqrY
= 0.0;
2661 double fSumXY
= 0.0;
2662 double fValX
, fValY
;
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
);
2670 fSumSqrX
+= fValX
* fValX
;
2672 fSumSqrY
+= fValY
* fValY
;
2673 fSumXY
+= fValX
*fValY
;
2683 double f1
= fCount
*fSumXY
-fSumX
*fSumY
;
2684 double fX
= fCount
*fSumSqrX
-fSumX
*fSumX
;
2688 b
= fSumY
/fCount
- f1
/fX
*fSumX
/fCount
;
2694 m
= fSumXY
/fSumSqrX
;
2696 pResMat
= GetNewMat(nCXN
, nRXN
);
2699 PushIllegalArgument();
2702 for (i
= 0; i
< nCountXN
; i
++)
2704 const double d
= pMatNewX
->GetDouble(i
)*m
+b
;
2705 pResMat
->PutDouble(_bGrowth
? exp(d
) : d
, i
);
2711 ScMatrixRef pQ
= Calculate2(bConstant
,M
,N
,pMatX
,pMatY
,nCase
);
2716 pResMat
= GetNewMat(1, nRXN
);
2719 PushIllegalArgument();
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
);
2733 pResMat
= GetNewMat(nCXN
, 1);
2736 PushIllegalArgument();
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
);
2764 PopSingleRef( aAdr
);
2765 ScFormulaCell
* pCell
= (ScFormulaCell
*) GetCell( aAdr
);
2766 if( pCell
&& pCell
->GetCellType() == CELLTYPE_FORMULA
)
2768 const ScMatrix
* pMat
= pCell
->GetMatrix();
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))
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
;
2788 else if (ScMatrix::IsEmptyType( nMatValType
))
2790 // Not inherited (really?) and display as empty string, not 0.
2791 PushTempToken( new ScEmptyCellToken( false, true));
2794 PushString( pMatVal
->GetString() );
2798 PushDouble(pMatVal
->fVal
); // handles DoubleError
2799 pDok
->GetNumberFormatInfo( nCurFmtType
, nCurFmtIndex
, aAdr
, pCell
);
2800 nFuncFmtType
= nCurFmtType
;
2801 nFuncFmtIndex
= nCurFmtIndex
;
2807 // If not a result matrix, obtain the cell value.
2808 USHORT nErr
= pCell
->GetErrCode();
2811 else if( pCell
->IsValue() )
2812 PushDouble( pCell
->GetValue() );
2816 pCell
->GetString( aVal
);
2819 pDok
->GetNumberFormatInfo( nCurFmtType
, nCurFmtIndex
, aAdr
, pCell
);
2820 nFuncFmtType
= nCurFmtType
;
2821 nFuncFmtIndex
= nCurFmtIndex
;
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" ) )
2843 else if( aStr
.EqualsAscii( "RECALC" ) )
2844 PushString( ScGlobal::GetRscString( pDok
->GetAutoCalc() ? STR_RECALC_AUTO
: STR_RECALC_MANUAL
) );
2846 PushIllegalArgument();