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