1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <rtl/math.hxx>
25 #include <unotools/bootstrap.hxx>
26 #include <officecfg/Office/Common.hxx>
27 #include <svl/zforlist.hxx>
29 #include "interpre.hxx"
31 #include "compiler.hxx"
32 #include "formulacell.hxx"
33 #include "document.hxx"
34 #include "dociter.hxx"
35 #include "scmatrix.hxx"
36 #include "globstr.hrc"
37 #include "cellkeytranslator.hxx"
38 #include "formulagroup.hxx"
43 using namespace formula
;
47 struct MatrixAdd
: public ::std::binary_function
<double,double,double>
49 inline double operator() (const double& lhs
, const double& rhs
) const
51 return ::rtl::math::approxAdd( lhs
,rhs
);
55 struct MatrixSub
: public ::std::binary_function
<double,double,double>
57 inline double operator() (const double& lhs
, const double& rhs
) const
59 return ::rtl::math::approxSub( lhs
,rhs
);
63 struct MatrixMul
: public ::std::binary_function
<double,double,double>
65 inline double operator() (const double& lhs
, const double& rhs
) const
71 struct MatrixDiv
: public ::std::binary_function
<double,double,double>
73 inline double operator() (const double& lhs
, const double& rhs
) const
75 return ScInterpreter::div( lhs
,rhs
);
79 struct MatrixPow
: public ::std::binary_function
<double,double,double>
81 inline double operator() (const double& lhs
, const double& rhs
) const
83 return ::pow( lhs
,rhs
);
87 // Multiply n x m Mat A with m x l Mat B to n x l Mat R
88 void lcl_MFastMult(ScMatrixRef pA
, ScMatrixRef pB
, ScMatrixRef pR
,
89 SCSIZE n
, SCSIZE m
, SCSIZE l
)
92 for (SCSIZE row
= 0; row
< n
; row
++)
94 for (SCSIZE col
= 0; col
< l
; col
++)
95 { // result element(col, row) =sum[ (row of A) * (column of B)]
97 for (SCSIZE k
= 0; k
< m
; k
++)
98 sum
+= pA
->GetDouble(k
,row
) * pB
->GetDouble(col
,k
);
99 pR
->PutDouble(sum
, col
, row
);
106 double ScInterpreter::ScGetGCD(double fx
, double fy
)
108 // By ODFF definition GCD(0,a) => a. This is also vital for the code in
109 // ScGCD() to work correctly with a preset fy=0.0
116 double fz
= fmod(fx
, fy
);
127 void ScInterpreter::ScGCD()
129 short nParamCount
= GetByte();
130 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
134 size_t nRefInList
= 0;
135 while (!nGlobalError
&& nParamCount
-- > 0)
137 switch (GetStackType())
143 fx
= ::rtl::math::approxFloor( GetDouble());
146 PushIllegalArgument();
149 fy
= ScGetGCD(fx
, fy
);
156 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
158 ScValueIterator
aValIter( pDok
, aRange
, mnSubTotalFlags
);
159 if (aValIter
.GetFirst(nCellVal
, nErr
))
163 fx
= ::rtl::math::approxFloor( nCellVal
);
166 PushIllegalArgument();
169 fy
= ScGetGCD(fx
, fy
);
170 } while (nErr
== 0 && aValIter
.GetNext(nCellVal
, nErr
));
176 case svExternalSingleRef
:
177 case svExternalDoubleRef
:
179 ScMatrixRef pMat
= GetMatrix();
183 pMat
->GetDimensions(nC
, nR
);
184 if (nC
== 0 || nR
== 0)
185 SetError(errIllegalArgument
);
188 for ( SCSIZE j
= 0; j
< nC
; j
++ )
190 for (SCSIZE k
= 0; k
< nR
; ++k
)
192 if (!pMat
->IsValue(j
,k
))
194 PushIllegalArgument();
197 fx
= ::rtl::math::approxFloor( pMat
->GetDouble(j
,k
));
200 PushIllegalArgument();
203 fy
= ScGetGCD(fx
, fy
);
210 default : SetError(errIllegalParameter
); break;
217 void ScInterpreter:: ScLCM()
219 short nParamCount
= GetByte();
220 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
224 size_t nRefInList
= 0;
225 while (!nGlobalError
&& nParamCount
-- > 0)
227 switch (GetStackType())
233 fx
= ::rtl::math::approxFloor( GetDouble());
236 PushIllegalArgument();
239 if (fx
== 0.0 || fy
== 0.0)
242 fy
= fx
* fy
/ ScGetGCD(fx
, fy
);
249 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
251 ScValueIterator
aValIter( pDok
, aRange
, mnSubTotalFlags
);
252 if (aValIter
.GetFirst(nCellVal
, nErr
))
256 fx
= ::rtl::math::approxFloor( nCellVal
);
259 PushIllegalArgument();
262 if (fx
== 0.0 || fy
== 0.0)
265 fy
= fx
* fy
/ ScGetGCD(fx
, fy
);
266 } while (nErr
== 0 && aValIter
.GetNext(nCellVal
, nErr
));
272 case svExternalSingleRef
:
273 case svExternalDoubleRef
:
275 ScMatrixRef pMat
= GetMatrix();
279 pMat
->GetDimensions(nC
, nR
);
280 if (nC
== 0 || nR
== 0)
281 SetError(errIllegalArgument
);
284 for ( SCSIZE j
= 0; j
< nC
; j
++ )
286 for (SCSIZE k
= 0; k
< nR
; ++k
)
288 if (!pMat
->IsValue(j
,k
))
290 PushIllegalArgument();
293 fx
= ::rtl::math::approxFloor( pMat
->GetDouble(j
,k
));
296 PushIllegalArgument();
299 if (fx
== 0.0 || fy
== 0.0)
302 fy
= fx
* fy
/ ScGetGCD(fx
, fy
);
309 default : SetError(errIllegalParameter
); break;
316 ScMatrixRef
ScInterpreter::GetNewMat(SCSIZE nC
, SCSIZE nR
, bool bEmpty
)
320 pMat
= new ScMatrix(nC
, nR
);
322 pMat
= new ScMatrix(nC
, nR
, 0.0);
324 pMat
->SetErrorInterpreter( this);
325 // A temporary matrix is mutable and ScMatrix::CloneIfConst() returns the
327 pMat
->SetImmutable( false);
329 pMat
->GetDimensions( nCols
, nRows
);
330 if ( nCols
!= nC
|| nRows
!= nR
)
331 { // arbitray limit of elements exceeded
332 SetError( errStackOverflow
);
338 ScMatrixRef
ScInterpreter::CreateMatrixFromDoubleRef( const FormulaToken
* pToken
,
339 SCCOL nCol1
, SCROW nRow1
, SCTAB nTab1
,
340 SCCOL nCol2
, SCROW nRow2
, SCTAB nTab2
)
342 if (nTab1
!= nTab2
|| nGlobalError
)
345 SetError(errIllegalParameter
);
349 SCSIZE nMatCols
= static_cast<SCSIZE
>(nCol2
- nCol1
+ 1);
350 SCSIZE nMatRows
= static_cast<SCSIZE
>(nRow2
- nRow1
+ 1);
352 if (nMatRows
* nMatCols
> ScMatrix::GetElementsMax())
354 SetError(errStackOverflow
);
358 ScTokenMatrixMap::const_iterator aIter
;
359 if (pTokenMatrixMap
&& ((aIter
= pTokenMatrixMap
->find( pToken
))
360 != pTokenMatrixMap
->end()))
362 return (*aIter
).second
.get()->GetMatrix();
365 ScMatrixRef pMat
= GetNewMat( nMatCols
, nMatRows
, true);
366 if (!pMat
|| nGlobalError
)
369 pDok
->FillMatrix(*pMat
, nTab1
, nCol1
, nRow1
, nCol2
, nRow2
);
372 pTokenMatrixMap
->insert( ScTokenMatrixMap::value_type(
373 pToken
, new ScMatrixToken( pMat
)));
378 ScMatrixRef
ScInterpreter::GetMatrix()
380 ScMatrixRef pMat
= NULL
;
381 switch (GetRawStackType())
386 PopSingleRef( aAdr
);
387 pMat
= GetNewMat(1, 1);
390 ScRefCellValue aCell
;
391 aCell
.assign(*pDok
, aAdr
);
392 if (aCell
.hasEmptyValue())
393 pMat
->PutEmpty(0, 0);
394 else if (aCell
.hasNumeric())
395 pMat
->PutDouble(GetCellValue(aAdr
, aCell
), 0);
398 svl::SharedString aStr
;
399 GetCellString(aStr
, aCell
);
400 pMat
->PutString(aStr
, 0);
410 const formula::FormulaToken
* p
= sp
? pStack
[sp
-1] : NULL
;
411 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
412 pMat
= CreateMatrixFromDoubleRef( p
, nCol1
, nRow1
, nTab1
,
413 nCol2
, nRow2
, nTab2
);
423 double fVal
= GetDouble();
424 pMat
= GetNewMat( 1, 1);
429 fVal
= CreateDoubleError( nGlobalError
);
432 pMat
->PutDouble( fVal
, 0);
438 svl::SharedString aStr
= GetString();
439 pMat
= GetNewMat( 1, 1);
444 double fVal
= CreateDoubleError( nGlobalError
);
445 pMat
->PutDouble( fVal
, 0);
449 pMat
->PutString(aStr
, 0);
453 case svExternalSingleRef
:
455 ScExternalRefCache::TokenRef pToken
;
456 PopExternalSingleRef(pToken
);
460 SetError( errIllegalArgument
);
463 if (pToken
->GetType() == svDouble
)
465 pMat
= new ScMatrix(1, 1, 0.0);
466 pMat
->PutDouble(pToken
->GetDouble(), 0, 0);
468 else if (pToken
->GetType() == svString
)
470 pMat
= new ScMatrix(1, 1, 0.0);
471 pMat
->PutString(pToken
->GetString(), 0, 0);
475 pMat
= new ScMatrix(1, 1);
479 case svExternalDoubleRef
:
480 PopExternalDoubleRef(pMat
);
484 SetError( errIllegalArgument
);
490 sc::RangeMatrix
ScInterpreter::GetRangeMatrix()
492 sc::RangeMatrix aRet
;
493 switch (GetRawStackType())
496 aRet
= PopRangeMatrix();
499 aRet
.mpMat
= GetMatrix();
504 void ScInterpreter::ScMatValue()
506 if ( MustHaveParamCount( GetByte(), 3 ) )
509 SCSIZE nR
= static_cast<SCSIZE
>(::rtl::math::approxFloor(GetDouble()));
510 SCSIZE nC
= static_cast<SCSIZE
>(::rtl::math::approxFloor(GetDouble()));
511 switch (GetStackType())
516 PopSingleRef( aAdr
);
517 ScRefCellValue aCell
;
518 aCell
.assign(*pDok
, aAdr
);
519 if (aCell
.meType
== CELLTYPE_FORMULA
)
521 sal_uInt16 nErrCode
= aCell
.mpFormula
->GetErrCode();
523 PushError( nErrCode
);
526 const ScMatrix
* pMat
= aCell
.mpFormula
->GetMatrix();
527 CalculateMatrixValue(pMat
,nC
,nR
);
531 PushIllegalParameter();
542 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
543 if (nCol2
- nCol1
>= static_cast<SCCOL
>(nR
) &&
544 nRow2
- nRow1
>= static_cast<SCROW
>(nC
) &&
547 ScAddress
aAdr( sal::static_int_cast
<SCCOL
>( nCol1
+ nR
),
548 sal::static_int_cast
<SCROW
>( nRow1
+ nC
), nTab1
);
549 ScRefCellValue aCell
;
550 aCell
.assign(*pDok
, aAdr
);
551 if (aCell
.hasNumeric())
552 PushDouble(GetCellValue(aAdr
, aCell
));
555 svl::SharedString aStr
;
556 GetCellString(aStr
, aCell
);
566 ScMatrixRef pMat
= PopMatrix();
567 CalculateMatrixValue(pMat
.get(),nC
,nR
);
572 PushIllegalParameter();
577 void ScInterpreter::CalculateMatrixValue(const ScMatrix
* pMat
,SCSIZE nC
,SCSIZE nR
)
582 pMat
->GetDimensions(nCl
, nRw
);
583 if (nC
< nCl
&& nR
< nRw
)
585 const ScMatrixValue nMatVal
= pMat
->Get( nC
, nR
);
586 ScMatValType nMatValType
= nMatVal
.nType
;
587 if (ScMatrix::IsNonValueType( nMatValType
))
588 PushString( nMatVal
.GetString() );
590 PushDouble(nMatVal
.fVal
);
591 // also handles DoubleError
600 void ScInterpreter::ScEMat()
602 if ( MustHaveParamCount( GetByte(), 1 ) )
604 SCSIZE nDim
= static_cast<SCSIZE
>(::rtl::math::approxFloor(GetDouble()));
605 if ( nDim
* nDim
> ScMatrix::GetElementsMax() || nDim
== 0)
606 PushIllegalArgument();
609 ScMatrixRef pRMat
= GetNewMat(nDim
, nDim
);
616 PushIllegalArgument();
621 void ScInterpreter::MEMat(const ScMatrixRef
& mM
, SCSIZE n
)
623 mM
->FillDouble(0.0, 0, 0, n
-1, n
-1);
624 for (SCSIZE i
= 0; i
< n
; i
++)
625 mM
->PutDouble(1.0, i
, i
);
628 /* Matrix LUP decomposition according to the pseudocode of "Introduction to
629 * Algorithms" by Cormen, Leiserson, Rivest, Stein.
631 * Added scaling for numeric stability.
633 * Given an n x n nonsingular matrix A, find a permutation matrix P, a unit
634 * lower-triangular matrix L, and an upper-triangular matrix U such that PA=LU.
635 * Compute L and U "in place" in the matrix A, the original content is
636 * destroyed. Note that the diagonal elements of the U triangular matrix
637 * replace the diagonal elements of the L-unit matrix (that are each ==1). The
638 * permutation matrix P is an array, where P[i]=j means that the i-th row of P
639 * contains a 1 in column j. Additionally keep track of the number of
640 * permutations (row exchanges).
642 * Returns 0 if a singular matrix is encountered, else +1 if an even number of
643 * permutations occurred, or -1 if odd, which is the sign of the determinant.
644 * This may be used to calculate the determinant by multiplying the sign with
645 * the product of the diagonal elements of the LU matrix.
647 static int lcl_LUP_decompose( ScMatrix
* mA
, const SCSIZE n
,
648 ::std::vector
< SCSIZE
> & P
)
651 // Find scale of each row.
652 ::std::vector
< double> aScale(n
);
653 for (SCSIZE i
=0; i
< n
; ++i
)
656 for (SCSIZE j
=0; j
< n
; ++j
)
658 double fTmp
= fabs( mA
->GetDouble( j
, i
));
663 return 0; // singular matrix
664 aScale
[i
] = 1.0 / fMax
;
666 // Represent identity permutation, P[i]=i
667 for (SCSIZE i
=0; i
< n
; ++i
)
669 // "Recursion" on the diagonale.
671 for (SCSIZE k
=0; k
< l
; ++k
)
673 // Implicit pivoting. With the scale found for a row, compare values of
674 // a column and pick largest.
676 double fScale
= aScale
[k
];
678 for (SCSIZE i
= k
; i
< n
; ++i
)
680 double fTmp
= fScale
* fabs( mA
->GetDouble( k
, i
));
688 return 0; // singular matrix
689 // Swap rows. The pivot element will be at mA[k,kp] (row,col notation)
698 double fTmp
= aScale
[k
];
699 aScale
[k
] = aScale
[kp
];
702 for (SCSIZE i
=0; i
< n
; ++i
)
704 double fMatTmp
= mA
->GetDouble( i
, k
);
705 mA
->PutDouble( mA
->GetDouble( i
, kp
), i
, k
);
706 mA
->PutDouble( fMatTmp
, i
, kp
);
709 // Compute Schur complement.
710 for (SCSIZE i
= k
+1; i
< n
; ++i
)
712 double fNum
= mA
->GetDouble( k
, i
);
713 double fDen
= mA
->GetDouble( k
, k
);
714 mA
->PutDouble( fNum
/fDen
, k
, i
);
715 for (SCSIZE j
= k
+1; j
< n
; ++j
)
716 mA
->PutDouble( ( mA
->GetDouble( j
, i
) * fDen
-
717 fNum
* mA
->GetDouble( j
, k
) ) / fDen
, j
, i
);
720 #if OSL_DEBUG_LEVEL > 1
721 fprintf( stderr
, "\n%s\n", "lcl_LUP_decompose(): LU");
722 for (SCSIZE i
=0; i
< n
; ++i
)
724 for (SCSIZE j
=0; j
< n
; ++j
)
725 fprintf( stderr
, "%8.2g ", mA
->GetDouble( j
, i
));
726 fprintf( stderr
, "\n%s\n", "");
728 fprintf( stderr
, "\n%s\n", "lcl_LUP_decompose(): P");
729 for (SCSIZE j
=0; j
< n
; ++j
)
730 fprintf( stderr
, "%5u ", (unsigned)P
[j
]);
731 fprintf( stderr
, "\n%s\n", "");
734 bool bSingular
=false;
735 for (SCSIZE i
=0; i
<n
&& !bSingular
; i
++)
736 bSingular
= bSingular
|| ((mA
->GetDouble(i
,i
))==0.0);
743 /* Solve a LUP decomposed equation Ax=b. LU is a combined matrix of L and U
744 * triangulars and P the permutation vector as obtained from
745 * lcl_LUP_decompose(). B is the right-hand side input vector, X is used to
746 * return the solution vector.
748 static void lcl_LUP_solve( const ScMatrix
* mLU
, const SCSIZE n
,
749 const ::std::vector
< SCSIZE
> & P
, const ::std::vector
< double> & B
,
750 ::std::vector
< double> & X
)
752 SCSIZE nFirst
= SCSIZE_MAX
;
753 // Ax=b => PAx=Pb, with decomposition LUx=Pb.
754 // Define y=Ux and solve for y in Ly=Pb using forward substitution.
755 for (SCSIZE i
=0; i
< n
; ++i
)
757 double fSum
= B
[P
[i
]];
758 // Matrix inversion comes with a lot of zeros in the B vectors, we
759 // don't have to do all the computing with results multiplied by zero.
760 // Until then, simply lookout for the position of the first nonzero
762 if (nFirst
!= SCSIZE_MAX
)
764 for (SCSIZE j
= nFirst
; j
< i
; ++j
)
765 fSum
-= mLU
->GetDouble( j
, i
) * X
[j
]; // X[j] === y[j]
769 X
[i
] = fSum
; // X[i] === y[i]
771 // Solve for x in Ux=y using back substitution.
772 for (SCSIZE i
= n
; i
--; )
774 double fSum
= X
[i
]; // X[i] === y[i]
775 for (SCSIZE j
= i
+1; j
< n
; ++j
)
776 fSum
-= mLU
->GetDouble( j
, i
) * X
[j
]; // X[j] === x[j]
777 X
[i
] = fSum
/ mLU
->GetDouble( i
, i
); // X[i] === x[i]
779 #if OSL_DEBUG_LEVEL >1
780 fprintf( stderr
, "\n%s\n", "lcl_LUP_solve():");
781 for (SCSIZE i
=0; i
< n
; ++i
)
782 fprintf( stderr
, "%8.2g ", X
[i
]);
783 fprintf( stderr
, "%s\n", "");
787 void ScInterpreter::ScMatDet()
789 if ( MustHaveParamCount( GetByte(), 1 ) )
791 ScMatrixRef pMat
= GetMatrix();
794 PushIllegalParameter();
797 if ( !pMat
->IsNumeric() )
803 pMat
->GetDimensions(nC
, nR
);
804 if ( nC
!= nR
|| nC
== 0 || (sal_uLong
) nC
* nC
> ScMatrix::GetElementsMax() )
805 PushIllegalArgument();
808 // LUP decomposition is done inplace, use copy.
809 ScMatrixRef xLU
= pMat
->Clone();
811 PushError( errCodeOverflow
);
814 ::std::vector
< SCSIZE
> P(nR
);
815 int nDetSign
= lcl_LUP_decompose( xLU
.get(), nR
, P
);
817 PushInt(0); // singular matrix
820 // In an LU matrix the determinant is simply the product of
821 // all diagonal elements.
822 double fDet
= nDetSign
;
823 for (SCSIZE i
=0; i
< nR
; ++i
)
824 fDet
*= xLU
->GetDouble( i
, i
);
832 void ScInterpreter::ScModalValue_Multi()
834 sal_uInt8 nParamCount
= GetByte();
835 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
837 vector
<double> aSortArray
;
838 GetSortArray( nParamCount
, aSortArray
, NULL
, false, false );
839 SCSIZE nSize
= aSortArray
.size();
840 if ( aSortArray
.empty() || nSize
== 0 || nGlobalError
)
844 SCSIZE nMax
= 1, nCount
= 1;
845 double nOldVal
= aSortArray
[0];
846 vector
<double> aResultArray
;
847 aResultArray
.resize( 1 );
848 aResultArray
[ 0 ] = aSortArray
[ 0 ];
851 for ( i
= 1; i
< nSize
; i
++ )
853 if ( aSortArray
[ i
] == nOldVal
)
856 if ( nCount
> nMax
&& aResultArray
.size() > 1 )
858 aResultArray
.clear();
859 aResultArray
.resize( 1 );
860 aResultArray
[ 0 ] = nOldVal
;
865 nOldVal
= aSortArray
[ i
];
866 if ( nCount
>= nMax
)
870 aResultArray
.resize( aResultArray
.size() + 1 );
872 aResultArray
[ aResultArray
.size() -1 ] = nOldVal
;
881 aResultArray
.resize( aResultArray
.size() - 1 );
884 if ( nMax
== 1 && nCount
== 1 )
888 ScMatrixRef pResMatrix
= GetNewMat( 1, aResultArray
.size(), true );
889 pResMatrix
->PutDoubleVector( aResultArray
, 0, 0 );
890 PushMatrix( pResMatrix
);
895 void ScInterpreter::ScMatInv()
897 if ( MustHaveParamCount( GetByte(), 1 ) )
899 ScMatrixRef pMat
= GetMatrix();
902 PushIllegalParameter();
905 if ( !pMat
->IsNumeric() )
911 pMat
->GetDimensions(nC
, nR
);
913 if (officecfg::Office::Common::Misc::UseOpenCL::get())
915 sc::FormulaGroupInterpreter
*pInterpreter
= sc::FormulaGroupInterpreter::getStatic();
916 if (pInterpreter
!= NULL
)
918 ScMatrixRef xResMat
= pInterpreter
->inverseMatrix(*pMat
);
927 if ( nC
!= nR
|| nC
== 0 || (sal_uLong
) nC
* nC
> ScMatrix::GetElementsMax() )
928 PushIllegalArgument();
931 // LUP decomposition is done inplace, use copy.
932 ScMatrixRef xLU
= pMat
->Clone();
933 // The result matrix.
934 ScMatrixRef xY
= GetNewMat( nR
, nR
);
936 PushError( errCodeOverflow
);
939 ::std::vector
< SCSIZE
> P(nR
);
940 int nDetSign
= lcl_LUP_decompose( xLU
.get(), nR
, P
);
942 PushIllegalArgument();
945 // Solve equation for each column.
946 ::std::vector
< double> B(nR
);
947 ::std::vector
< double> X(nR
);
948 for (SCSIZE j
=0; j
< nR
; ++j
)
950 for (SCSIZE i
=0; i
< nR
; ++i
)
953 lcl_LUP_solve( xLU
.get(), nR
, P
, B
, X
);
954 for (SCSIZE i
=0; i
< nR
; ++i
)
955 xY
->PutDouble( X
[i
], j
, i
);
957 #if OSL_DEBUG_LEVEL > 1
958 /* Possible checks for ill-condition:
959 * 1. Scale matrix, invert scaled matrix. If there are
960 * elements of the inverted matrix that are several
961 * orders of magnitude greater than 1 =>
963 * Just how much is "several orders"?
964 * 2. Invert the inverted matrix and assess whether the
965 * result is sufficiently close to the original matrix.
966 * If not => ill-conditioned.
967 * Just what is sufficient?
968 * 3. Multiplying the inverse by the original matrix should
969 * produce a result sufficiently close to the identity
971 * Just what is sufficient?
973 * The following is #3.
975 const double fInvEpsilon
= 1.0E-7;
976 ScMatrixRef xR
= GetNewMat( nR
, nR
);
979 ScMatrix
* pR
= xR
.get();
980 lcl_MFastMult( pMat
, xY
.get(), pR
, nR
, nR
, nR
);
981 fprintf( stderr
, "\n%s\n", "ScMatInv(): mult-identity");
982 for (SCSIZE i
=0; i
< nR
; ++i
)
984 for (SCSIZE j
=0; j
< nR
; ++j
)
986 double fTmp
= pR
->GetDouble( j
, i
);
987 fprintf( stderr
, "%8.2g ", fTmp
);
988 if (fabs( fTmp
- (i
== j
)) > fInvEpsilon
)
989 SetError( errIllegalArgument
);
991 fprintf( stderr
, "\n%s\n", "");
996 PushError( nGlobalError
);
1005 void ScInterpreter::ScMatMult()
1007 if ( MustHaveParamCount( GetByte(), 2 ) )
1009 ScMatrixRef pMat2
= GetMatrix();
1010 ScMatrixRef pMat1
= GetMatrix();
1014 if ( pMat1
->IsNumeric() && pMat2
->IsNumeric() )
1018 pMat1
->GetDimensions(nC1
, nR1
);
1019 pMat2
->GetDimensions(nC2
, nR2
);
1021 PushIllegalArgument();
1024 pRMat
= GetNewMat(nC2
, nR1
);
1028 for (SCSIZE i
= 0; i
< nR1
; i
++)
1030 for (SCSIZE j
= 0; j
< nC2
; j
++)
1033 for (SCSIZE k
= 0; k
< nC1
; k
++)
1035 sum
+= pMat1
->GetDouble(k
,i
)*pMat2
->GetDouble(j
,k
);
1037 pRMat
->PutDouble(sum
, j
, i
);
1043 PushIllegalArgument();
1050 PushIllegalParameter();
1054 void ScInterpreter::ScMatTrans()
1056 if ( MustHaveParamCount( GetByte(), 1 ) )
1058 ScMatrixRef pMat
= GetMatrix();
1063 pMat
->GetDimensions(nC
, nR
);
1064 pRMat
= GetNewMat(nR
, nC
);
1067 pMat
->MatTrans(*pRMat
);
1071 PushIllegalArgument();
1074 PushIllegalParameter();
1078 /** Minimum extent of one result matrix dimension.
1079 For a row or column vector to be replicated the larger matrix dimension is
1080 returned, else the smaller dimension.
1082 static inline SCSIZE
lcl_GetMinExtent( SCSIZE n1
, SCSIZE n2
)
1094 template<class _Function
>
1095 static ScMatrixRef
lcl_MatrixCalculation(
1096 const ScMatrix
& rMat1
, const ScMatrix
& rMat2
, ScInterpreter
* pInterpreter
)
1098 static _Function Op
;
1100 SCSIZE nC1
, nC2
, nMinC
;
1101 SCSIZE nR1
, nR2
, nMinR
;
1103 rMat1
.GetDimensions(nC1
, nR1
);
1104 rMat2
.GetDimensions(nC2
, nR2
);
1105 nMinC
= lcl_GetMinExtent( nC1
, nC2
);
1106 nMinR
= lcl_GetMinExtent( nR1
, nR2
);
1107 ScMatrixRef xResMat
= pInterpreter
->GetNewMat(nMinC
, nMinR
);
1110 for (i
= 0; i
< nMinC
; i
++)
1112 for (j
= 0; j
< nMinR
; j
++)
1114 bool bVal1
= rMat1
.IsValueOrEmpty(i
,j
);
1115 bool bVal2
= rMat2
.IsValueOrEmpty(i
,j
);
1119 double d
= Op(rMat1
.GetDouble(i
,j
), rMat2
.GetDouble(i
,j
));
1120 xResMat
->PutDouble( d
, i
, j
);
1122 else if (((nErr
= rMat1
.GetErrorIfNotString(i
,j
)) != 0) ||
1123 ((nErr
= rMat2
.GetErrorIfNotString(i
,j
)) != 0))
1125 xResMat
->PutError( nErr
, i
, j
);
1127 else if ((!bVal1
&& rMat1
.IsString(i
,j
)) || (!bVal2
&& rMat2
.IsString(i
,j
)))
1129 sal_uInt16 nError1
= 0;
1131 double fVal1
= (bVal1
? rMat1
.GetDouble(i
,j
) :
1132 pInterpreter
->ConvertStringToValue( rMat1
.GetString(i
,j
).getString(), nError1
, nFmt1
));
1134 sal_uInt16 nError2
= 0;
1136 double fVal2
= (bVal2
? rMat2
.GetDouble(i
,j
) :
1137 pInterpreter
->ConvertStringToValue( rMat2
.GetString(i
,j
).getString(), nError2
, nFmt2
));
1140 xResMat
->PutError( nError1
, i
, j
);
1142 xResMat
->PutError( nError2
, i
, j
);
1145 double d
= Op( fVal1
, fVal2
);
1146 xResMat
->PutDouble( d
, i
, j
);
1150 xResMat
->PutError( errNoValue
, i
, j
);
1157 ScMatrixRef
ScInterpreter::MatConcat(const ScMatrixRef
& pMat1
, const ScMatrixRef
& pMat2
)
1159 SCSIZE nC1
, nC2
, nMinC
;
1160 SCSIZE nR1
, nR2
, nMinR
;
1162 pMat1
->GetDimensions(nC1
, nR1
);
1163 pMat2
->GetDimensions(nC2
, nR2
);
1164 nMinC
= lcl_GetMinExtent( nC1
, nC2
);
1165 nMinR
= lcl_GetMinExtent( nR1
, nR2
);
1166 ScMatrixRef xResMat
= GetNewMat(nMinC
, nMinR
);
1169 for (i
= 0; i
< nMinC
; i
++)
1171 for (j
= 0; j
< nMinR
; j
++)
1173 sal_uInt16 nErr
= pMat1
->GetErrorIfNotString( i
, j
);
1175 nErr
= pMat2
->GetErrorIfNotString( i
, j
);
1177 xResMat
->PutError( nErr
, i
, j
);
1180 OUString aTmp
= pMat1
->GetString(*pFormatter
, i
, j
).getString();
1181 aTmp
+= pMat2
->GetString(*pFormatter
, i
, j
).getString();
1182 xResMat
->PutString(mrStrPool
.intern(aTmp
), i
, j
);
1190 // for DATE, TIME, DATETIME
1191 static void lcl_GetDiffDateTimeFmtType( short& nFuncFmt
, short nFmt1
, short nFmt2
)
1193 if ( nFmt1
!= css::util::NumberFormat::UNDEFINED
|| nFmt2
!= css::util::NumberFormat::UNDEFINED
)
1195 if ( nFmt1
== nFmt2
)
1197 if ( nFmt1
== css::util::NumberFormat::TIME
|| nFmt1
== css::util::NumberFormat::DATETIME
)
1198 nFuncFmt
= css::util::NumberFormat::TIME
; // times result in time
1199 // else: nothing special, number (date - date := days)
1201 else if ( nFmt1
== css::util::NumberFormat::UNDEFINED
)
1202 nFuncFmt
= nFmt2
; // e.g. date + days := date
1203 else if ( nFmt2
== css::util::NumberFormat::UNDEFINED
)
1207 if ( nFmt1
== css::util::NumberFormat::DATE
|| nFmt2
== css::util::NumberFormat::DATE
||
1208 nFmt1
== css::util::NumberFormat::DATETIME
|| nFmt2
== css::util::NumberFormat::DATETIME
)
1210 if ( nFmt1
== css::util::NumberFormat::TIME
|| nFmt2
== css::util::NumberFormat::TIME
)
1211 nFuncFmt
= css::util::NumberFormat::DATETIME
; // date + time
1217 void ScInterpreter::ScAdd()
1219 CalculateAddSub(false);
1226 void ScInterpreter::CalculateAddSub(bool _bSub
)
1228 ScMatrixRef pMat1
= NULL
;
1229 ScMatrixRef pMat2
= NULL
;
1230 double fVal1
= 0.0, fVal2
= 0.0;
1232 nFmt1
= nFmt2
= css::util::NumberFormat::UNDEFINED
;
1233 short nFmtCurrencyType
= nCurFmtType
;
1234 sal_uLong nFmtCurrencyIndex
= nCurFmtIndex
;
1235 short nFmtPercentType
= nCurFmtType
;
1236 if ( GetStackType() == svMatrix
)
1237 pMat2
= GetMatrix();
1240 fVal2
= GetDouble();
1241 switch ( nCurFmtType
)
1243 case css::util::NumberFormat::DATE
:
1244 case css::util::NumberFormat::TIME
:
1245 case css::util::NumberFormat::DATETIME
:
1246 nFmt2
= nCurFmtType
;
1248 case css::util::NumberFormat::CURRENCY
:
1249 nFmtCurrencyType
= nCurFmtType
;
1250 nFmtCurrencyIndex
= nCurFmtIndex
;
1252 case css::util::NumberFormat::PERCENT
:
1253 nFmtPercentType
= css::util::NumberFormat::PERCENT
;
1257 if ( GetStackType() == svMatrix
)
1258 pMat1
= GetMatrix();
1261 fVal1
= GetDouble();
1262 switch ( nCurFmtType
)
1264 case css::util::NumberFormat::DATE
:
1265 case css::util::NumberFormat::TIME
:
1266 case css::util::NumberFormat::DATETIME
:
1267 nFmt1
= nCurFmtType
;
1269 case css::util::NumberFormat::CURRENCY
:
1270 nFmtCurrencyType
= nCurFmtType
;
1271 nFmtCurrencyIndex
= nCurFmtIndex
;
1273 case css::util::NumberFormat::PERCENT
:
1274 nFmtPercentType
= css::util::NumberFormat::PERCENT
;
1280 ScMatrixRef pResMat
;
1283 pResMat
= lcl_MatrixCalculation
<MatrixSub
>( *pMat1
, *pMat2
, this);
1287 pResMat
= lcl_MatrixCalculation
<MatrixAdd
>( *pMat1
, *pMat2
, this);
1293 PushMatrix(pResMat
);
1295 else if (pMat1
|| pMat2
)
1299 ScMatrixRef pMat
= pMat1
;
1304 bFlag
= true; // double - Matrix
1309 bFlag
= false; // Matrix - double
1312 pMat
->GetDimensions(nC
, nR
);
1313 ScMatrixRef pResMat
= GetNewMat(nC
, nR
, true);
1318 pMat
->SubOp( bFlag
, fVal
, *pResMat
);
1322 pMat
->AddOp( fVal
, *pResMat
);
1324 PushMatrix(pResMat
);
1327 PushIllegalArgument();
1330 PushDouble( ::rtl::math::approxSub( fVal1
, fVal2
) );
1332 PushDouble( ::rtl::math::approxAdd( fVal1
, fVal2
) );
1333 if ( nFmtCurrencyType
== css::util::NumberFormat::CURRENCY
)
1335 nFuncFmtType
= nFmtCurrencyType
;
1336 nFuncFmtIndex
= nFmtCurrencyIndex
;
1340 lcl_GetDiffDateTimeFmtType( nFuncFmtType
, nFmt1
, nFmt2
);
1341 if ( nFmtPercentType
== css::util::NumberFormat::PERCENT
&& nFuncFmtType
== css::util::NumberFormat::NUMBER
)
1342 nFuncFmtType
= css::util::NumberFormat::PERCENT
;
1346 void ScInterpreter::ScAmpersand()
1348 ScMatrixRef pMat1
= NULL
;
1349 ScMatrixRef pMat2
= NULL
;
1350 OUString sStr1
, sStr2
;
1351 if ( GetStackType() == svMatrix
)
1352 pMat2
= GetMatrix();
1354 sStr2
= GetString().getString();
1355 if ( GetStackType() == svMatrix
)
1356 pMat1
= GetMatrix();
1358 sStr1
= GetString().getString();
1361 ScMatrixRef pResMat
= MatConcat(pMat1
, pMat2
);
1365 PushMatrix(pResMat
);
1367 else if (pMat1
|| pMat2
)
1371 ScMatrixRef pMat
= pMat1
;
1376 bFlag
= true; // double - Matrix
1381 bFlag
= false; // Matrix - double
1384 pMat
->GetDimensions(nC
, nR
);
1385 ScMatrixRef pResMat
= GetNewMat(nC
, nR
);
1390 for (SCSIZE i
= 0; i
< nC
; ++i
)
1391 for (SCSIZE j
= 0; j
< nR
; ++j
)
1392 pResMat
->PutError( nGlobalError
, i
, j
);
1396 for (SCSIZE i
= 0; i
< nC
; ++i
)
1397 for (SCSIZE j
= 0; j
< nR
; ++j
)
1399 sal_uInt16 nErr
= pMat
->GetErrorIfNotString( i
, j
);
1401 pResMat
->PutError( nErr
, i
, j
);
1404 OUString aTmp
= sStr
;
1405 aTmp
+= pMat
->GetString(*pFormatter
, i
, j
).getString();
1406 pResMat
->PutString(mrStrPool
.intern(aTmp
), i
, j
);
1412 for (SCSIZE i
= 0; i
< nC
; ++i
)
1413 for (SCSIZE j
= 0; j
< nR
; ++j
)
1415 sal_uInt16 nErr
= pMat
->GetErrorIfNotString( i
, j
);
1417 pResMat
->PutError( nErr
, i
, j
);
1420 OUString aTmp
= pMat
->GetString(*pFormatter
, i
, j
).getString();
1422 pResMat
->PutString(mrStrPool
.intern(aTmp
), i
, j
);
1426 PushMatrix(pResMat
);
1429 PushIllegalArgument();
1433 if ( CheckStringResultLen( sStr1
, sStr2
) )
1439 void ScInterpreter::ScSub()
1441 CalculateAddSub(true);
1444 void ScInterpreter::ScMul()
1446 ScMatrixRef pMat1
= NULL
;
1447 ScMatrixRef pMat2
= NULL
;
1448 double fVal1
= 0.0, fVal2
= 0.0;
1449 short nFmtCurrencyType
= nCurFmtType
;
1450 sal_uLong nFmtCurrencyIndex
= nCurFmtIndex
;
1451 if ( GetStackType() == svMatrix
)
1452 pMat2
= GetMatrix();
1455 fVal2
= GetDouble();
1456 switch ( nCurFmtType
)
1458 case css::util::NumberFormat::CURRENCY
:
1459 nFmtCurrencyType
= nCurFmtType
;
1460 nFmtCurrencyIndex
= nCurFmtIndex
;
1464 if ( GetStackType() == svMatrix
)
1465 pMat1
= GetMatrix();
1468 fVal1
= GetDouble();
1469 switch ( nCurFmtType
)
1471 case css::util::NumberFormat::CURRENCY
:
1472 nFmtCurrencyType
= nCurFmtType
;
1473 nFmtCurrencyIndex
= nCurFmtIndex
;
1479 ScMatrixRef pResMat
= lcl_MatrixCalculation
<MatrixMul
>( *pMat1
, *pMat2
, this);
1483 PushMatrix(pResMat
);
1485 else if (pMat1
|| pMat2
)
1488 ScMatrixRef pMat
= pMat1
;
1497 pMat
->GetDimensions(nC
, nR
);
1498 ScMatrixRef pResMat
= GetNewMat(nC
, nR
);
1501 pMat
->MulOp( fVal
, *pResMat
);
1502 PushMatrix(pResMat
);
1505 PushIllegalArgument();
1508 PushDouble(fVal1
* fVal2
);
1509 if ( nFmtCurrencyType
== css::util::NumberFormat::CURRENCY
)
1511 nFuncFmtType
= nFmtCurrencyType
;
1512 nFuncFmtIndex
= nFmtCurrencyIndex
;
1516 void ScInterpreter::ScDiv()
1518 ScMatrixRef pMat1
= NULL
;
1519 ScMatrixRef pMat2
= NULL
;
1520 double fVal1
= 0.0, fVal2
= 0.0;
1521 short nFmtCurrencyType
= nCurFmtType
;
1522 sal_uLong nFmtCurrencyIndex
= nCurFmtIndex
;
1523 short nFmtCurrencyType2
= css::util::NumberFormat::UNDEFINED
;
1524 if ( GetStackType() == svMatrix
)
1525 pMat2
= GetMatrix();
1528 fVal2
= GetDouble();
1529 // do not take over currency, 123kg/456USD is not USD
1530 nFmtCurrencyType2
= nCurFmtType
;
1532 if ( GetStackType() == svMatrix
)
1533 pMat1
= GetMatrix();
1536 fVal1
= GetDouble();
1537 switch ( nCurFmtType
)
1539 case css::util::NumberFormat::CURRENCY
:
1540 nFmtCurrencyType
= nCurFmtType
;
1541 nFmtCurrencyIndex
= nCurFmtIndex
;
1547 ScMatrixRef pResMat
= lcl_MatrixCalculation
<MatrixDiv
>( *pMat1
, *pMat2
, this);
1551 PushMatrix(pResMat
);
1553 else if (pMat1
|| pMat2
)
1557 ScMatrixRef pMat
= pMat1
;
1562 bFlag
= true; // double - Matrix
1567 bFlag
= false; // Matrix - double
1570 pMat
->GetDimensions(nC
, nR
);
1571 ScMatrixRef pResMat
= GetNewMat(nC
, nR
);
1574 pMat
->DivOp( bFlag
, fVal
, *pResMat
);
1575 PushMatrix(pResMat
);
1578 PushIllegalArgument();
1582 PushDouble( div( fVal1
, fVal2
) );
1584 if ( nFmtCurrencyType
== css::util::NumberFormat::CURRENCY
&& nFmtCurrencyType2
!= css::util::NumberFormat::CURRENCY
)
1585 { // even USD/USD is not USD
1586 nFuncFmtType
= nFmtCurrencyType
;
1587 nFuncFmtIndex
= nFmtCurrencyIndex
;
1591 void ScInterpreter::ScPower()
1593 if ( MustHaveParamCount( GetByte(), 2 ) )
1597 void ScInterpreter::ScPow()
1599 ScMatrixRef pMat1
= NULL
;
1600 ScMatrixRef pMat2
= NULL
;
1601 double fVal1
= 0.0, fVal2
= 0.0;
1602 if ( GetStackType() == svMatrix
)
1603 pMat2
= GetMatrix();
1605 fVal2
= GetDouble();
1606 if ( GetStackType() == svMatrix
)
1607 pMat1
= GetMatrix();
1609 fVal1
= GetDouble();
1612 ScMatrixRef pResMat
= lcl_MatrixCalculation
<MatrixPow
>( *pMat1
, *pMat2
, this);
1616 PushMatrix(pResMat
);
1618 else if (pMat1
|| pMat2
)
1622 ScMatrixRef pMat
= pMat1
;
1627 bFlag
= true; // double - Matrix
1632 bFlag
= false; // Matrix - double
1635 pMat
->GetDimensions(nC
, nR
);
1636 ScMatrixRef pResMat
= GetNewMat(nC
, nR
);
1639 pMat
->PowOp( bFlag
, fVal
, *pResMat
);
1640 PushMatrix(pResMat
);
1643 PushIllegalArgument();
1647 if (fVal1
< 0 && fVal2
!= 0.0)
1649 int i
= (int) (1 / fVal2
+ ((fVal2
< 0) ? -0.5 : 0.5));
1650 if (rtl::math::approxEqual(1 / ((double) i
), fVal2
) && i
% 2 != 0)
1651 PushDouble(-pow(-fVal1
, fVal2
));
1653 PushDouble(pow(fVal1
, fVal2
));
1657 PushDouble(pow(fVal1
,fVal2
));
1664 class SumValues
: std::unary_function
<double, void>
1669 SumValues() : mfSum(0.0), mbError(false) {}
1671 void operator() (double f
)
1676 sal_uInt16 nErr
= GetDoubleErrorValue(f
);
1679 else if (nErr
!= errElementNaN
)
1681 // Propagate the first error encountered, ignore "this is not a
1682 // number" elements.
1688 double getValue() const { return mfSum
; }
1693 void ScInterpreter::ScSumProduct()
1695 sal_uInt8 nParamCount
= GetByte();
1696 if ( !MustHaveParamCount( nParamCount
, 1, 30 ) )
1699 ScMatrixRef pMatLast
;
1702 pMatLast
= GetMatrix();
1705 PushIllegalParameter();
1709 SCSIZE nC
, nCLast
, nR
, nRLast
;
1710 pMatLast
->GetDimensions(nCLast
, nRLast
);
1711 std::vector
<double> aResArray
;
1712 pMatLast
->GetDoubleArray(aResArray
);
1714 for (sal_uInt16 i
= 1; i
< nParamCount
; ++i
)
1719 PushIllegalParameter();
1722 pMat
->GetDimensions(nC
, nR
);
1723 if (nC
!= nCLast
|| nR
!= nRLast
)
1729 pMat
->MergeDoubleArray(aResArray
, ScMatrix::Mul
);
1732 double fSum
= std::for_each(aResArray
.begin(), aResArray
.end(), SumValues()).getValue();
1736 void ScInterpreter::ScSumX2MY2()
1738 CalculateSumX2MY2SumX2DY2(false);
1740 void ScInterpreter::CalculateSumX2MY2SumX2DY2(bool _bSumX2DY2
)
1742 if ( !MustHaveParamCount( GetByte(), 2 ) )
1745 ScMatrixRef pMat1
= NULL
;
1746 ScMatrixRef pMat2
= NULL
;
1748 pMat2
= GetMatrix();
1749 pMat1
= GetMatrix();
1750 if (!pMat2
|| !pMat1
)
1752 PushIllegalParameter();
1757 pMat2
->GetDimensions(nC2
, nR2
);
1758 pMat1
->GetDimensions(nC1
, nR1
);
1759 if (nC1
!= nC2
|| nR1
!= nR2
)
1764 double fVal
, fSum
= 0.0;
1765 for (i
= 0; i
< nC1
; i
++)
1766 for (j
= 0; j
< nR1
; j
++)
1767 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
1769 fVal
= pMat1
->GetDouble(i
,j
);
1770 fSum
+= fVal
* fVal
;
1771 fVal
= pMat2
->GetDouble(i
,j
);
1773 fSum
+= fVal
* fVal
;
1775 fSum
-= fVal
* fVal
;
1780 void ScInterpreter::ScSumX2DY2()
1782 CalculateSumX2MY2SumX2DY2(true);
1785 void ScInterpreter::ScSumXMY2()
1787 if ( !MustHaveParamCount( GetByte(), 2 ) )
1790 ScMatrixRef pMat1
= NULL
;
1791 ScMatrixRef pMat2
= NULL
;
1792 pMat2
= GetMatrix();
1793 pMat1
= GetMatrix();
1794 if (!pMat2
|| !pMat1
)
1796 PushIllegalParameter();
1801 pMat2
->GetDimensions(nC2
, nR2
);
1802 pMat1
->GetDimensions(nC1
, nR1
);
1803 if (nC1
!= nC2
|| nR1
!= nR2
)
1807 } // if (nC1 != nC2 || nR1 != nR2)
1808 ScMatrixRef pResMat
= lcl_MatrixCalculation
<MatrixSub
>( *pMat1
, *pMat2
, this);
1815 ScMatrix::IterateResult aRes
= pResMat
->SumSquare(false);
1816 double fSum
= aRes
.mfFirst
+ aRes
.mfRest
;
1821 void ScInterpreter::ScFrequency()
1823 if ( !MustHaveParamCount( GetByte(), 2 ) )
1826 vector
<double> aBinArray
;
1827 vector
<long> aBinIndexOrder
;
1829 GetSortArray( 1, aBinArray
, &aBinIndexOrder
, false, false );
1830 SCSIZE nBinSize
= aBinArray
.size();
1837 vector
<double> aDataArray
;
1838 GetSortArray( 1, aDataArray
, NULL
, false, false );
1839 SCSIZE nDataSize
= aDataArray
.size();
1841 if (aDataArray
.empty() || nGlobalError
)
1846 ScMatrixRef pResMat
= GetNewMat(1, nBinSize
+1);
1849 PushIllegalArgument();
1853 if (nBinSize
!= aBinIndexOrder
.size())
1855 PushIllegalArgument();
1861 for (j
= 0; j
< nBinSize
; ++j
)
1864 while (i
< nDataSize
&& aDataArray
[i
] <= aBinArray
[j
])
1869 pResMat
->PutDouble(static_cast<double>(nCount
), aBinIndexOrder
[j
]);
1871 pResMat
->PutDouble(static_cast<double>(nDataSize
-i
), j
);
1872 PushMatrix(pResMat
);
1877 // Helper methods for LINEST/LOGEST and TREND/GROWTH
1878 // All matrices must already exist and have the needed size, no control tests
1879 // done. Those methods, which names start with lcl_T, are adapted to case 3,
1880 // where Y (=observed values) is given as row.
1881 // Remember, ScMatrix matrices are zero based, index access (column,row).
1883 // <A;B> over all elements; uses the matrices as vectors of length M
1884 double lcl_GetSumProduct(ScMatrixRef pMatA
, ScMatrixRef pMatB
, SCSIZE nM
)
1887 for (SCSIZE i
=0; i
<nM
; i
++)
1888 fSum
+= pMatA
->GetDouble(i
) * pMatB
->GetDouble(i
);
1892 // Special version for use within QR decomposition.
1893 // Euclidean norm of column index C starting in row index R;
1894 // matrix A has count N rows.
1895 double lcl_GetColumnEuclideanNorm(ScMatrixRef pMatA
, SCSIZE nC
, SCSIZE nR
, SCSIZE nN
)
1898 for (SCSIZE row
=nR
; row
<nN
; row
++)
1899 fNorm
+= (pMatA
->GetDouble(nC
,row
)) * (pMatA
->GetDouble(nC
,row
));
1903 // Euclidean norm of row index R starting in column index C;
1904 // matrix A has count N columns.
1905 double lcl_TGetColumnEuclideanNorm(ScMatrixRef pMatA
, SCSIZE nR
, SCSIZE nC
, SCSIZE nN
)
1908 for (SCSIZE col
=nC
; col
<nN
; col
++)
1909 fNorm
+= (pMatA
->GetDouble(col
,nR
)) * (pMatA
->GetDouble(col
,nR
));
1913 // Special version for use within QR decomposition.
1914 // Maximum norm of column index C starting in row index R;
1915 // matrix A has count N rows.
1916 double lcl_GetColumnMaximumNorm(ScMatrixRef pMatA
, SCSIZE nC
, SCSIZE nR
, SCSIZE nN
)
1919 for (SCSIZE row
=nR
; row
<nN
; row
++)
1920 if (fNorm
< fabs(pMatA
->GetDouble(nC
,row
)))
1921 fNorm
= fabs(pMatA
->GetDouble(nC
,row
));
1925 // Maximum norm of row index R starting in col index C;
1926 // matrix A has count N columns.
1927 double lcl_TGetColumnMaximumNorm(ScMatrixRef pMatA
, SCSIZE nR
, SCSIZE nC
, SCSIZE nN
)
1930 for (SCSIZE col
=nC
; col
<nN
; col
++)
1931 if (fNorm
< fabs(pMatA
->GetDouble(col
,nR
)))
1932 fNorm
= fabs(pMatA
->GetDouble(col
,nR
));
1936 // Special version for use within QR decomposition.
1937 // <A(Ca);B(Cb)> starting in row index R;
1938 // Ca and Cb are indices of columns, matrices A and B have count N rows.
1939 double lcl_GetColumnSumProduct(ScMatrixRef pMatA
, SCSIZE nCa
,
1940 ScMatrixRef pMatB
, SCSIZE nCb
, SCSIZE nR
, SCSIZE nN
)
1942 double fResult
= 0.0;
1943 for (SCSIZE row
=nR
; row
<nN
; row
++)
1944 fResult
+= pMatA
->GetDouble(nCa
,row
) * pMatB
->GetDouble(nCb
,row
);
1948 // <A(Ra);B(Rb)> starting in column index C;
1949 // Ra and Rb are indices of rows, matrices A and B have count N columns.
1950 double lcl_TGetColumnSumProduct(ScMatrixRef pMatA
, SCSIZE nRa
,
1951 ScMatrixRef pMatB
, SCSIZE nRb
, SCSIZE nC
, SCSIZE nN
)
1953 double fResult
= 0.0;
1954 for (SCSIZE col
=nC
; col
<nN
; col
++)
1955 fResult
+= pMatA
->GetDouble(col
,nRa
) * pMatB
->GetDouble(col
,nRb
);
1959 // no mathematical signum, but used to switch between adding and subtracting
1960 double lcl_GetSign(double fValue
)
1962 return (fValue
>= 0.0 ? 1.0 : -1.0 );
1965 /* Calculates a QR decomposition with Householder reflection.
1966 * For each NxK matrix A exists a decomposition A=Q*R with an orthogonal
1967 * NxN matrix Q and a NxK matrix R.
1968 * Q=H1*H2*...*Hk with Householder matrices H. Such a householder matrix can
1969 * be build from a vector u by H=I-(2/u'u)*(u u'). This vectors u are returned
1970 * in the columns of matrix A, overwriting the old content.
1971 * The matrix R has a quadric upper part KxK with values in the upper right
1972 * triangle and zeros in all other elements. Here the diagonal elements of R
1973 * are stored in the vector R and the other upper right elements in the upper
1974 * right of the matrix A.
1975 * The function returns false, if calculation breaks. But because of round-off
1976 * errors singularity is often not detected.
1978 bool lcl_CalculateQRdecomposition(ScMatrixRef pMatA
,
1979 ::std::vector
< double>& pVecR
, SCSIZE nK
, SCSIZE nN
)
1986 // ScMatrix matrices are zero based, index access (column,row)
1987 for (SCSIZE col
= 0; col
<nK
; col
++)
1989 // calculate vector u of the householder transformation
1990 fScale
= lcl_GetColumnMaximumNorm(pMatA
, col
, col
, nN
);
1996 for (SCSIZE row
= col
; row
<nN
; row
++)
1997 pMatA
->PutDouble( pMatA
->GetDouble(col
,row
)/fScale
, col
, row
);
1999 fEuclid
= lcl_GetColumnEuclideanNorm(pMatA
, col
, col
, nN
);
2000 fFactor
= 1.0/fEuclid
/(fEuclid
+ fabs(pMatA
->GetDouble(col
,col
)));
2001 fSignum
= lcl_GetSign(pMatA
->GetDouble(col
,col
));
2002 pMatA
->PutDouble( pMatA
->GetDouble(col
,col
) + fSignum
*fEuclid
, col
,col
);
2003 pVecR
[col
] = -fSignum
* fScale
* fEuclid
;
2005 // apply Householder transformation to A
2006 for (SCSIZE c
=col
+1; c
<nK
; c
++)
2008 fSum
=lcl_GetColumnSumProduct(pMatA
, col
, pMatA
, c
, col
, nN
);
2009 for (SCSIZE row
= col
; row
<nN
; row
++)
2010 pMatA
->PutDouble( pMatA
->GetDouble(c
,row
) - fSum
* fFactor
* pMatA
->GetDouble(col
,row
), c
, row
);
2016 // same with transposed matrix A, N is count of columns, K count of rows
2017 bool lcl_TCalculateQRdecomposition(ScMatrixRef pMatA
,
2018 ::std::vector
< double>& pVecR
, SCSIZE nK
, SCSIZE nN
)
2021 // ScMatrix matrices are zero based, index access (column,row)
2022 for (SCSIZE row
= 0; row
<nK
; row
++)
2024 // calculate vector u of the householder transformation
2025 const double fScale
= lcl_TGetColumnMaximumNorm(pMatA
, row
, row
, nN
);
2031 for (SCSIZE col
= row
; col
<nN
; col
++)
2032 pMatA
->PutDouble( pMatA
->GetDouble(col
,row
)/fScale
, col
, row
);
2034 const double fEuclid
= lcl_TGetColumnEuclideanNorm(pMatA
, row
, row
, nN
);
2035 const double fFactor
= 1.0/fEuclid
/(fEuclid
+ fabs(pMatA
->GetDouble(row
,row
)));
2036 const double fSignum
= lcl_GetSign(pMatA
->GetDouble(row
,row
));
2037 pMatA
->PutDouble( pMatA
->GetDouble(row
,row
) + fSignum
*fEuclid
, row
,row
);
2038 pVecR
[row
] = -fSignum
* fScale
* fEuclid
;
2040 // apply Householder transformation to A
2041 for (SCSIZE r
=row
+1; r
<nK
; r
++)
2043 fSum
=lcl_TGetColumnSumProduct(pMatA
, row
, pMatA
, r
, row
, nN
);
2044 for (SCSIZE col
= row
; col
<nN
; col
++)
2046 pMatA
->GetDouble(col
,r
) - fSum
* fFactor
* pMatA
->GetDouble(col
,row
), col
, r
);
2052 /* Applies a Householder transformation to a column vector Y with is given as
2053 * Nx1 Matrix. The Vektor u, from which the Householder transformation is build,
2054 * is the column part in matrix A, with column index C, starting with row
2055 * index C. A is the result of the QR decomposition as obtained from
2056 * lcl_CaluclateQRdecomposition.
2058 void lcl_ApplyHouseholderTransformation(ScMatrixRef pMatA
, SCSIZE nC
,
2059 ScMatrixRef pMatY
, SCSIZE nN
)
2061 // ScMatrix matrices are zero based, index access (column,row)
2062 double fDenominator
= lcl_GetColumnSumProduct(pMatA
, nC
, pMatA
, nC
, nC
, nN
);
2063 double fNumerator
= lcl_GetColumnSumProduct(pMatA
, nC
, pMatY
, 0, nC
, nN
);
2064 double fFactor
= 2.0 * (fNumerator
/fDenominator
);
2065 for (SCSIZE row
= nC
; row
< nN
; row
++)
2067 pMatY
->GetDouble(row
) - fFactor
* pMatA
->GetDouble(nC
,row
), row
);
2070 // Same with transposed matrices A and Y.
2071 void lcl_TApplyHouseholderTransformation(ScMatrixRef pMatA
, SCSIZE nR
,
2072 ScMatrixRef pMatY
, SCSIZE nN
)
2074 // ScMatrix matrices are zero based, index access (column,row)
2075 double fDenominator
= lcl_TGetColumnSumProduct(pMatA
, nR
, pMatA
, nR
, nR
, nN
);
2076 double fNumerator
= lcl_TGetColumnSumProduct(pMatA
, nR
, pMatY
, 0, nR
, nN
);
2077 double fFactor
= 2.0 * (fNumerator
/fDenominator
);
2078 for (SCSIZE col
= nR
; col
< nN
; col
++)
2080 pMatY
->GetDouble(col
) - fFactor
* pMatA
->GetDouble(col
,nR
), col
);
2083 /* Solve for X in R*X=S using back substitution. The solution X overwrites S.
2084 * Uses R from the result of the QR decomposition of a NxK matrix A.
2085 * S is a column vector given as matrix, with at least elements on index
2086 * 0 to K-1; elements on index>=K are ignored. Vector R must not have zero
2087 * elements, no check is done.
2089 void lcl_SolveWithUpperRightTriangle(ScMatrixRef pMatA
,
2090 ::std::vector
< double>& pVecR
, ScMatrixRef pMatS
,
2091 SCSIZE nK
, bool bIsTransposed
)
2093 // ScMatrix matrices are zero based, index access (column,row)
2095 // SCSIZE is never negative, therefore test with rowp1=row+1
2096 for (SCSIZE rowp1
= nK
; rowp1
>0; rowp1
--)
2099 double fSum
= pMatS
->GetDouble(row
);
2100 for (SCSIZE col
= rowp1
; col
<nK
; col
++)
2102 fSum
-= pMatA
->GetDouble(row
,col
) * pMatS
->GetDouble(col
);
2104 fSum
-= pMatA
->GetDouble(col
,row
) * pMatS
->GetDouble(col
);
2105 pMatS
->PutDouble( fSum
/ pVecR
[row
] , row
);
2109 /* Solve for X in R' * X= T using forward substitution. The solution X
2110 * overwrites T. Uses R from the result of the QR decomposition of a NxK
2111 * matrix A. T is a column vectors given as matrix, with at least elements on
2112 * index 0 to K-1; elements on index>=K are ignored. Vector R must not have
2113 * zero elements, no check is done.
2115 void lcl_SolveWithLowerLeftTriangle(ScMatrixRef pMatA
,
2116 ::std::vector
< double>& pVecR
, ScMatrixRef pMatT
,
2117 SCSIZE nK
, bool bIsTransposed
)
2119 // ScMatrix matrices are zero based, index access (column,row)
2120 for (SCSIZE row
= 0; row
< nK
; row
++)
2122 double fSum
= pMatT
-> GetDouble(row
);
2123 for (SCSIZE col
=0; col
< row
; col
++)
2126 fSum
-= pMatA
->GetDouble(col
,row
) * pMatT
->GetDouble(col
);
2128 fSum
-= pMatA
->GetDouble(row
,col
) * pMatT
->GetDouble(col
);
2130 pMatT
->PutDouble( fSum
/ pVecR
[row
] , row
);
2134 /* Calculates Z = R * B
2135 * R is given in matrix A and vector VecR as obtained from the QR
2136 * decompostion in lcl_CalculateQRdecomposition. B and Z are column vectors
2137 * given as matrix with at least index 0 to K-1; elements on index>=K are
2140 void lcl_ApplyUpperRightTriangle(ScMatrixRef pMatA
,
2141 ::std::vector
< double>& pVecR
, ScMatrixRef pMatB
,
2142 ScMatrixRef pMatZ
, SCSIZE nK
, bool bIsTransposed
)
2144 // ScMatrix matrices are zero based, index access (column,row)
2145 for (SCSIZE row
= 0; row
< nK
; row
++)
2147 double fSum
= pVecR
[row
] * pMatB
->GetDouble(row
);
2148 for (SCSIZE col
= row
+1; col
< nK
; col
++)
2150 fSum
+= pMatA
->GetDouble(row
,col
) * pMatB
->GetDouble(col
);
2152 fSum
+= pMatA
->GetDouble(col
,row
) * pMatB
->GetDouble(col
);
2153 pMatZ
->PutDouble( fSum
, row
);
2157 double lcl_GetMeanOverAll(ScMatrixRef pMat
, SCSIZE nN
)
2160 for (SCSIZE i
=0 ; i
<nN
; i
++)
2161 fSum
+= pMat
->GetDouble(i
);
2162 return fSum
/static_cast<double>(nN
);
2165 // Calculates means of the columns of matrix X. X is a RxC matrix;
2166 // ResMat is a 1xC matrix (=row).
2167 void lcl_CalculateColumnMeans(ScMatrixRef pX
, ScMatrixRef pResMat
,
2168 SCSIZE nC
, SCSIZE nR
)
2170 for (SCSIZE i
=0; i
< nC
; i
++)
2173 for (SCSIZE k
=0; k
< nR
; k
++)
2174 fSum
+= pX
->GetDouble(i
,k
); // GetDouble(Column,Row)
2175 pResMat
->PutDouble( fSum
/static_cast<double>(nR
),i
);
2179 // Calculates means of the rows of matrix X. X is a RxC matrix;
2180 // ResMat is a Rx1 matrix (=column).
2181 void lcl_CalculateRowMeans(ScMatrixRef pX
, ScMatrixRef pResMat
,
2182 SCSIZE nC
, SCSIZE nR
)
2184 for (SCSIZE k
=0; k
< nR
; k
++)
2187 for (SCSIZE i
=0; i
< nC
; i
++)
2188 fSum
+= pX
->GetDouble(i
,k
); // GetDouble(Column,Row)
2189 pResMat
->PutDouble( fSum
/static_cast<double>(nC
),k
);
2193 void lcl_CalculateColumnsDelta(ScMatrixRef pMat
, ScMatrixRef pColumnMeans
,
2194 SCSIZE nC
, SCSIZE nR
)
2196 for (SCSIZE i
= 0; i
< nC
; i
++)
2197 for (SCSIZE k
= 0; k
< nR
; k
++)
2198 pMat
->PutDouble( ::rtl::math::approxSub
2199 (pMat
->GetDouble(i
,k
) , pColumnMeans
->GetDouble(i
) ) , i
, k
);
2202 void lcl_CalculateRowsDelta(ScMatrixRef pMat
, ScMatrixRef pRowMeans
,
2203 SCSIZE nC
, SCSIZE nR
)
2205 for (SCSIZE k
= 0; k
< nR
; k
++)
2206 for (SCSIZE i
= 0; i
< nC
; i
++)
2207 pMat
->PutDouble( ::rtl::math::approxSub
2208 ( pMat
->GetDouble(i
,k
) , pRowMeans
->GetDouble(k
) ) , i
, k
);
2211 // Case1 = simple regression
2212 // MatX = X - MeanX, MatY = Y - MeanY, y - haty = (y - MeanY) - (haty - MeanY)
2213 // = (y-MeanY)-((slope*x+a)-(slope*MeanX+a)) = (y-MeanY)-slope*(x-MeanX)
2214 double lcl_GetSSresid(ScMatrixRef pMatX
, ScMatrixRef pMatY
, double fSlope
,
2218 for (SCSIZE i
=0; i
<nN
; i
++)
2220 const double fTemp
= pMatY
->GetDouble(i
) - fSlope
* pMatX
->GetDouble(i
);
2221 fSum
+= fTemp
* fTemp
;
2228 // Fill default values in matrix X, transform Y to log(Y) in case LOGEST|GROWTH,
2229 // determine sizes of matrices X and Y, determine kind of regression, clone
2230 // Y in case LOGEST|GROWTH, if constant.
2231 bool ScInterpreter::CheckMatrix(bool _bLOG
, sal_uInt8
& nCase
, SCSIZE
& nCX
,
2232 SCSIZE
& nCY
, SCSIZE
& nRX
, SCSIZE
& nRY
, SCSIZE
& M
,
2233 SCSIZE
& N
, ScMatrixRef
& pMatX
, ScMatrixRef
& pMatY
)
2242 pMatY
->GetDimensions(nCY
, nRY
);
2243 const SCSIZE nCountY
= nCY
* nRY
;
2244 for ( SCSIZE i
= 0; i
< nCountY
; i
++ )
2246 if (!pMatY
->IsValue(i
))
2248 PushIllegalArgument();
2255 ScMatrixRef pNewY
= pMatY
->CloneIfConst();
2256 for (SCSIZE nElem
= 0; nElem
< nCountY
; nElem
++)
2258 const double fVal
= pNewY
->GetDouble(nElem
);
2261 PushIllegalArgument();
2265 pNewY
->PutDouble(log(fVal
), nElem
);
2272 pMatX
->GetDimensions(nCX
, nRX
);
2273 const SCSIZE nCountX
= nCX
* nRX
;
2274 for ( SCSIZE i
= 0; i
< nCountX
; i
++ )
2275 if (!pMatX
->IsValue(i
))
2277 PushIllegalArgument();
2280 if (nCX
== nCY
&& nRX
== nRY
)
2282 nCase
= 1; // simple regression
2286 else if (nCY
!= 1 && nRY
!= 1)
2288 PushIllegalArgument();
2295 PushIllegalArgument();
2300 nCase
= 2; // Y is column
2305 else if (nCX
!= nCY
)
2307 PushIllegalArgument();
2312 nCase
= 3; // Y is row
2319 pMatX
= GetNewMat(nCY
, nRY
);
2324 PushIllegalArgument();
2327 for ( SCSIZE i
= 1; i
<= nCountY
; i
++ )
2328 pMatX
->PutDouble(static_cast<double>(i
), i
-1);
2337 void ScInterpreter::ScLinest()
2339 CalculateRGPRKP(false);
2343 void ScInterpreter::ScLogest()
2345 CalculateRGPRKP(true);
2348 void ScInterpreter::CalculateRGPRKP(bool _bRKP
)
2350 sal_uInt8 nParamCount
= GetByte();
2351 if (!MustHaveParamCount( nParamCount
, 1, 4 ))
2353 bool bConstant
, bStats
;
2355 // optional forth parameter
2356 if (nParamCount
== 4)
2361 // The third parameter may not be missing in ODF, if the forth parameter
2362 // is present. But Excel allows it with default true, we too.
2363 if (nParamCount
>= 3)
2369 // PushIllegalParameter(); if ODF behavior is desired
2373 bConstant
= GetBool();
2379 if (nParamCount
>= 2)
2382 { //In ODF1.2 empty second parameter (which is two ;; ) is allowed
2388 pMatX
= GetMatrix();
2395 pMatY
= GetMatrix();
2398 PushIllegalParameter();
2402 // 1 = simple; 2 = multiple with Y as column; 3 = multiple with Y as row
2405 SCSIZE nCX
, nCY
; // number of columns
2406 SCSIZE nRX
, nRY
; //number of rows
2407 SCSIZE K
= 0, N
= 0; // K=number of variables X, N=number of data samples
2408 if (!CheckMatrix(_bRKP
,nCase
,nCX
,nCY
,nRX
,nRY
,K
,N
,pMatX
,pMatY
))
2410 PushIllegalParameter();
2414 // Enough data samples?
2415 if ((bConstant
&& (N
<K
+1)) || (!bConstant
&& (N
<K
)) || (N
<1) || (K
<1))
2417 PushIllegalParameter();
2421 ScMatrixRef pResMat
;
2423 pResMat
= GetNewMat(K
+1,5);
2425 pResMat
= GetNewMat(K
+1,1);
2428 PushError(errCodeOverflow
);
2431 // Fill unused cells in pResMat; order (column,row)
2434 for (SCSIZE i
=2; i
<K
+1; i
++)
2436 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), i
, 2);
2437 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), i
, 3);
2438 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), i
, 4);
2442 // Uses sum(x-MeanX)^2 and not [sum x^2]-N * MeanX^2 in case bConstant.
2443 // Clone constant matrices, so that Mat = Mat - Mean is possible.
2444 double fMeanY
= 0.0;
2447 ScMatrixRef pNewX
= pMatX
->CloneIfConst();
2448 ScMatrixRef pNewY
= pMatY
->CloneIfConst();
2449 if (!pNewX
|| !pNewY
)
2451 PushError(errCodeOverflow
);
2456 // DeltaY is possible here; DeltaX depends on nCase, so later
2457 fMeanY
= lcl_GetMeanOverAll(pMatY
, N
);
2458 for (SCSIZE i
=0; i
<N
; i
++)
2460 pMatY
->PutDouble( ::rtl::math::approxSub(pMatY
->GetDouble(i
),fMeanY
), i
);
2466 // calculate simple regression
2467 double fMeanX
= 0.0;
2469 { // Mat = Mat - Mean
2470 fMeanX
= lcl_GetMeanOverAll(pMatX
, N
);
2471 for (SCSIZE i
=0; i
<N
; i
++)
2473 pMatX
->PutDouble( ::rtl::math::approxSub(pMatX
->GetDouble(i
),fMeanX
), i
);
2476 double fSumXY
= lcl_GetSumProduct(pMatX
,pMatY
,N
);
2477 double fSumX2
= lcl_GetSumProduct(pMatX
,pMatX
,N
);
2480 PushNoValue(); // all x-values are identical
2483 double fSlope
= fSumXY
/ fSumX2
;
2484 double fIntercept
= 0.0;
2486 fIntercept
= fMeanY
- fSlope
* fMeanX
;
2487 pResMat
->PutDouble(_bRKP
? exp(fIntercept
) : fIntercept
, 1, 0); //order (column,row)
2488 pResMat
->PutDouble(_bRKP
? exp(fSlope
) : fSlope
, 0, 0);
2492 double fSSreg
= fSlope
* fSlope
* fSumX2
;
2493 pResMat
->PutDouble(fSSreg
, 0, 4);
2495 double fDegreesFreedom
=static_cast<double>( (bConstant
) ? N
-2 : N
-1 );
2496 pResMat
->PutDouble(fDegreesFreedom
, 1, 3);
2498 double fSSresid
= lcl_GetSSresid(pMatX
,pMatY
,fSlope
,N
);
2499 pResMat
->PutDouble(fSSresid
, 1, 4);
2501 if (fDegreesFreedom
== 0.0 || fSSresid
== 0.0 || fSSreg
== 0.0)
2502 { // exact fit; test SSreg too, because SSresid might be
2503 // unequal zero due to round of errors
2504 pResMat
->PutDouble(0.0, 1, 4); // SSresid
2505 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), 0, 3); // F
2506 pResMat
->PutDouble(0.0, 1, 2); // RMSE
2507 pResMat
->PutDouble(0.0, 0, 1); // SigmaSlope
2509 pResMat
->PutDouble(0.0, 1, 1); //SigmaIntercept
2511 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), 1, 1);
2512 pResMat
->PutDouble(1.0, 0, 2); // R^2
2516 double fFstatistic
= (fSSreg
/ static_cast<double>(K
))
2517 / (fSSresid
/ fDegreesFreedom
);
2518 pResMat
->PutDouble(fFstatistic
, 0, 3);
2520 // standard error of estimate
2521 double fRMSE
= sqrt(fSSresid
/ fDegreesFreedom
);
2522 pResMat
->PutDouble(fRMSE
, 1, 2);
2524 double fSigmaSlope
= fRMSE
/ sqrt(fSumX2
);
2525 pResMat
->PutDouble(fSigmaSlope
, 0, 1);
2529 double fSigmaIntercept
= fRMSE
2530 * sqrt(fMeanX
*fMeanX
/fSumX2
+ 1.0/static_cast<double>(N
));
2531 pResMat
->PutDouble(fSigmaIntercept
, 1, 1);
2535 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), 1, 1);
2538 double fR2
= fSSreg
/ (fSSreg
+ fSSresid
);
2539 pResMat
->PutDouble(fR2
, 0, 2);
2542 PushMatrix(pResMat
);
2544 else // calculate multiple regression;
2546 // Uses a QR decomposition X = QR. The solution B = (X'X)^(-1) * X' * Y
2547 // becomes B = R^(-1) * Q' * Y
2548 if (nCase
==2) // Y is column
2550 ::std::vector
< double> aVecR(N
); // for QR decomposition
2551 // Enough memory for needed matrices?
2552 ScMatrixRef pMeans
= GetNewMat(K
, 1); // mean of each column
2553 ScMatrixRef pMatZ
; // for Q' * Y , inter alia
2555 pMatZ
= pMatY
->Clone(); // Y is used in statistic, keep it
2557 pMatZ
= pMatY
; // Y can be overwritten
2558 ScMatrixRef pSlopes
= GetNewMat(1,K
); // from b1 to bK
2559 if (!pMeans
|| !pMatZ
|| !pSlopes
)
2561 PushError(errCodeOverflow
);
2566 lcl_CalculateColumnMeans(pMatX
, pMeans
, K
, N
);
2567 lcl_CalculateColumnsDelta(pMatX
, pMeans
, K
, N
);
2569 if (!lcl_CalculateQRdecomposition(pMatX
, aVecR
, K
, N
))
2574 // Later on we will divide by elements of aVecR, so make sure
2575 // that they aren't zero.
2576 bool bIsSingular
=false;
2577 for (SCSIZE row
=0; row
< K
&& !bIsSingular
; row
++)
2578 bIsSingular
= bIsSingular
|| aVecR
[row
]==0.0;
2585 for (SCSIZE col
= 0; col
< K
; col
++)
2587 lcl_ApplyHouseholderTransformation(pMatX
, col
, pMatZ
, N
);
2589 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
2590 // result Z should have zeros for index>=K; if not, ignore values
2591 for (SCSIZE col
= 0; col
< K
; col
++)
2593 pSlopes
->PutDouble( pMatZ
->GetDouble(col
), col
);
2595 lcl_SolveWithUpperRightTriangle(pMatX
, aVecR
, pSlopes
, K
, false);
2596 double fIntercept
= 0.0;
2598 fIntercept
= fMeanY
- lcl_GetSumProduct(pMeans
,pSlopes
,K
);
2599 // Fill first line in result matrix
2600 pResMat
->PutDouble(_bRKP
? exp(fIntercept
) : fIntercept
, K
, 0 );
2601 for (SCSIZE i
= 0; i
< K
; i
++)
2602 pResMat
->PutDouble(_bRKP
? exp(pSlopes
->GetDouble(i
))
2603 : pSlopes
->GetDouble(i
) , K
-1-i
, 0);
2607 double fSSreg
= 0.0;
2608 double fSSresid
= 0.0;
2609 // re-use memory of Z;
2610 pMatZ
->FillDouble(0.0, 0, 0, 0, N
-1);
2612 lcl_ApplyUpperRightTriangle(pMatX
, aVecR
, pSlopes
, pMatZ
, K
, false);
2613 // Z = Q * Z, that is Q * R * Slopes = X * Slopes
2614 for (SCSIZE colp1
= K
; colp1
> 0; colp1
--)
2616 lcl_ApplyHouseholderTransformation(pMatX
, colp1
-1, pMatZ
,N
);
2618 fSSreg
=lcl_GetSumProduct(pMatZ
, pMatZ
, N
);
2619 // re-use Y for residuals, Y = Y-Z
2620 for (SCSIZE row
= 0; row
< N
; row
++)
2621 pMatY
->PutDouble(pMatY
->GetDouble(row
) - pMatZ
->GetDouble(row
), row
);
2622 fSSresid
= lcl_GetSumProduct(pMatY
, pMatY
, N
);
2623 pResMat
->PutDouble(fSSreg
, 0, 4);
2624 pResMat
->PutDouble(fSSresid
, 1, 4);
2626 double fDegreesFreedom
=static_cast<double>( (bConstant
) ? N
-K
-1 : N
-K
);
2627 pResMat
->PutDouble(fDegreesFreedom
, 1, 3);
2629 if (fDegreesFreedom
== 0.0 || fSSresid
== 0.0 || fSSreg
== 0.0)
2630 { // exact fit; incl. observed values Y are identical
2631 pResMat
->PutDouble(0.0, 1, 4); // SSresid
2632 // F = (SSreg/K) / (SSresid/df) = #DIV/0!
2633 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), 0, 3); // F
2634 // RMSE = sqrt(SSresid / df) = sqrt(0 / df) = 0
2635 pResMat
->PutDouble(0.0, 1, 2); // RMSE
2636 // SigmaSlope[i] = RMSE * sqrt(matrix[i,i]) = 0 * sqrt(...) = 0
2637 for (SCSIZE i
=0; i
<K
; i
++)
2638 pResMat
->PutDouble(0.0, K
-1-i
, 1);
2640 // SigmaIntercept = RMSE * sqrt(...) = 0
2642 pResMat
->PutDouble(0.0, K
, 1); //SigmaIntercept
2644 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), K
, 1);
2646 // R^2 = SSreg / (SSreg + SSresid) = 1.0
2647 pResMat
->PutDouble(1.0, 0, 2); // R^2
2651 double fFstatistic
= (fSSreg
/ static_cast<double>(K
))
2652 / (fSSresid
/ fDegreesFreedom
);
2653 pResMat
->PutDouble(fFstatistic
, 0, 3);
2655 // standard error of estimate = root mean SSE
2656 double fRMSE
= sqrt(fSSresid
/ fDegreesFreedom
);
2657 pResMat
->PutDouble(fRMSE
, 1, 2);
2659 // standard error of slopes
2660 // = RMSE * sqrt(diagonal element of (R' R)^(-1) )
2661 // standard error of intercept
2662 // = RMSE * sqrt( Xmean * (R' R)^(-1) * Xmean' + 1/N)
2663 // (R' R)^(-1) = R^(-1) * (R')^(-1). Do not calculate it as
2664 // a whole matrix, but iterate over unit vectors.
2665 double fSigmaIntercept
= 0.0;
2666 double fPart
; // for Xmean * single column of (R' R)^(-1)
2667 for (SCSIZE col
= 0; col
< K
; col
++)
2669 //re-use memory of MatZ
2670 pMatZ
->FillDouble(0.0,0,0,0,K
-1); // Z = unit vector e
2671 pMatZ
->PutDouble(1.0, col
);
2673 lcl_SolveWithLowerLeftTriangle(pMatX
, aVecR
, pMatZ
, K
, false);
2674 // Solve R * Znew = Zold
2675 lcl_SolveWithUpperRightTriangle(pMatX
, aVecR
, pMatZ
, K
, false);
2676 // now Z is column col in (R' R)^(-1)
2677 double fSigmaSlope
= fRMSE
* sqrt(pMatZ
->GetDouble(col
));
2678 pResMat
->PutDouble(fSigmaSlope
, K
-1-col
, 1);
2679 // (R' R) ^(-1) is symmetric
2682 fPart
= lcl_GetSumProduct(pMeans
, pMatZ
, K
);
2683 fSigmaIntercept
+= fPart
* pMeans
->GetDouble(col
);
2688 fSigmaIntercept
= fRMSE
2689 * sqrt(fSigmaIntercept
+ 1.0 / static_cast<double>(N
));
2690 pResMat
->PutDouble(fSigmaIntercept
, K
, 1);
2694 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), K
, 1);
2697 double fR2
= fSSreg
/ (fSSreg
+ fSSresid
);
2698 pResMat
->PutDouble(fR2
, 0, 2);
2701 PushMatrix(pResMat
);
2703 else // nCase == 3, Y is row, all matrices are transposed
2705 ::std::vector
< double> aVecR(N
); // for QR decomposition
2706 // Enough memory for needed matrices?
2707 ScMatrixRef pMeans
= GetNewMat(1, K
); // mean of each row
2708 ScMatrixRef pMatZ
; // for Q' * Y , inter alia
2710 pMatZ
= pMatY
->Clone(); // Y is used in statistic, keep it
2712 pMatZ
= pMatY
; // Y can be overwritten
2713 ScMatrixRef pSlopes
= GetNewMat(K
,1); // from b1 to bK
2714 if (!pMeans
|| !pMatZ
|| !pSlopes
)
2716 PushError(errCodeOverflow
);
2721 lcl_CalculateRowMeans(pMatX
, pMeans
, N
, K
);
2722 lcl_CalculateRowsDelta(pMatX
, pMeans
, N
, K
);
2725 if (!lcl_TCalculateQRdecomposition(pMatX
, aVecR
, K
, N
))
2731 // Later on we will divide by elements of aVecR, so make sure
2732 // that they aren't zero.
2733 bool bIsSingular
=false;
2734 for (SCSIZE row
=0; row
< K
&& !bIsSingular
; row
++)
2735 bIsSingular
= bIsSingular
|| aVecR
[row
]==0.0;
2742 for (SCSIZE row
= 0; row
< K
; row
++)
2744 lcl_TApplyHouseholderTransformation(pMatX
, row
, pMatZ
, N
);
2746 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
2747 // result Z should have zeros for index>=K; if not, ignore values
2748 for (SCSIZE col
= 0; col
< K
; col
++)
2750 pSlopes
->PutDouble( pMatZ
->GetDouble(col
), col
);
2752 lcl_SolveWithUpperRightTriangle(pMatX
, aVecR
, pSlopes
, K
, true);
2753 double fIntercept
= 0.0;
2755 fIntercept
= fMeanY
- lcl_GetSumProduct(pMeans
,pSlopes
,K
);
2756 // Fill first line in result matrix
2757 pResMat
->PutDouble(_bRKP
? exp(fIntercept
) : fIntercept
, K
, 0 );
2758 for (SCSIZE i
= 0; i
< K
; i
++)
2759 pResMat
->PutDouble(_bRKP
? exp(pSlopes
->GetDouble(i
))
2760 : pSlopes
->GetDouble(i
) , K
-1-i
, 0);
2764 double fSSreg
= 0.0;
2765 double fSSresid
= 0.0;
2766 // re-use memory of Z;
2767 pMatZ
->FillDouble(0.0, 0, 0, N
-1, 0);
2769 lcl_ApplyUpperRightTriangle(pMatX
, aVecR
, pSlopes
, pMatZ
, K
, true);
2770 // Z = Q * Z, that is Q * R * Slopes = X * Slopes
2771 for (SCSIZE rowp1
= K
; rowp1
> 0; rowp1
--)
2773 lcl_TApplyHouseholderTransformation(pMatX
, rowp1
-1, pMatZ
,N
);
2775 fSSreg
=lcl_GetSumProduct(pMatZ
, pMatZ
, N
);
2776 // re-use Y for residuals, Y = Y-Z
2777 for (SCSIZE col
= 0; col
< N
; col
++)
2778 pMatY
->PutDouble(pMatY
->GetDouble(col
) - pMatZ
->GetDouble(col
), col
);
2779 fSSresid
= lcl_GetSumProduct(pMatY
, pMatY
, N
);
2780 pResMat
->PutDouble(fSSreg
, 0, 4);
2781 pResMat
->PutDouble(fSSresid
, 1, 4);
2783 double fDegreesFreedom
=static_cast<double>( (bConstant
) ? N
-K
-1 : N
-K
);
2784 pResMat
->PutDouble(fDegreesFreedom
, 1, 3);
2786 if (fDegreesFreedom
== 0.0 || fSSresid
== 0.0 || fSSreg
== 0.0)
2787 { // exact fit; incl. case observed values Y are identical
2788 pResMat
->PutDouble(0.0, 1, 4); // SSresid
2789 // F = (SSreg/K) / (SSresid/df) = #DIV/0!
2790 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), 0, 3); // F
2791 // RMSE = sqrt(SSresid / df) = sqrt(0 / df) = 0
2792 pResMat
->PutDouble(0.0, 1, 2); // RMSE
2793 // SigmaSlope[i] = RMSE * sqrt(matrix[i,i]) = 0 * sqrt(...) = 0
2794 for (SCSIZE i
=0; i
<K
; i
++)
2795 pResMat
->PutDouble(0.0, K
-1-i
, 1);
2797 // SigmaIntercept = RMSE * sqrt(...) = 0
2799 pResMat
->PutDouble(0.0, K
, 1); //SigmaIntercept
2801 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), K
, 1);
2803 // R^2 = SSreg / (SSreg + SSresid) = 1.0
2804 pResMat
->PutDouble(1.0, 0, 2); // R^2
2808 double fFstatistic
= (fSSreg
/ static_cast<double>(K
))
2809 / (fSSresid
/ fDegreesFreedom
);
2810 pResMat
->PutDouble(fFstatistic
, 0, 3);
2812 // standard error of estimate = root mean SSE
2813 double fRMSE
= sqrt(fSSresid
/ fDegreesFreedom
);
2814 pResMat
->PutDouble(fRMSE
, 1, 2);
2816 // standard error of slopes
2817 // = RMSE * sqrt(diagonal element of (R' R)^(-1) )
2818 // standard error of intercept
2819 // = RMSE * sqrt( Xmean * (R' R)^(-1) * Xmean' + 1/N)
2820 // (R' R)^(-1) = R^(-1) * (R')^(-1). Do not calculate it as
2821 // a whole matrix, but iterate over unit vectors.
2822 // (R' R) ^(-1) is symmetric
2823 double fSigmaIntercept
= 0.0;
2824 double fPart
; // for Xmean * single col of (R' R)^(-1)
2825 for (SCSIZE row
= 0; row
< K
; row
++)
2827 //re-use memory of MatZ
2828 pMatZ
->FillDouble(0.0,0,0,K
-1,0); // Z = unit vector e
2829 pMatZ
->PutDouble(1.0, row
);
2831 lcl_SolveWithLowerLeftTriangle(pMatX
, aVecR
, pMatZ
, K
, true);
2832 // Solve R * Znew = Zold
2833 lcl_SolveWithUpperRightTriangle(pMatX
, aVecR
, pMatZ
, K
, true);
2834 // now Z is column col in (R' R)^(-1)
2835 double fSigmaSlope
= fRMSE
* sqrt(pMatZ
->GetDouble(row
));
2836 pResMat
->PutDouble(fSigmaSlope
, K
-1-row
, 1);
2839 fPart
= lcl_GetSumProduct(pMeans
, pMatZ
, K
);
2840 fSigmaIntercept
+= fPart
* pMeans
->GetDouble(row
);
2845 fSigmaIntercept
= fRMSE
2846 * sqrt(fSigmaIntercept
+ 1.0 / static_cast<double>(N
));
2847 pResMat
->PutDouble(fSigmaIntercept
, K
, 1);
2851 pResMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NV_STR
)), K
, 1);
2854 double fR2
= fSSreg
/ (fSSreg
+ fSSresid
);
2855 pResMat
->PutDouble(fR2
, 0, 2);
2858 PushMatrix(pResMat
);
2863 void ScInterpreter::ScTrend()
2865 CalculateTrendGrowth(false);
2868 void ScInterpreter::ScGrowth()
2870 CalculateTrendGrowth(true);
2873 void ScInterpreter::CalculateTrendGrowth(bool _bGrowth
)
2875 sal_uInt8 nParamCount
= GetByte();
2876 if (!MustHaveParamCount( nParamCount
, 1, 4 ))
2879 // optional forth parameter
2881 if (nParamCount
== 4)
2882 bConstant
= GetBool();
2886 // The third parameter may be missing in ODF, although the forth parameter
2887 // is present. Default values depend on data not yet read.
2888 ScMatrixRef pMatNewX
;
2889 if (nParamCount
>= 3)
2897 pMatNewX
= GetMatrix();
2902 //In ODF1.2 empty second parameter (which is two ;; ) is allowed
2903 //Defaults will be set in CheckMatrix
2905 if (nParamCount
>= 2)
2914 pMatX
= GetMatrix();
2921 pMatY
= GetMatrix();
2924 PushIllegalParameter();
2928 // 1 = simple; 2 = multiple with Y as column; 3 = multiple with Y as row
2931 SCSIZE nCX
, nCY
; // number of columns
2932 SCSIZE nRX
, nRY
; //number of rows
2933 SCSIZE K
= 0, N
= 0; // K=number of variables X, N=number of data samples
2934 if (!CheckMatrix(_bGrowth
,nCase
,nCX
,nCY
,nRX
,nRY
,K
,N
,pMatX
,pMatY
))
2936 PushIllegalParameter();
2940 // Enough data samples?
2941 if ((bConstant
&& (N
<K
+1)) || (!bConstant
&& (N
<K
)) || (N
<1) || (K
<1))
2943 PushIllegalParameter();
2947 // Set default pMatNewX if necessary
2954 nCountXN
= nCXN
* nRXN
;
2955 pMatNewX
= pMatX
->Clone(); // pMatX will be changed to X-meanX
2959 pMatNewX
->GetDimensions(nCXN
, nRXN
);
2960 if ((nCase
== 2 && K
!= nCXN
) || (nCase
== 3 && K
!= nRXN
))
2962 PushIllegalArgument();
2965 nCountXN
= nCXN
* nRXN
;
2966 for (SCSIZE i
= 0; i
< nCountXN
; i
++)
2967 if (!pMatNewX
->IsValue(i
))
2969 PushIllegalArgument();
2973 ScMatrixRef pResMat
; // size depends on nCase
2975 pResMat
= GetNewMat(nCXN
,nRXN
);
2979 pResMat
= GetNewMat(1,nRXN
);
2981 pResMat
= GetNewMat(nCXN
,1);
2985 PushError(errCodeOverflow
);
2988 // Uses sum(x-MeanX)^2 and not [sum x^2]-N * MeanX^2 in case bConstant.
2989 // Clone constant matrices, so that Mat = Mat - Mean is possible.
2990 double fMeanY
= 0.0;
2993 ScMatrixRef pCopyX
= pMatX
->CloneIfConst();
2994 ScMatrixRef pCopyY
= pMatY
->CloneIfConst();
2995 if (!pCopyX
|| !pCopyY
)
2997 PushError(errStackOverflow
);
3002 // DeltaY is possible here; DeltaX depends on nCase, so later
3003 fMeanY
= lcl_GetMeanOverAll(pMatY
, N
);
3004 for (SCSIZE i
=0; i
<N
; i
++)
3006 pMatY
->PutDouble( ::rtl::math::approxSub(pMatY
->GetDouble(i
),fMeanY
), i
);
3012 // calculate simple regression
3013 double fMeanX
= 0.0;
3015 { // Mat = Mat - Mean
3016 fMeanX
= lcl_GetMeanOverAll(pMatX
, N
);
3017 for (SCSIZE i
=0; i
<N
; i
++)
3019 pMatX
->PutDouble( ::rtl::math::approxSub(pMatX
->GetDouble(i
),fMeanX
), i
);
3022 double fSumXY
= lcl_GetSumProduct(pMatX
,pMatY
,N
);
3023 double fSumX2
= lcl_GetSumProduct(pMatX
,pMatX
,N
);
3026 PushNoValue(); // all x-values are identical
3029 double fSlope
= fSumXY
/ fSumX2
;
3033 double fIntercept
= fMeanY
- fSlope
* fMeanX
;
3034 for (SCSIZE i
= 0; i
< nCountXN
; i
++)
3036 fHelp
= pMatNewX
->GetDouble(i
)*fSlope
+ fIntercept
;
3037 pResMat
->PutDouble(_bGrowth
? exp(fHelp
) : fHelp
, i
);
3042 for (SCSIZE i
= 0; i
< nCountXN
; i
++)
3044 fHelp
= pMatNewX
->GetDouble(i
)*fSlope
;
3045 pResMat
->PutDouble(_bGrowth
? exp(fHelp
) : fHelp
, i
);
3049 else // calculate multiple regression;
3051 if (nCase
==2) // Y is column
3053 ::std::vector
< double> aVecR(N
); // for QR decomposition
3054 // Enough memory for needed matrices?
3055 ScMatrixRef pMeans
= GetNewMat(K
, 1); // mean of each column
3056 ScMatrixRef pSlopes
= GetNewMat(1,K
); // from b1 to bK
3057 if (!pMeans
|| !pSlopes
)
3059 PushError(errCodeOverflow
);
3064 lcl_CalculateColumnMeans(pMatX
, pMeans
, K
, N
);
3065 lcl_CalculateColumnsDelta(pMatX
, pMeans
, K
, N
);
3067 if (!lcl_CalculateQRdecomposition(pMatX
, aVecR
, K
, N
))
3072 // Later on we will divide by elements of aVecR, so make sure
3073 // that they aren't zero.
3074 bool bIsSingular
=false;
3075 for (SCSIZE row
=0; row
< K
&& !bIsSingular
; row
++)
3076 bIsSingular
= bIsSingular
|| aVecR
[row
]==0.0;
3082 // Z := Q' Y; Y is overwritten with result Z
3083 for (SCSIZE col
= 0; col
< K
; col
++)
3085 lcl_ApplyHouseholderTransformation(pMatX
, col
, pMatY
, N
);
3087 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
3088 // result Z should have zeros for index>=K; if not, ignore values
3089 for (SCSIZE col
= 0; col
< K
; col
++)
3091 pSlopes
->PutDouble( pMatY
->GetDouble(col
), col
);
3093 lcl_SolveWithUpperRightTriangle(pMatX
, aVecR
, pSlopes
, K
, false);
3095 // Fill result matrix
3096 lcl_MFastMult(pMatNewX
,pSlopes
,pResMat
,nRXN
,K
,1);
3099 double fIntercept
= fMeanY
- lcl_GetSumProduct(pMeans
,pSlopes
,K
);
3100 for (SCSIZE row
= 0; row
< nRXN
; row
++)
3101 pResMat
->PutDouble(pResMat
->GetDouble(row
)+fIntercept
, row
);
3105 for (SCSIZE i
= 0; i
< nRXN
; i
++)
3106 pResMat
->PutDouble(exp(pResMat
->GetDouble(i
)), i
);
3110 { // nCase == 3, Y is row, all matrices are transposed
3112 ::std::vector
< double> aVecR(N
); // for QR decomposition
3113 // Enough memory for needed matrices?
3114 ScMatrixRef pMeans
= GetNewMat(1, K
); // mean of each row
3115 ScMatrixRef pSlopes
= GetNewMat(K
,1); // row from b1 to bK
3116 if (!pMeans
|| !pSlopes
)
3118 PushError(errCodeOverflow
);
3123 lcl_CalculateRowMeans(pMatX
, pMeans
, N
, K
);
3124 lcl_CalculateRowsDelta(pMatX
, pMeans
, N
, K
);
3126 if (!lcl_TCalculateQRdecomposition(pMatX
, aVecR
, K
, N
))
3131 // Later on we will divide by elements of aVecR, so make sure
3132 // that they aren't zero.
3133 bool bIsSingular
=false;
3134 for (SCSIZE row
=0; row
< K
&& !bIsSingular
; row
++)
3135 bIsSingular
= bIsSingular
|| aVecR
[row
]==0.0;
3141 // Z := Q' Y; Y is overwritten with result Z
3142 for (SCSIZE row
= 0; row
< K
; row
++)
3144 lcl_TApplyHouseholderTransformation(pMatX
, row
, pMatY
, N
);
3146 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
3147 // result Z should have zeros for index>=K; if not, ignore values
3148 for (SCSIZE col
= 0; col
< K
; col
++)
3150 pSlopes
->PutDouble( pMatY
->GetDouble(col
), col
);
3152 lcl_SolveWithUpperRightTriangle(pMatX
, aVecR
, pSlopes
, K
, true);
3154 // Fill result matrix
3155 lcl_MFastMult(pSlopes
,pMatNewX
,pResMat
,1,K
,nCXN
);
3158 double fIntercept
= fMeanY
- lcl_GetSumProduct(pMeans
,pSlopes
,K
);
3159 for (SCSIZE col
= 0; col
< nCXN
; col
++)
3160 pResMat
->PutDouble(pResMat
->GetDouble(col
)+fIntercept
, col
);
3164 for (SCSIZE i
= 0; i
< nCXN
; i
++)
3165 pResMat
->PutDouble(exp(pResMat
->GetDouble(i
)), i
);
3169 PushMatrix(pResMat
);
3172 void ScInterpreter::ScMatRef()
3174 // Falls Deltarefs drin sind...
3175 Push( (FormulaToken
&)*pCur
);
3177 PopSingleRef( aAdr
);
3179 ScRefCellValue aCell
;
3180 aCell
.assign(*pDok
, aAdr
);
3182 if (aCell
.meType
!= CELLTYPE_FORMULA
)
3184 PushError( errNoRef
);
3188 const ScMatrix
* pMat
= aCell
.mpFormula
->GetMatrix();
3191 SCSIZE nCols
, nRows
;
3192 pMat
->GetDimensions( nCols
, nRows
);
3193 SCSIZE nC
= static_cast<SCSIZE
>(aPos
.Col() - aAdr
.Col());
3194 SCSIZE nR
= static_cast<SCSIZE
>(aPos
.Row() - aAdr
.Row());
3195 if ((nCols
<= nC
&& nCols
!= 1) || (nRows
<= nR
&& nRows
!= 1))
3199 const ScMatrixValue nMatVal
= pMat
->Get( nC
, nR
);
3200 ScMatValType nMatValType
= nMatVal
.nType
;
3202 if (ScMatrix::IsNonValueType( nMatValType
))
3204 if (ScMatrix::IsEmptyPathType( nMatValType
))
3205 { // result of empty false jump path
3206 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
3209 else if (ScMatrix::IsEmptyType( nMatValType
))
3211 // Not inherited (really?) and display as empty string, not 0.
3212 PushTempToken( new ScEmptyCellToken( false, true));
3215 PushString( nMatVal
.GetString() );
3219 PushDouble(nMatVal
.fVal
); // handles DoubleError
3220 pDok
->GetNumberFormatInfo(nCurFmtType
, nCurFmtIndex
, aAdr
);
3221 nFuncFmtType
= nCurFmtType
;
3222 nFuncFmtIndex
= nCurFmtIndex
;
3228 // If not a result matrix, obtain the cell value.
3229 sal_uInt16 nErr
= aCell
.mpFormula
->GetErrCode();
3232 else if (aCell
.mpFormula
->IsValue())
3233 PushDouble(aCell
.mpFormula
->GetValue());
3236 svl::SharedString aVal
= aCell
.mpFormula
->GetString();
3239 pDok
->GetNumberFormatInfo(nCurFmtType
, nCurFmtIndex
, aAdr
);
3240 nFuncFmtType
= nCurFmtType
;
3241 nFuncFmtIndex
= nCurFmtIndex
;
3245 void ScInterpreter::ScInfo()
3247 if( MustHaveParamCount( GetByte(), 1 ) )
3249 OUString aStr
= GetString().getString();
3250 ScCellKeywordTranslator::transKeyword(aStr
, ScGlobal::GetLocale(), ocInfo
);
3251 if( aStr
== "SYSTEM" )
3252 PushString( OUString( SC_INFO_OSVERSION
) );
3253 else if( aStr
== "OSVERSION" )
3254 PushString( OUString( "Windows (32-bit) NT 5.01" ) );
3255 else if( aStr
== "RELEASE" )
3256 PushString( ::utl::Bootstrap::getBuildIdData( OUString() ) );
3257 else if( aStr
== "NUMFILE" )
3259 else if( aStr
== "RECALC" )
3260 PushString( ScGlobal::GetRscString( pDok
->GetAutoCalc() ? STR_RECALC_AUTO
: STR_RECALC_MANUAL
) );
3262 PushIllegalArgument();
3266 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */