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