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