merge the formfield patch from ooo-build
[ooovba.git] / sc / source / core / tool / interpr2.cxx
blob408bccf6fc60d41f0b822fba93f3497c36d4a55d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: interpr2.cxx,v $
10 * $Revision: 1.37.88.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include <svx/linkmgr.hxx>
37 #include <sfx2/dispatch.hxx>
38 #include <sfx2/objsh.hxx>
39 #include <svtools/stritem.hxx>
40 #include <svtools/zforlist.hxx>
41 #include <rtl/logfile.hxx>
43 #include "interpre.hxx"
44 #include "attrib.hxx"
45 #include "sc.hrc"
46 #include "ddelink.hxx"
47 #include "scmatrix.hxx"
48 #include "compiler.hxx"
49 #include "cell.hxx"
50 #include "document.hxx"
51 #include "dociter.hxx"
52 #include "docoptio.hxx"
53 #include "unitconv.hxx"
54 #include "globstr.hrc"
55 #include "hints.hxx"
56 #include "dpobject.hxx"
57 #include "postit.hxx"
59 #include <string.h>
60 #include <math.h>
62 using namespace formula;
63 // STATIC DATA -----------------------------------------------------------
65 #define D_TIMEFACTOR 86400.0
66 #define SCdEpsilon 1.0E-7
68 //-----------------------------------------------------------------------------
69 // Datum und Zeit
70 //-----------------------------------------------------------------------------
72 double ScInterpreter::GetDateSerial( INT16 nYear, INT16 nMonth, INT16 nDay, bool bStrict )
74 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDateSerial" );
75 if ( nYear < 100 && !bStrict )
76 nYear = pFormatter->ExpandTwoDigitYear( nYear );
77 // Do not use a default Date ctor here because it asks system time with a
78 // performance penalty.
79 INT16 nY, nM, nD;
80 if (bStrict)
81 nY = nYear, nM = nMonth, nD = nDay;
82 else
84 if (nMonth > 0)
86 nY = nYear + (nMonth-1) / 12;
87 nM = ((nMonth-1) % 12) + 1;
89 else
91 nY = nYear + (nMonth-12) / 12;
92 nM = 12 - (-nMonth) % 12;
94 nD = 1;
96 Date aDate( nD, nM, nY);
97 if (!bStrict)
98 aDate += nDay - 1;
99 if (aDate.IsValid())
100 return (double) (aDate - *(pFormatter->GetNullDate()));
101 else
103 SetError(errNoValue);
104 return 0;
108 //-----------------------------------------------------------------------------
109 // Funktionen
110 //-----------------------------------------------------------------------------
112 void ScInterpreter::ScGetActDate()
114 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetActDate" );
115 nFuncFmtType = NUMBERFORMAT_DATE;
116 Date aActDate;
117 long nDiff = aActDate - *(pFormatter->GetNullDate());
118 PushDouble((double) nDiff);
121 void ScInterpreter::ScGetActTime()
123 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetActTime" );
124 nFuncFmtType = NUMBERFORMAT_DATETIME;
125 Date aActDate;
126 long nDiff = aActDate - *(pFormatter->GetNullDate());
127 Time aActTime;
128 double nTime = ((double)aActTime.Get100Sec() / 100 +
129 (double)(aActTime.GetSec() +
130 (aActTime.GetMin() * 60) +
131 (aActTime.GetHour() * 3600))) / D_TIMEFACTOR;
132 PushDouble( (double) nDiff + nTime );
135 void ScInterpreter::ScGetYear()
137 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetYear" );
138 Date aDate = *(pFormatter->GetNullDate());
139 aDate += (long) ::rtl::math::approxFloor(GetDouble());
140 PushDouble( (double) aDate.GetYear() );
143 void ScInterpreter::ScGetMonth()
145 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetMonth" );
146 Date aDate = *(pFormatter->GetNullDate());
147 aDate += (long) ::rtl::math::approxFloor(GetDouble());
148 PushDouble( (double) aDate.GetMonth() );
151 void ScInterpreter::ScGetDay()
153 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDay" );
154 Date aDate = *(pFormatter->GetNullDate());
155 aDate += (long)::rtl::math::approxFloor(GetDouble());
156 PushDouble((double) aDate.GetDay());
159 void ScInterpreter::ScGetMin()
161 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetMin" );
162 double fTime = GetDouble();
163 fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
164 long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) % 3600;
165 PushDouble( (double) (nVal/60) );
168 void ScInterpreter::ScGetSec()
170 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetSec" );
171 double fTime = GetDouble();
172 fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
173 long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) % 60;
174 PushDouble( (double) nVal );
177 void ScInterpreter::ScGetHour()
179 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetHour" );
180 double fTime = GetDouble();
181 fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
182 long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) / 3600;
183 PushDouble((double) nVal);
186 void ScInterpreter::ScGetDateValue()
188 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDateValue" );
189 String aInputString = GetString();
190 sal_uInt32 nFIndex = 0; // damit default Land/Spr.
191 double fVal;
192 if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
194 short eType = pFormatter->GetType(nFIndex);
195 if (eType == NUMBERFORMAT_DATE || eType == NUMBERFORMAT_DATETIME)
196 PushDouble(::rtl::math::approxFloor(fVal));
197 else
198 PushIllegalArgument();
200 else
201 PushIllegalArgument();
204 void ScInterpreter::ScGetDayOfWeek()
206 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDayOfWeek" );
207 BYTE nParamCount = GetByte();
208 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
210 short nFlag;
211 if (nParamCount == 2)
212 nFlag = (short) ::rtl::math::approxFloor(GetDouble());
213 else
214 nFlag = 1;
216 Date aDate = *(pFormatter->GetNullDate());
217 aDate += (long)::rtl::math::approxFloor(GetDouble());
218 int nVal = (int) aDate.GetDayOfWeek();
219 if (nFlag == 1)
221 if (nVal == 6)
222 nVal = 1;
223 else
224 nVal += 2;
226 else if (nFlag == 2)
227 nVal += 1;
228 PushInt( nVal );
232 void ScInterpreter::ScGetWeekOfYear()
234 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetWeekOfYear" );
235 if ( MustHaveParamCount( GetByte(), 2 ) )
237 short nFlag = (short) ::rtl::math::approxFloor(GetDouble());
239 Date aDate = *(pFormatter->GetNullDate());
240 aDate += (long)::rtl::math::approxFloor(GetDouble());
241 PushInt( (int) aDate.GetWeekOfYear( nFlag == 1 ? SUNDAY : MONDAY ));
245 void ScInterpreter::ScEasterSunday()
247 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEasterSunday" );
248 nFuncFmtType = NUMBERFORMAT_DATE;
249 if ( MustHaveParamCount( GetByte(), 1 ) )
251 INT16 nDay, nMonth, nYear;
252 nYear = (INT16) ::rtl::math::approxFloor( GetDouble() );
253 if ( nYear < 100 )
254 nYear = pFormatter->ExpandTwoDigitYear( nYear );
255 // don't worry, be happy :)
256 int B,C,D,E,F,G,H,I,K,L,M,N,O;
257 N = nYear % 19;
258 B = int(nYear / 100);
259 C = nYear % 100;
260 D = int(B / 4);
261 E = B % 4;
262 F = int((B + 8) / 25);
263 G = int((B - F + 1) / 3);
264 H = (19 * N + B - D - G + 15) % 30;
265 I = int(C / 4);
266 K = C % 4;
267 L = (32 + 2 * E + 2 * I - H - K) % 7;
268 M = int((N + 11 * H + 22 * L) / 451);
269 O = H + L - 7 * M + 114;
270 nDay = sal::static_int_cast<INT16>( O % 31 + 1 );
271 nMonth = sal::static_int_cast<INT16>( int(O / 31) );
272 PushDouble( GetDateSerial( nYear, nMonth, nDay, true ) );
276 void ScInterpreter::ScGetDate()
278 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDate" );
279 nFuncFmtType = NUMBERFORMAT_DATE;
280 if ( MustHaveParamCount( GetByte(), 3 ) )
282 INT16 nDay = (INT16) ::rtl::math::approxFloor(GetDouble());
283 INT16 nMonth = (INT16) ::rtl::math::approxFloor(GetDouble());
284 INT16 nYear = (INT16) ::rtl::math::approxFloor(GetDouble());
285 if (nYear < 0)
286 PushIllegalArgument();
287 else
289 PushDouble(GetDateSerial(nYear, nMonth, nDay, false));
294 void ScInterpreter::ScGetTime()
296 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetTime" );
297 nFuncFmtType = NUMBERFORMAT_TIME;
298 if ( MustHaveParamCount( GetByte(), 3 ) )
300 double nSec = GetDouble();
301 double nMin = GetDouble();
302 double nHour = GetDouble();
303 PushDouble( ( (nHour * 3600) + (nMin * 60) + nSec ) / D_TIMEFACTOR );
307 void ScInterpreter::ScGetDiffDate()
309 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDiffDate" );
310 if ( MustHaveParamCount( GetByte(), 2 ) )
312 double nDate2 = GetDouble();
313 double nDate1 = GetDouble();
314 PushDouble(nDate1 - nDate2);
318 void ScInterpreter::ScGetDiffDate360()
320 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDiffDate360" );
321 /* Implementation follows
322 * http://www.bondmarkets.com/eCommerce/SMD_Fields_030802.pdf
323 * Appendix B: Day-Count Bases, there are 7 different ways to calculate the
324 * 30-days count. That document also claims that Excel implements the "PSA
325 * 30" or "NASD 30" method (funny enough they also state that Excel is the
326 * only tool that does so).
328 * Note that the definiton given in
329 * http://msdn.microsoft.com/library/en-us/office97/html/SEB7C.asp
330 * is _not_ the way how it is actually calculated by Excel (that would not
331 * even match any of the 7 methods mentioned above) and would result in the
332 * following test cases producing wrong results according to that appendix B:
334 * 28-Feb-95 31-Aug-95 181 instead of 180
335 * 29-Feb-96 31-Aug-96 181 instead of 180
336 * 30-Jan-96 31-Mar-96 61 instead of 60
337 * 31-Jan-96 31-Mar-96 61 instead of 60
339 * Still, there is a difference between OOoCalc and Excel:
340 * In Excel:
341 * 02-Feb-99 31-Mar-00 results in 419
342 * 31-Mar-00 02-Feb-99 results in -418
343 * In Calc the result is 419 respectively -419. I consider the -418 a bug in Excel.
346 BYTE nParamCount = GetByte();
347 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
349 BOOL bFlag;
350 if (nParamCount == 3)
351 bFlag = GetBool();
352 else
353 bFlag = FALSE;
354 double nDate2 = GetDouble();
355 double nDate1 = GetDouble();
356 double fSign;
357 if (nGlobalError)
358 PushError( nGlobalError);
359 else
361 // #i84934# only for non-US European algorithm swap dates. Else
362 // follow Excel's meaningless extrapolation for "interoperability".
363 if (bFlag && (nDate2 < nDate1))
365 fSign = nDate1;
366 nDate1 = nDate2;
367 nDate2 = fSign;
368 fSign = -1.0;
370 else
371 fSign = 1.0;
372 Date aDate1 = *(pFormatter->GetNullDate());
373 aDate1 += (long) ::rtl::math::approxFloor(nDate1);
374 Date aDate2 = *(pFormatter->GetNullDate());
375 aDate2 += (long) ::rtl::math::approxFloor(nDate2);
376 if (aDate1.GetDay() == 31)
377 aDate1 -= (ULONG) 1;
378 else if (!bFlag)
380 if (aDate1.GetMonth() == 2)
382 switch ( aDate1.GetDay() )
384 case 28 :
385 if ( !aDate1.IsLeapYear() )
386 aDate1.SetDay(30);
387 break;
388 case 29 :
389 aDate1.SetDay(30);
390 break;
394 if (aDate2.GetDay() == 31)
396 if (!bFlag )
398 if (aDate1.GetDay() == 30)
399 aDate2 -= (ULONG) 1;
401 else
402 aDate2.SetDay(30);
404 PushDouble( fSign * (double)
405 ( (double) aDate2.GetDay() + (double) aDate2.GetMonth() * 30.0 +
406 (double) aDate2.GetYear() * 360.0
407 - (double) aDate1.GetDay() - (double) aDate1.GetMonth() * 30.0
408 - (double)aDate1.GetYear() * 360.0) );
413 void ScInterpreter::ScGetTimeValue()
415 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetTimeValue" );
416 String aInputString = GetString();
417 sal_uInt32 nFIndex = 0; // damit default Land/Spr.
418 double fVal;
419 if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
421 short eType = pFormatter->GetType(nFIndex);
422 if (eType == NUMBERFORMAT_TIME || eType == NUMBERFORMAT_DATETIME)
424 double fDateVal = rtl::math::approxFloor(fVal);
425 double fTimeVal = fVal - fDateVal;
426 PushDouble(fTimeVal);
428 else
429 PushIllegalArgument();
431 else
432 PushIllegalArgument();
435 void ScInterpreter::ScPlusMinus()
437 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPlusMinus" );
438 double nVal = GetDouble();
439 short n = 0;
440 if (nVal < 0.0)
441 n = -1;
442 else if (nVal > 0.0)
443 n = 1;
444 PushInt( n );
447 void ScInterpreter::ScAbs()
449 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAbs" );
450 PushDouble(fabs(GetDouble()));
453 void ScInterpreter::ScInt()
455 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInt" );
456 PushDouble(::rtl::math::approxFloor(GetDouble()));
460 void ScInterpreter::RoundNumber( rtl_math_RoundingMode eMode )
462 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RoundNumber" );
463 BYTE nParamCount = GetByte();
464 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
466 double fVal = 0.0;
467 if (nParamCount == 1)
468 fVal = ::rtl::math::round( GetDouble(), 0, eMode );
469 else
471 INT32 nDec = (INT32) ::rtl::math::approxFloor(GetDouble());
472 if( nDec < -20 || nDec > 20 )
473 PushIllegalArgument();
474 else
475 fVal = ::rtl::math::round( GetDouble(), (short)nDec, eMode );
477 PushDouble(fVal);
481 void ScInterpreter::ScRound()
483 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRound" );
484 RoundNumber( rtl_math_RoundingMode_Corrected );
487 void ScInterpreter::ScRoundDown()
489 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRoundDown" );
490 RoundNumber( rtl_math_RoundingMode_Down );
493 void ScInterpreter::ScRoundUp()
495 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRoundUp" );
496 RoundNumber( rtl_math_RoundingMode_Up );
499 void ScInterpreter::ScCeil()
501 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCeil" );
502 BYTE nParamCount = GetByte();
503 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
505 BOOL bAbs = ( nParamCount == 3 ? GetBool() : FALSE );
506 double fDec = GetDouble();
507 double fVal = GetDouble();
508 if ( fDec == 0.0 )
509 PushInt(0);
510 else if (fVal*fDec < 0.0)
511 PushIllegalArgument();
512 else
514 if ( !bAbs && fVal < 0.0 )
515 PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec);
516 else
517 PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec);
522 void ScInterpreter::ScFloor()
524 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFloor" );
525 BYTE nParamCount = GetByte();
526 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
528 BOOL bAbs = ( nParamCount == 3 ? GetBool() : FALSE );
529 double fDec = GetDouble();
530 double fVal = GetDouble();
531 if ( fDec == 0.0 )
532 PushInt(0);
533 else if (fVal*fDec < 0.0)
534 PushIllegalArgument();
535 else
537 if ( !bAbs && fVal < 0.0 )
538 PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec);
539 else
540 PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec);
545 void ScInterpreter::ScEven()
547 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEven" );
548 double fVal = GetDouble();
549 if (fVal < 0.0)
550 PushDouble(::rtl::math::approxFloor(fVal/2.0) * 2.0);
551 else
552 PushDouble(::rtl::math::approxCeil(fVal/2.0) * 2.0);
555 void ScInterpreter::ScOdd()
557 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOdd" );
558 double fVal = GetDouble();
559 if (fVal >= 0.0)
561 fVal = ::rtl::math::approxCeil(fVal);
562 if (fmod(fVal, 2.0) == 0.0)
563 fVal += 1.0;
565 else
567 fVal = ::rtl::math::approxFloor(fVal);
568 if (fmod(fVal, 2.0) == 0.0)
569 fVal -= 1.0;
571 PushDouble(fVal);
574 void ScInterpreter::ScArcTan2()
576 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcTan2" );
577 if ( MustHaveParamCount( GetByte(), 2 ) )
579 double nVal2 = GetDouble();
580 double nVal1 = GetDouble();
581 PushDouble(atan2(nVal2, nVal1));
585 void ScInterpreter::ScLog()
587 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLog" );
588 BYTE nParamCount = GetByte();
589 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
591 double nBase;
592 if (nParamCount == 2)
593 nBase = GetDouble();
594 else
595 nBase = 10.0;
596 double nVal = GetDouble();
597 if (nVal > 0.0 && nBase > 0.0 && nBase != 1.0)
598 PushDouble(log(nVal) / log(nBase));
599 else
600 PushIllegalArgument();
604 void ScInterpreter::ScLn()
606 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLn" );
607 double fVal = GetDouble();
608 if (fVal > 0.0)
609 PushDouble(log(fVal));
610 else
611 PushIllegalArgument();
614 void ScInterpreter::ScLog10()
616 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLog10" );
617 double fVal = GetDouble();
618 if (fVal > 0.0)
619 PushDouble(log10(fVal));
620 else
621 PushIllegalArgument();
624 void ScInterpreter::ScNPV()
626 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNPV" );
627 nFuncFmtType = NUMBERFORMAT_CURRENCY;
628 short nParamCount = GetByte();
629 if ( MustHaveParamCount( nParamCount, 2, 31 ) )
631 double nVal = 0.0;
632 // Wir drehen den Stack um!!
633 FormulaToken* pTemp[ 31 ];
634 for( short i = 0; i < nParamCount; i++ )
635 pTemp[ i ] = pStack[ sp - i - 1 ];
636 memcpy( &pStack[ sp - nParamCount ], pTemp, nParamCount * sizeof( FormulaToken* ) );
637 if (nGlobalError == 0)
639 double nCount = 1.0;
640 double nZins = GetDouble();
641 --nParamCount;
642 size_t nRefInList = 0;
643 ScRange aRange;
644 while (nParamCount-- > 0)
646 switch (GetStackType())
648 case svDouble :
650 nVal += (GetDouble() / pow(1.0 + nZins, (double)nCount));
651 nCount++;
653 break;
654 case svSingleRef :
656 nVal += (GetDouble() / pow(1.0 + nZins, (double)nCount));
657 nCount++;
659 break;
660 case svDoubleRef :
661 case svRefList :
663 USHORT nErr = 0;
664 double nCellVal;
665 PopDoubleRef( aRange, nParamCount, nRefInList);
666 ScValueIterator aValIter(pDok, aRange, glSubTotal);
667 if (aValIter.GetFirst(nCellVal, nErr))
669 nVal += (nCellVal / pow(1.0 + nZins, (double)nCount));
670 nCount++;
671 while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
673 nVal += (nCellVal / pow(1.0 + nZins, (double)nCount));
674 nCount++;
676 SetError(nErr);
679 break;
680 default : SetError(errIllegalParameter); break;
684 PushDouble(nVal);
688 #if defined(WIN) && defined(MSC)
689 #pragma optimize("",off)
690 #endif
692 void ScInterpreter::ScIRR()
694 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIRR" );
695 double fSchaetzwert;
696 nFuncFmtType = NUMBERFORMAT_PERCENT;
697 BYTE nParamCount = GetByte();
698 if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
699 return;
700 if (nParamCount == 2)
701 fSchaetzwert = GetDouble();
702 else
703 fSchaetzwert = 0.1;
704 USHORT sPos = sp; // Stack-Position merken
705 double fEps = 1.0;
706 double x, xNeu, fWert, fZaehler, fNenner, nCount;
707 if (fSchaetzwert == -1.0)
708 x = 0.1; // default gegen Nulldivisionen
709 else
710 x = fSchaetzwert; // Startwert
711 switch (GetStackType())
713 case svDoubleRef :
714 break;
715 default:
717 PushIllegalParameter();
718 return;
721 const USHORT nIterationsMax = 20;
722 USHORT nItCount = 0;
723 ScRange aRange;
724 while (fEps > SCdEpsilon && nItCount < nIterationsMax)
725 { // Newton-Verfahren:
726 sp = sPos; // Stack zuruecksetzen
727 nCount = 0.0;
728 fZaehler = 0.0;
729 fNenner = 0.0;
730 USHORT nErr = 0;
731 PopDoubleRef( aRange );
732 ScValueIterator aValIter(pDok, aRange, glSubTotal);
733 if (aValIter.GetFirst(fWert, nErr))
735 fZaehler += fWert / pow(1.0+x,(double)nCount);
736 fNenner += -nCount * fWert / pow(1.0+x,nCount+1.0);
737 nCount++;
738 while ((nErr == 0) && aValIter.GetNext(fWert, nErr))
740 fZaehler += fWert / pow(1.0+x,(double)nCount);
741 fNenner += -nCount * fWert / pow(1.0+x,nCount+1.0);
742 nCount++;
744 SetError(nErr);
746 xNeu = x - fZaehler / fNenner; // x(i+1) = x(i)-f(x(i))/f'(x(i))
747 nItCount++;
748 fEps = fabs(xNeu - x);
749 x = xNeu;
751 if (fSchaetzwert == 0.0 && fabs(x) < SCdEpsilon)
752 x = 0.0; // auf Null normieren
753 if (fEps < SCdEpsilon)
754 PushDouble(x);
755 else
756 PushError( errNoConvergence);
758 #if defined(WIN) && defined(MSC)
759 #pragma optimize("",on)
760 #endif
763 void ScInterpreter::ScMIRR()
764 { // range_of_values ; rate_invest ; rate_reinvest
765 nFuncFmtType = NUMBERFORMAT_PERCENT;
766 if( MustHaveParamCount( GetByte(), 3 ) )
768 double fRate1_reinvest = GetDouble() + 1;
769 double fNPV_reinvest = 0.0;
770 double fPow_reinvest = 1.0;
772 double fRate1_invest = GetDouble() + 1;
773 double fNPV_invest = 0.0;
774 double fPow_invest = 1.0;
776 ScRange aRange;
777 PopDoubleRef( aRange );
779 if( nGlobalError )
780 PushError( nGlobalError);
781 else
783 ScValueIterator aValIter( pDok, aRange, glSubTotal );
784 double fCellValue;
785 ULONG nCount = 0;
786 USHORT nIterError = 0;
788 BOOL bLoop = aValIter.GetFirst( fCellValue, nIterError );
789 while( bLoop )
791 if( fCellValue > 0.0 ) // reinvestments
792 fNPV_reinvest += fCellValue * fPow_reinvest;
793 else if( fCellValue < 0.0 ) // investments
794 fNPV_invest += fCellValue * fPow_invest;
795 fPow_reinvest /= fRate1_reinvest;
796 fPow_invest /= fRate1_invest;
797 nCount++;
799 bLoop = aValIter.GetNext( fCellValue, nIterError );
801 if( nIterError )
802 PushError( nIterError );
803 else
805 double fResult = -fNPV_reinvest / fNPV_invest;
806 fResult *= pow( fRate1_reinvest, (double) nCount - 1 );
807 fResult = pow( fResult, 1.0 / (nCount - 1) );
808 PushDouble( fResult - 1.0 );
815 void ScInterpreter::ScISPMT()
816 { // rate ; period ; total_periods ; invest
817 if( MustHaveParamCount( GetByte(), 4 ) )
819 double fInvest = GetDouble();
820 double fTotal = GetDouble();
821 double fPeriod = GetDouble();
822 double fRate = GetDouble();
824 if( nGlobalError )
825 PushError( nGlobalError);
826 else
827 PushDouble( fInvest * fRate * (fPeriod / fTotal - 1.0) );
832 //----------------------- Finanzfunktionen ------------------------------------
834 double ScInterpreter::ScGetBw(double fZins, double fZzr, double fRmz,
835 double fZw, double fF)
837 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMIRR" );
838 double fBw;
839 if (fZins == 0.0)
840 fBw = fZw + fRmz * fZzr;
841 else if (fF > 0.0)
842 fBw = (fZw * pow(1.0 + fZins, -fZzr))
843 + (fRmz * (1.0 - pow(1.0 + fZins, -fZzr + 1.0)) / fZins)
844 + fRmz;
845 else
846 fBw = (fZw * pow(1.0 + fZins, -fZzr))
847 + (fRmz * (1.0 - pow(1.0 + fZins, -fZzr)) / fZins);
848 return -fBw;
851 void ScInterpreter::ScBW()
853 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBW" );
854 nFuncFmtType = NUMBERFORMAT_CURRENCY;
855 double nRmz, nZzr, nZins, nZw = 0, nFlag = 0;
856 BYTE nParamCount = GetByte();
857 if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
858 return;
859 if (nParamCount == 5)
860 nFlag = GetDouble();
861 if (nParamCount >= 4)
862 nZw = GetDouble();
863 nRmz = GetDouble();
864 nZzr = GetDouble();
865 nZins = GetDouble();
866 PushDouble(ScGetBw(nZins, nZzr, nRmz, nZw, nFlag));
869 void ScInterpreter::ScDIA()
871 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDIA" );
872 nFuncFmtType = NUMBERFORMAT_CURRENCY;
873 if ( MustHaveParamCount( GetByte(), 4 ) )
875 double nZr = GetDouble();
876 double nDauer = GetDouble();
877 double nRest = GetDouble();
878 double nWert = GetDouble();
879 double nDia = ((nWert - nRest) * (nDauer - nZr + 1.0)) /
880 ((nDauer * (nDauer + 1.0)) / 2.0);
881 PushDouble(nDia);
885 double ScInterpreter::ScGetGDA(double fWert, double fRest, double fDauer,
886 double fPeriode, double fFaktor)
888 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetGDA" );
889 double fGda, fZins, fAlterWert, fNeuerWert;
890 fZins = fFaktor / fDauer;
891 if (fZins >= 1.0)
893 fZins = 1.0;
894 if (fPeriode == 1.0)
895 fAlterWert = fWert;
896 else
897 fAlterWert = 0.0;
899 else
900 fAlterWert = fWert * pow(1.0 - fZins, fPeriode - 1.0);
901 fNeuerWert = fWert * pow(1.0 - fZins, fPeriode);
903 if (fNeuerWert < fRest)
904 fGda = fAlterWert - fRest;
905 else
906 fGda = fAlterWert - fNeuerWert;
907 if (fGda < 0.0)
908 fGda = 0.0;
909 return fGda;
912 void ScInterpreter::ScGDA()
914 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGDA" );
915 nFuncFmtType = NUMBERFORMAT_CURRENCY;
916 BYTE nParamCount = GetByte();
917 if ( MustHaveParamCount( nParamCount, 4, 5 ) )
919 double nFaktor;
920 if (nParamCount == 5)
921 nFaktor = GetDouble();
922 else
923 nFaktor = 2.0;
924 double nPeriode = GetDouble();
925 double nDauer = GetDouble();
926 double nRest = GetDouble();
927 double nWert = GetDouble();
928 if (nWert < 0.0 || nRest < 0.0 || nFaktor <= 0.0 || nRest > nWert
929 || nPeriode < 1.0 || nPeriode > nDauer)
930 PushIllegalArgument();
931 else
932 PushDouble(ScGetGDA(nWert, nRest, nDauer, nPeriode, nFaktor));
936 void ScInterpreter::ScGDA2()
938 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGDA2" );
939 nFuncFmtType = NUMBERFORMAT_CURRENCY;
940 BYTE nParamCount = GetByte();
941 if ( !MustHaveParamCount( nParamCount, 4, 5 ) )
942 return ;
943 double nMonate;
944 if (nParamCount == 4)
945 nMonate = 12.0;
946 else
947 nMonate = ::rtl::math::approxFloor(GetDouble());
948 double nPeriode = GetDouble();
949 double nDauer = GetDouble();
950 double nRest = GetDouble();
951 double nWert = GetDouble();
952 if (nMonate < 1.0 || nMonate > 12.0 || nDauer > 1200.0 || nRest < 0.0 ||
953 nPeriode > (nDauer + 1.0) || nRest > nWert || nWert < 0.0)
955 PushIllegalArgument();
956 return;
958 double nAbRate = 1.0 - pow(nRest / nWert, 1.0 / nDauer);
959 nAbRate = ::rtl::math::approxFloor((nAbRate * 1000.0) + 0.5) / 1000.0;
960 double nErsteAbRate = nWert * nAbRate * nMonate / 12.0;
961 double nGda2 = 0.0;
962 if (::rtl::math::approxFloor(nPeriode) == 1)
963 nGda2 = nErsteAbRate;
964 else
966 double nSummAbRate = nErsteAbRate;
967 double nMin = nDauer;
968 if (nMin > nPeriode) nMin = nPeriode;
969 USHORT iMax = (USHORT)::rtl::math::approxFloor(nMin);
970 for (USHORT i = 2; i <= iMax; i++)
972 nGda2 = (nWert - nSummAbRate) * nAbRate;
973 nSummAbRate += nGda2;
975 if (nPeriode > nDauer)
976 nGda2 = ((nWert - nSummAbRate) * nAbRate * (12.0 - nMonate)) / 12.0;
978 PushDouble(nGda2);
982 double ScInterpreter::ScInterVDB(double fWert,double fRest,double fDauer,
983 double fDauer1,double fPeriode,double fFaktor)
985 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInterVDB" );
986 double fVdb=0;
987 double fIntEnd = ::rtl::math::approxCeil(fPeriode);
988 ULONG nLoopEnd = (ULONG) fIntEnd;
990 double fTerm, fLia;
991 double fRestwert = fWert - fRest;
992 BOOL bNowLia = FALSE;
994 double fGda;
995 ULONG i;
996 fLia=0;
997 for ( i = 1; i <= nLoopEnd; i++)
999 if(!bNowLia)
1001 fGda = ScGetGDA(fWert, fRest, fDauer, (double) i, fFaktor);
1002 fLia = fRestwert/ (fDauer1 - (double) (i-1));
1004 if (fLia > fGda)
1006 fTerm = fLia;
1007 bNowLia = TRUE;
1009 else
1011 fTerm = fGda;
1012 fRestwert -= fGda;
1015 else
1017 fTerm = fLia;
1020 if ( i == nLoopEnd)
1021 fTerm *= ( fPeriode + 1.0 - fIntEnd );
1023 fVdb += fTerm;
1025 return fVdb;
1029 inline double DblMin( double a, double b )
1031 return (a < b) ? a : b;
1034 void ScInterpreter::ScVDB()
1036 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVDB" );
1037 nFuncFmtType = NUMBERFORMAT_CURRENCY;
1038 BYTE nParamCount = GetByte();
1039 if ( MustHaveParamCount( nParamCount, 5, 7 ) )
1041 double fWert, fRest, fDauer, fAnfang, fEnde, fFaktor, fVdb = 0.0;
1042 BOOL bFlag;
1043 if (nParamCount == 7)
1044 bFlag = GetBool();
1045 else
1046 bFlag = FALSE;
1047 if (nParamCount >= 6)
1048 fFaktor = GetDouble();
1049 else
1050 fFaktor = 2.0;
1051 fEnde = GetDouble();
1052 fAnfang = GetDouble();
1053 fDauer = GetDouble();
1054 fRest = GetDouble();
1055 fWert = GetDouble();
1056 if (fAnfang < 0.0 || fEnde < fAnfang || fEnde > fDauer || fWert < 0.0
1057 || fRest > fWert || fFaktor <= 0.0)
1058 PushIllegalArgument();
1059 else
1061 double fIntStart = ::rtl::math::approxFloor(fAnfang);
1062 double fIntEnd = ::rtl::math::approxCeil(fEnde);
1063 ULONG nLoopStart = (ULONG) fIntStart;
1064 ULONG nLoopEnd = (ULONG) fIntEnd;
1066 fVdb = 0.0;
1067 if (bFlag)
1069 for (ULONG i = nLoopStart + 1; i <= nLoopEnd; i++)
1071 double fTerm = ScGetGDA(fWert, fRest, fDauer, (double) i, fFaktor);
1073 // Teilperioden am Anfang / Ende beruecksichtigen:
1074 if ( i == nLoopStart+1 )
1075 fTerm *= ( DblMin( fEnde, fIntStart + 1.0 ) - fAnfang );
1076 else if ( i == nLoopEnd )
1077 fTerm *= ( fEnde + 1.0 - fIntEnd );
1079 fVdb += fTerm;
1082 else
1085 double fDauer1=fDauer;
1086 double fPart;
1088 //@Die Frage aller Fragen: "Ist das hier richtig"
1089 if(!::rtl::math::approxEqual(fAnfang,::rtl::math::approxFloor(fAnfang)))
1091 if(fFaktor>1)
1093 if(fAnfang>fDauer/2 || ::rtl::math::approxEqual(fAnfang,fDauer/2))
1095 fPart=fAnfang-fDauer/2;
1096 fAnfang=fDauer/2;
1097 fEnde-=fPart;
1098 fDauer1+=1;
1103 fWert-=ScInterVDB(fWert,fRest,fDauer,fDauer1,fAnfang,fFaktor);
1104 fVdb=ScInterVDB(fWert,fRest,fDauer,fDauer-fAnfang,fEnde-fAnfang,fFaktor);
1107 PushDouble(fVdb);
1111 void ScInterpreter::ScLaufz()
1113 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLaufz" );
1114 if ( MustHaveParamCount( GetByte(), 3 ) )
1116 double nZukunft = GetDouble();
1117 double nGegenwart = GetDouble();
1118 double nZins = GetDouble();
1119 PushDouble(log(nZukunft / nGegenwart) / log(1.0 + nZins));
1123 void ScInterpreter::ScLIA()
1125 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLIA" );
1126 nFuncFmtType = NUMBERFORMAT_CURRENCY;
1127 if ( MustHaveParamCount( GetByte(), 3 ) )
1129 double nDauer = GetDouble();
1130 double nRest = GetDouble();
1131 double nWert = GetDouble();
1132 PushDouble((nWert - nRest) / nDauer);
1136 double ScInterpreter::ScGetRmz(double fZins, double fZzr, double fBw,
1137 double fZw, double fF)
1139 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetRmz" );
1140 double fRmz;
1141 if (fZins == 0.0)
1142 fRmz = (fBw + fZw) / fZzr;
1143 else
1145 double fTerm = pow(1.0 + fZins, fZzr);
1146 if (fF > 0.0)
1147 fRmz = (fZw * fZins / (fTerm - 1.0)
1148 + fBw * fZins / (1.0 - 1.0 / fTerm)) / (1.0+fZins);
1149 else
1150 fRmz = fZw * fZins / (fTerm - 1.0)
1151 + fBw * fZins / (1.0 - 1.0 / fTerm);
1153 return -fRmz;
1156 void ScInterpreter::ScRMZ()
1158 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRMZ" );
1159 double nZins, nZzr, nBw, nZw = 0, nFlag = 0;
1160 nFuncFmtType = NUMBERFORMAT_CURRENCY;
1161 BYTE nParamCount = GetByte();
1162 if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1163 return;
1164 if (nParamCount == 5)
1165 nFlag = GetDouble();
1166 if (nParamCount >= 4)
1167 nZw = GetDouble();
1168 nBw = GetDouble();
1169 nZzr = GetDouble();
1170 nZins = GetDouble();
1171 PushDouble(ScGetRmz(nZins, nZzr, nBw, nZw, nFlag));
1174 void ScInterpreter::ScZGZ()
1176 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZGZ" );
1177 nFuncFmtType = NUMBERFORMAT_PERCENT;
1178 if ( MustHaveParamCount( GetByte(), 3 ) )
1180 double nZukunftswert = GetDouble();
1181 double nGegenwartswert = GetDouble();
1182 double nZeitraum = GetDouble();
1183 PushDouble(pow(nZukunftswert / nGegenwartswert, 1.0 / nZeitraum) - 1.0);
1187 double ScInterpreter::ScGetZw(double fZins, double fZzr, double fRmz,
1188 double fBw, double fF)
1190 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetZw" );
1191 double fZw;
1192 if (fZins == 0.0)
1193 fZw = fBw + fRmz * fZzr;
1194 else
1196 double fTerm = pow(1.0 + fZins, fZzr);
1197 if (fF > 0.0)
1198 fZw = fBw * fTerm + fRmz*(1.0 + fZins)*(fTerm - 1.0)/fZins;
1199 else
1200 fZw = fBw * fTerm + fRmz*(fTerm - 1.0)/fZins;
1202 return -fZw;
1205 void ScInterpreter::ScZW()
1207 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZW" );
1208 double nZins, nZzr, nRmz, nBw = 0, nFlag = 0;
1209 nFuncFmtType = NUMBERFORMAT_CURRENCY;
1210 BYTE nParamCount = GetByte();
1211 if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1212 return;
1213 if (nParamCount == 5)
1214 nFlag = GetDouble();
1215 if (nParamCount >= 4)
1216 nBw = GetDouble();
1217 nRmz = GetDouble();
1218 nZzr = GetDouble();
1219 nZins = GetDouble();
1220 PushDouble(ScGetZw(nZins, nZzr, nRmz, nBw, nFlag));
1223 void ScInterpreter::ScZZR()
1225 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZZR" );
1226 double nZins, nRmz, nBw, nZw = 0, nFlag = 0;
1227 BYTE nParamCount = GetByte();
1228 if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1229 return;
1230 if (nParamCount == 5)
1231 nFlag = GetDouble();
1232 if (nParamCount >= 4)
1233 nZw = GetDouble();
1234 nBw = GetDouble();
1235 nRmz = GetDouble();
1236 nZins = GetDouble();
1237 if (nZins == 0.0)
1238 PushDouble(-(nBw + nZw)/nRmz);
1239 else if (nFlag > 0.0)
1240 PushDouble(log(-(nZins*nZw-nRmz*(1.0+nZins))/(nZins*nBw+nRmz*(1.0+nZins)))
1241 /log(1.0+nZins));
1242 else
1243 PushDouble(log(-(nZins*nZw-nRmz)/(nZins*nBw+nRmz))/log(1.0+nZins));
1246 bool ScInterpreter::RateIteration( double fNper, double fPayment, double fPv,
1247 double fFv, double fPayType, double & fGuess )
1249 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RateIteration" );
1250 // See also #i15090#
1251 // Newton-Raphson method: x(i+1) = x(i) - f(x(i)) / f'(x(i))
1252 // This solution handles integer and non-integer values of Nper different.
1253 // If ODFF will constraint Nper to integer, the distinction of cases can be
1254 // removed; only the integer-part is needed then.
1255 bool bValid = true, bFound = false;
1256 double fX, fXnew, fTerm, fTermDerivation;
1257 double fGeoSeries, fGeoSeriesDerivation;
1258 const USHORT nIterationsMax = 150;
1259 USHORT nCount = 0;
1260 const double fEpsilonSmall = 1.0E-14;
1261 // convert any fPayType situation to fPayType == zero situation
1262 fFv = fFv - fPayment * fPayType;
1263 fPv = fPv + fPayment * fPayType;
1264 if (fNper == ::rtl::math::round( fNper, 0, rtl_math_RoundingMode_Corrected ))
1265 { // Nper is an integer value
1266 fX = fGuess;
1267 double fPowN, fPowNminus1; // for (1.0+fX)^Nper and (1.0+fX)^(Nper-1)
1268 while (!bFound && nCount < nIterationsMax)
1270 fPowNminus1 = pow( 1.0+fX, fNper-1.0);
1271 fPowN = fPowNminus1 * (1.0+fX);
1272 if (rtl::math::approxEqual( fabs(fX), 0.0))
1274 fGeoSeries = fNper;
1275 fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
1277 else
1279 fGeoSeries = (fPowN-1.0)/fX;
1280 fGeoSeriesDerivation = fNper * fPowNminus1 / fX - fGeoSeries / fX;
1282 fTerm = fFv + fPv *fPowN+ fPayment * fGeoSeries;
1283 fTermDerivation = fPv * fNper * fPowNminus1 + fPayment * fGeoSeriesDerivation;
1284 if (fabs(fTerm) < fEpsilonSmall)
1285 bFound = true; // will catch root which is at an extreme
1286 else
1288 if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0))
1289 fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
1290 else
1291 fXnew = fX - fTerm / fTermDerivation;
1292 nCount++;
1293 // more accuracy not possible in oscillating cases
1294 bFound = (fabs(fXnew - fX) < SCdEpsilon);
1295 fX = fXnew;
1298 // Gnumeric returns roots < -1, Excel gives an error in that cases,
1299 // ODFF says nothing about it. Enable the statement, if you want Excel's
1300 // behavior
1301 //bValid =(fX >=-1.0);
1303 else
1304 { // Nper is not an integer value.
1305 fX = (fGuess < -1.0) ? -1.0 : fGuess; // start with a valid fX
1306 while (bValid && !bFound && nCount < nIterationsMax)
1308 if (rtl::math::approxEqual( fabs(fX), 0.0))
1310 fGeoSeries = fNper;
1311 fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
1313 else
1315 fGeoSeries = (pow( 1.0+fX, fNper) - 1.0) / fX;
1316 fGeoSeriesDerivation = fNper * pow( 1.0+fX, fNper-1.0) / fX - fGeoSeries / fX;
1318 fTerm = fFv + fPv *pow(1.0 + fX,fNper)+ fPayment * fGeoSeries;
1319 fTermDerivation = fPv * fNper * pow( 1.0+fX, fNper-1.0) + fPayment * fGeoSeriesDerivation;
1320 if (fabs(fTerm) < fEpsilonSmall)
1321 bFound = true; // will catch root which is at an extreme
1322 else
1324 if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0))
1325 fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
1326 else
1327 fXnew = fX - fTerm / fTermDerivation;
1328 nCount++;
1329 // more accuracy not possible in oscillating cases
1330 bFound = (fabs(fXnew - fX) < SCdEpsilon);
1331 fX = fXnew;
1332 bValid = (fX >= -1.0); // otherwise pow(1.0+fX,fNper) will fail
1336 fGuess = fX; // return approximate root
1337 return bValid && bFound;
1340 // In Calc UI it is the function RATE(Nper;Pmt;Pv;Fv;Type;Guess)
1341 void ScInterpreter::ScZins()
1343 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZins" );
1344 double fPv, fPayment, fNper;
1345 // defaults for missing arguments, see ODFF spec
1346 double fFv = 0, fPayType = 0, fGuess = 0.1;
1347 bool bValid = true;
1348 nFuncFmtType = NUMBERFORMAT_PERCENT;
1349 BYTE nParamCount = GetByte();
1350 if ( !MustHaveParamCount( nParamCount, 3, 6 ) )
1351 return;
1352 if (nParamCount == 6)
1353 fGuess = GetDouble();
1354 if (nParamCount >= 5)
1355 fPayType = GetDouble();
1356 if (nParamCount >= 4)
1357 fFv = GetDouble();
1358 fPv = GetDouble();
1359 fPayment = GetDouble();
1360 fNper = GetDouble();
1361 if (fNper <= 0.0) // constraint from ODFF spec
1363 PushIllegalArgument();
1364 return;
1366 // other values for fPayType might be meaningful,
1367 // ODFF spec is not clear yet, enable statement if you want only 0 and 1
1368 //if (fPayType != 0.0) fPayType = 1.0;
1369 bValid = RateIteration(fNper, fPayment, fPv, fFv, fPayType, fGuess);
1370 if (!bValid)
1371 SetError(errNoConvergence);
1372 PushDouble(fGuess);
1375 double ScInterpreter::ScGetZinsZ(double fZins, double fZr, double fZzr, double fBw,
1376 double fZw, double fF, double& fRmz)
1378 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetZinsZ" );
1379 fRmz = ScGetRmz(fZins, fZzr, fBw, fZw, fF); // fuer kapz auch bei fZr == 1
1380 double fZinsZ;
1381 nFuncFmtType = NUMBERFORMAT_CURRENCY;
1382 if (fZr == 1.0)
1384 if (fF > 0.0)
1385 fZinsZ = 0.0;
1386 else
1387 fZinsZ = -fBw;
1389 else
1391 if (fF > 0.0)
1392 fZinsZ = ScGetZw(fZins, fZr-2.0, fRmz, fBw, 1.0) - fRmz;
1393 else
1394 fZinsZ = ScGetZw(fZins, fZr-1.0, fRmz, fBw, 0.0);
1396 return fZinsZ * fZins;
1399 void ScInterpreter::ScZinsZ()
1401 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZinsZ" );
1402 double nZins, nZr, nRmz, nZzr, nBw, nZw = 0, nFlag = 0;
1403 nFuncFmtType = NUMBERFORMAT_CURRENCY;
1404 BYTE nParamCount = GetByte();
1405 if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
1406 return;
1407 if (nParamCount == 6)
1408 nFlag = GetDouble();
1409 if (nParamCount >= 5)
1410 nZw = GetDouble();
1411 nBw = GetDouble();
1412 nZzr = GetDouble();
1413 nZr = GetDouble();
1414 nZins = GetDouble();
1415 if (nZr < 1.0 || nZr > nZzr)
1416 PushIllegalArgument();
1417 else
1418 PushDouble(ScGetZinsZ(nZins, nZr, nZzr, nBw, nZw, nFlag, nRmz));
1421 void ScInterpreter::ScKapz()
1423 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKapz" );
1424 double nZins, nZr, nZzr, nBw, nZw = 0, nFlag = 0, nRmz, nZinsz;
1425 nFuncFmtType = NUMBERFORMAT_CURRENCY;
1426 BYTE nParamCount = GetByte();
1427 if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
1428 return;
1429 if (nParamCount == 6)
1430 nFlag = GetDouble();
1431 if (nParamCount >= 5)
1432 nZw = GetDouble();
1433 nBw = GetDouble();
1434 nZzr = GetDouble();
1435 nZr = GetDouble();
1436 nZins = GetDouble();
1437 if (nZr < 1.0 || nZr > nZzr)
1438 PushIllegalArgument();
1439 else
1441 nZinsz = ScGetZinsZ(nZins, nZr, nZzr, nBw, nZw, nFlag, nRmz);
1442 PushDouble(nRmz - nZinsz);
1446 void ScInterpreter::ScKumZinsZ()
1448 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKumZinsZ" );
1449 nFuncFmtType = NUMBERFORMAT_CURRENCY;
1450 if ( MustHaveParamCount( GetByte(), 6 ) )
1452 double fZins, fZzr, fBw, fAnfang, fEnde, fF, fRmz, fZinsZ;
1453 fF = GetDouble();
1454 fEnde = ::rtl::math::approxFloor(GetDouble());
1455 fAnfang = ::rtl::math::approxFloor(GetDouble());
1456 fBw = GetDouble();
1457 fZzr = GetDouble();
1458 fZins = GetDouble();
1459 if (fAnfang < 1.0 || fEnde < fAnfang || fZins <= 0.0 ||
1460 fEnde > fZzr || fZzr <= 0.0 || fBw <= 0.0)
1461 PushIllegalArgument();
1462 else
1464 ULONG nAnfang = (ULONG) fAnfang;
1465 ULONG nEnde = (ULONG) fEnde ;
1466 fRmz = ScGetRmz(fZins, fZzr, fBw, 0.0, fF);
1467 fZinsZ = 0.0;
1468 if (nAnfang == 1)
1470 if (fF <= 0.0)
1471 fZinsZ = -fBw;
1472 nAnfang++;
1474 for (ULONG i = nAnfang; i <= nEnde; i++)
1476 if (fF > 0.0)
1477 fZinsZ += ScGetZw(fZins, (double)(i-2), fRmz, fBw, 1.0) - fRmz;
1478 else
1479 fZinsZ += ScGetZw(fZins, (double)(i-1), fRmz, fBw, 0.0);
1481 fZinsZ *= fZins;
1482 PushDouble(fZinsZ);
1487 void ScInterpreter::ScKumKapZ()
1489 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKumKapZ" );
1490 nFuncFmtType = NUMBERFORMAT_CURRENCY;
1491 if ( MustHaveParamCount( GetByte(), 6 ) )
1493 double fZins, fZzr, fBw, fAnfang, fEnde, fF, fRmz, fKapZ;
1494 fF = GetDouble();
1495 fEnde = ::rtl::math::approxFloor(GetDouble());
1496 fAnfang = ::rtl::math::approxFloor(GetDouble());
1497 fBw = GetDouble();
1498 fZzr = GetDouble();
1499 fZins = GetDouble();
1500 if (fAnfang < 1.0 || fEnde < fAnfang || fZins <= 0.0 ||
1501 fEnde > fZzr || fZzr <= 0.0 || fBw <= 0.0)
1502 PushIllegalArgument();
1503 else
1505 fRmz = ScGetRmz(fZins, fZzr, fBw, 0.0, fF);
1506 fKapZ = 0.0;
1507 ULONG nAnfang = (ULONG) fAnfang;
1508 ULONG nEnde = (ULONG) fEnde;
1509 if (nAnfang == 1)
1511 if (fF <= 0.0)
1512 fKapZ = fRmz + fBw * fZins;
1513 else
1514 fKapZ = fRmz;
1515 nAnfang++;
1517 for (ULONG i = nAnfang; i <= nEnde; i++)
1519 if (fF > 0.0)
1520 fKapZ += fRmz - (ScGetZw(fZins, (double)(i-2), fRmz, fBw, 1.0) - fRmz) * fZins;
1521 else
1522 fKapZ += fRmz - ScGetZw(fZins, (double)(i-1), fRmz, fBw, 0.0) * fZins;
1524 PushDouble(fKapZ);
1529 void ScInterpreter::ScEffektiv()
1531 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEffektiv" );
1532 nFuncFmtType = NUMBERFORMAT_PERCENT;
1533 if ( MustHaveParamCount( GetByte(), 2 ) )
1535 double fPerioden = GetDouble();
1536 double fNominal = GetDouble();
1537 if (fPerioden < 1.0 || fNominal <= 0.0)
1538 PushIllegalArgument();
1539 else
1541 fPerioden = ::rtl::math::approxFloor(fPerioden);
1542 PushDouble(pow(1.0 + fNominal/fPerioden, fPerioden) - 1.0);
1547 void ScInterpreter::ScNominal()
1549 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNominal" );
1550 nFuncFmtType = NUMBERFORMAT_PERCENT;
1551 if ( MustHaveParamCount( GetByte(), 2 ) )
1553 double fPerioden = GetDouble();
1554 double fEffektiv = GetDouble();
1555 if (fPerioden < 1.0 || fEffektiv <= 0.0)
1556 PushIllegalArgument();
1557 else
1559 fPerioden = ::rtl::math::approxFloor(fPerioden);
1560 PushDouble( (pow(fEffektiv + 1.0, 1.0 / fPerioden) - 1.0) * fPerioden );
1565 void ScInterpreter::ScMod()
1567 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMod" );
1568 if ( MustHaveParamCount( GetByte(), 2 ) )
1570 double fVal2 = GetDouble(); // Denominator
1571 double fVal1 = GetDouble(); // Numerator
1572 if (fVal2 == floor(fVal2)) // a pure integral number stored in double
1574 double fResult = fmod(fVal1,fVal2);
1575 if ( (fResult != 0.0) &&
1576 ((fVal1 > 0.0 && fVal2 < 0.0) || (fVal1 < 0.0 && fVal2 > 0.0)))
1577 fResult += fVal2 ;
1578 PushDouble( fResult );
1580 else
1582 PushDouble( ::rtl::math::approxSub( fVal1,
1583 ::rtl::math::approxFloor(fVal1 / fVal2) * fVal2));
1588 /** (Goal Seek) Find a value of x that is a root of f(x)
1590 This function is used internally for the goal seek operation. It uses the
1591 Regula Falsi (aka false position) algorithm to find a root of f(x). The
1592 start value and the target value are to be given by the user in the
1593 goal seek dialog. The f(x) in this case is defined as the formula in the
1594 formula cell minus target value. This function may also perform additional
1595 search in the horizontal directions when the f(x) is discrete in order to
1596 ensure a non-zero slope necessary for deriving a subsequent x that is
1597 reasonably close to the root of interest.
1599 @change 24.10.2004 by Kohei Yoshida (kohei@openoffice.org)
1601 @see #i28955#
1603 void ScInterpreter::ScBackSolver()
1605 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBackSolver" );
1606 if ( MustHaveParamCount( GetByte(), 3 ) )
1608 BOOL bDoneIteration = FALSE;
1609 ScAddress aValueAdr, aFormulaAdr;
1610 double fTargetVal = GetDouble();
1611 PopSingleRef( aFormulaAdr );
1612 PopSingleRef( aValueAdr );
1614 if (nGlobalError == 0)
1616 ScBaseCell* pVCell = GetCell( aValueAdr );
1617 // CELLTYPE_NOTE: kein Value aber von Formel referiert
1618 BOOL bTempCell = (!pVCell || pVCell->GetCellType() == CELLTYPE_NOTE);
1619 ScBaseCell* pFCell = GetCell( aFormulaAdr );
1621 if ( ((pVCell && pVCell->GetCellType() == CELLTYPE_VALUE) || bTempCell)
1622 && pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA )
1624 ScRange aVRange( aValueAdr, aValueAdr ); // fuer SetDirty
1625 double fSaveVal; // Original value to be restored later if necessary
1626 ScPostIt* pNote = 0;
1628 if ( bTempCell )
1630 pNote = pVCell ? pVCell->ReleaseNote() : 0;
1631 fSaveVal = 0.0;
1632 pVCell = new ScValueCell( fSaveVal );
1633 pDok->PutCell( aValueAdr, pVCell );
1635 else
1636 fSaveVal = GetCellValue( aValueAdr, pVCell );
1638 const USHORT nMaxIter = 100;
1639 const double fEps = 1E-10;
1640 const double fDelta = 1E-6;
1642 double fBestX, fXPrev;
1643 double fBestF, fFPrev;
1644 fBestX = fXPrev = fSaveVal;
1646 ScFormulaCell* pFormula = (ScFormulaCell*) pFCell;
1647 ScValueCell* pValue = (ScValueCell*) pVCell;
1649 pFormula->Interpret();
1650 BOOL bError = ( pFormula->GetErrCode() != 0 );
1651 // bError always corresponds with fF
1653 fFPrev = pFormula->GetValue() - fTargetVal;
1655 fBestF = fabs( fFPrev );
1656 if ( fBestF < fDelta )
1657 bDoneIteration = TRUE;
1659 double fX = fXPrev + fEps;
1660 double fF = fFPrev;
1661 double fSlope;
1663 USHORT nIter = 0;
1665 BOOL bHorMoveError = FALSE;
1666 // Nach der Regula Falsi Methode
1667 while ( !bDoneIteration && ( nIter++ < nMaxIter ) )
1669 pValue->SetValue( fX );
1670 pDok->SetDirty( aVRange );
1671 pFormula->Interpret();
1672 bError = ( pFormula->GetErrCode() != 0 );
1673 fF = pFormula->GetValue() - fTargetVal;
1675 if ( fF == fFPrev && !bError )
1677 // HORIZONTAL SEARCH: Keep moving x in both directions until the f(x)
1678 // becomes different from the previous f(x). This routine is needed
1679 // when a given function is discrete, in which case the resulting slope
1680 // may become zero which ultimately causes the goal seek operation
1681 // to fail. #i28955#
1683 USHORT nHorIter = 0;
1684 const double fHorStepAngle = 5.0;
1685 const double fHorMaxAngle = 80.0;
1686 int nHorMaxIter = static_cast<int>( fHorMaxAngle / fHorStepAngle );
1687 BOOL bDoneHorMove = FALSE;
1689 while ( !bDoneHorMove && !bHorMoveError && nHorIter++ < nHorMaxIter )
1691 double fHorAngle = fHorStepAngle * static_cast<double>( nHorIter );
1692 double fHorTangent = ::rtl::math::tan( fHorAngle * F_PI / 180 );
1694 USHORT nIdx = 0;
1695 while( nIdx++ < 2 && !bDoneHorMove )
1697 double fHorX;
1698 if ( nIdx == 1 )
1699 fHorX = fX + fabs(fF)*fHorTangent;
1700 else
1701 fHorX = fX - fabs(fF)*fHorTangent;
1703 pValue->SetValue( fHorX );
1704 pDok->SetDirty( aVRange );
1705 pFormula->Interpret();
1706 bHorMoveError = ( pFormula->GetErrCode() != 0 );
1707 if ( bHorMoveError )
1708 break;
1710 fF = pFormula->GetValue() - fTargetVal;
1711 if ( fF != fFPrev )
1713 fX = fHorX;
1714 bDoneHorMove = TRUE;
1718 if ( !bDoneHorMove )
1719 bHorMoveError = TRUE;
1722 if ( bError )
1724 // move closer to last valid value (fXPrev), keep fXPrev & fFPrev
1725 double fDiff = ( fXPrev - fX ) / 2;
1726 if (fabs(fDiff) < fEps)
1727 fDiff = (fDiff < 0.0) ? - fEps : fEps;
1728 fX += fDiff;
1730 else if ( bHorMoveError )
1731 break;
1732 else if ( fabs(fF) < fDelta )
1734 // converged to root
1735 fBestX = fX;
1736 bDoneIteration = TRUE;
1738 else
1740 if ( fabs(fF) + fDelta < fBestF )
1742 fBestX = fX;
1743 fBestF = fabs(fF);
1746 if ( ( fXPrev - fX ) != 0 )
1748 fSlope = ( fFPrev - fF ) / ( fXPrev - fX );
1749 if ( fabs( fSlope ) < fEps )
1750 fSlope = fSlope < 0.0 ? -fEps : fEps;
1752 else
1753 fSlope = fEps;
1755 fXPrev = fX;
1756 fFPrev = fF;
1757 fX = fX - ( fF / fSlope );
1761 // Try a nice rounded input value if possible.
1762 const double fNiceDelta = (bDoneIteration && fabs(fBestX) >= 1e-3 ? 1e-3 : fDelta);
1763 double nX = ::rtl::math::approxFloor((fBestX / fNiceDelta) + 0.5) * fNiceDelta;
1764 // double nX = ::rtl::math::approxFloor((fBestX / fDelta) + 0.5) * fDelta;
1766 if ( bDoneIteration )
1768 pValue->SetValue( nX );
1769 pDok->SetDirty( aVRange );
1770 pFormula->Interpret();
1771 if ( fabs( pFormula->GetValue() - fTargetVal ) > fabs( fF ) )
1772 nX = fBestX;
1774 else if ( bError || bHorMoveError )
1776 nX = fBestX;
1778 if ( bTempCell )
1780 pVCell = pNote ? new ScNoteCell( pNote ) : 0;
1781 pDok->PutCell( aValueAdr, pVCell );
1783 else
1784 pValue->SetValue( fSaveVal );
1785 pDok->SetDirty( aVRange );
1786 pFormula->Interpret();
1787 if ( !bDoneIteration )
1788 SetError(NOTAVAILABLE);
1789 PushDouble(nX);
1791 else
1793 if ( !bDoneIteration )
1794 SetError(NOTAVAILABLE);
1795 PushInt(0); // falsche Zelltypen
1798 else
1800 if ( !bDoneIteration )
1801 SetError(NOTAVAILABLE);
1802 PushInt(0); // nGlobalError
1807 void ScInterpreter::ScIntersect()
1809 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIntersect" );
1810 formula::FormulaTokenRef p2nd = PopToken();
1811 formula::FormulaTokenRef p1st = PopToken();
1813 if (nGlobalError || !p2nd || !p1st)
1815 PushIllegalArgument();
1816 return;
1817 } // if (nGlobalError || !xT2 || !xT1)
1819 StackVar sv1 = p1st->GetType();
1820 StackVar sv2 = p2nd->GetType();
1821 if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
1822 (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
1824 PushIllegalArgument();
1825 return;
1828 ScToken* x1 = static_cast<ScToken*>(p1st.get());
1829 ScToken* x2 = static_cast<ScToken*>(p2nd.get());
1830 if (sv1 == svRefList || sv2 == svRefList)
1832 // Now this is a bit nasty but it simplifies things, and having
1833 // intersections with lists isn't too common, if at all..
1834 // Convert a reference to list.
1835 ScToken* xt[2] = { x1, x2 };
1836 StackVar sv[2] = { sv1, sv2 };
1837 for (size_t i=0; i<2; ++i)
1839 if (sv[i] == svSingleRef)
1841 ScComplexRefData aRef;
1842 aRef.Ref1 = aRef.Ref2 = xt[i]->GetSingleRef();
1843 xt[i] = new ScRefListToken;
1844 xt[i]->GetRefList()->push_back( aRef);
1846 else if (sv[i] == svDoubleRef)
1848 ScComplexRefData aRef = xt[i]->GetDoubleRef();
1849 xt[i] = new ScRefListToken;
1850 xt[i]->GetRefList()->push_back( aRef);
1853 x1 = xt[0], x2 = xt[1];
1855 x1->CalcAbsIfRel( aPos);
1856 x2->CalcAbsIfRel( aPos);
1857 ScTokenRef xRes = new ScRefListToken;
1858 ScRefList* pRefList = xRes->GetRefList();
1859 ScRefList::const_iterator end1( x1->GetRefList()->end());
1860 ScRefList::const_iterator end2( x2->GetRefList()->end());
1861 for (ScRefList::const_iterator it1( x1->GetRefList()->begin());
1862 it1 != end1; ++it1)
1864 const ScSingleRefData& r11 = (*it1).Ref1;
1865 const ScSingleRefData& r12 = (*it1).Ref2;
1866 for (ScRefList::const_iterator it2( x2->GetRefList()->begin());
1867 it2 != end2; ++it2)
1869 const ScSingleRefData& r21 = (*it2).Ref1;
1870 const ScSingleRefData& r22 = (*it2).Ref2;
1871 SCCOL nCol1 = ::std::max( r11.nCol, r21.nCol);
1872 SCROW nRow1 = ::std::max( r11.nRow, r21.nRow);
1873 SCTAB nTab1 = ::std::max( r11.nTab, r21.nTab);
1874 SCCOL nCol2 = ::std::min( r12.nCol, r22.nCol);
1875 SCROW nRow2 = ::std::min( r12.nRow, r22.nRow);
1876 SCTAB nTab2 = ::std::min( r12.nTab, r22.nTab);
1877 if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
1878 ; // nothing
1879 else
1881 ScComplexRefData aRef;
1882 aRef.InitRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
1883 pRefList->push_back( aRef);
1887 size_t n = pRefList->size();
1888 if (!n)
1889 PushError( errNoRef);
1890 else if (n == 1)
1892 const ScComplexRefData& rRef = (*pRefList)[0];
1893 if (rRef.Ref1 == rRef.Ref2)
1894 PushTempToken( new ScSingleRefToken( rRef.Ref1));
1895 else
1896 PushTempToken( new ScDoubleRefToken( rRef));
1898 else
1899 PushTempToken( xRes);
1901 else
1903 ScToken* pt[2] = { x1, x2 };
1904 StackVar sv[2] = { sv1, sv2 };
1905 SCCOL nC1[2], nC2[2];
1906 SCROW nR1[2], nR2[2];
1907 SCTAB nT1[2], nT2[2];
1908 for (size_t i=0; i<2; ++i)
1910 switch (sv[i])
1912 case svSingleRef:
1913 case svDoubleRef:
1914 pt[i]->CalcAbsIfRel( aPos);
1916 const ScSingleRefData& r = pt[i]->GetSingleRef();
1917 nC1[i] = r.nCol;
1918 nR1[i] = r.nRow;
1919 nT1[i] = r.nTab;
1921 if (sv[i] == svDoubleRef)
1923 const ScSingleRefData& r = pt[i]->GetSingleRef2();
1924 nC2[i] = r.nCol;
1925 nR2[i] = r.nRow;
1926 nT2[i] = r.nTab;
1928 else
1930 nC2[i] = nC1[i];
1931 nR2[i] = nR1[i];
1932 nT2[i] = nT1[i];
1934 break;
1935 default:
1936 ; // nothing, prevent compiler warning
1939 SCCOL nCol1 = ::std::max( nC1[0], nC1[1]);
1940 SCROW nRow1 = ::std::max( nR1[0], nR1[1]);
1941 SCTAB nTab1 = ::std::max( nT1[0], nT1[1]);
1942 SCCOL nCol2 = ::std::min( nC2[0], nC2[1]);
1943 SCROW nRow2 = ::std::min( nR2[0], nR2[1]);
1944 SCTAB nTab2 = ::std::min( nT2[0], nT2[1]);
1945 if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
1946 PushError( errNoRef);
1947 else if (nCol2 == nCol1 && nRow2 == nRow1 && nTab2 == nTab1)
1948 PushSingleRef( nCol1, nRow1, nTab1);
1949 else
1950 PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
1955 void ScInterpreter::ScRangeFunc()
1957 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRangeFunc" );
1958 formula::FormulaTokenRef x2 = PopToken();
1959 formula::FormulaTokenRef x1 = PopToken();
1961 if (nGlobalError || !x2 || !x1)
1963 PushIllegalArgument();
1964 return;
1965 } // if (nGlobalError || !xT2 || !xT1)
1966 FormulaTokenRef xRes = ScToken::ExtendRangeReference( *x1, *x2, aPos, false);
1967 if (!xRes)
1968 PushIllegalArgument();
1969 else
1970 PushTempToken( xRes);
1974 void ScInterpreter::ScUnionFunc()
1976 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScUnionFunc" );
1977 formula::FormulaTokenRef p2nd = PopToken();
1978 formula::FormulaTokenRef p1st = PopToken();
1980 if (nGlobalError || !p2nd || !p1st)
1982 PushIllegalArgument();
1983 return;
1984 } // if (nGlobalError || !xT2 || !xT1)
1986 StackVar sv1 = p1st->GetType();
1987 StackVar sv2 = p2nd->GetType();
1988 if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
1989 (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
1991 PushIllegalArgument();
1992 return;
1995 ScToken* x1 = static_cast<ScToken*>(p1st.get());
1996 ScToken* x2 = static_cast<ScToken*>(p2nd.get());
1999 ScTokenRef xRes;
2000 // Append to an existing RefList if there is one.
2001 if (sv1 == svRefList)
2003 xRes = x1;
2004 sv1 = svUnknown; // mark as handled
2006 else if (sv2 == svRefList)
2008 xRes = x2;
2009 sv2 = svUnknown; // mark as handled
2011 else
2012 xRes = new ScRefListToken;
2013 ScRefList* pRes = xRes->GetRefList();
2014 ScToken* pt[2] = { x1, x2 };
2015 StackVar sv[2] = { sv1, sv2 };
2016 for (size_t i=0; i<2; ++i)
2018 if (pt[i] == xRes)
2019 continue;
2020 switch (sv[i])
2022 case svSingleRef:
2024 ScComplexRefData aRef;
2025 aRef.Ref1 = aRef.Ref2 = pt[i]->GetSingleRef();
2026 pRes->push_back( aRef);
2028 break;
2029 case svDoubleRef:
2030 pRes->push_back( pt[i]->GetDoubleRef());
2031 break;
2032 case svRefList:
2034 const ScRefList* p = pt[i]->GetRefList();
2035 ScRefList::const_iterator it( p->begin());
2036 ScRefList::const_iterator end( p->end());
2037 for ( ; it != end; ++it)
2039 pRes->push_back( *it);
2042 break;
2043 default:
2044 ; // nothing, prevent compiler warning
2047 ValidateRef( *pRes); // set #REF! if needed
2048 PushTempToken( xRes);
2052 void ScInterpreter::ScCurrent()
2054 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCurrent" );
2055 FormulaTokenRef xTok( PopToken());
2056 if (xTok)
2058 PushTempToken( xTok);
2059 PushTempToken( xTok);
2061 else
2062 PushError( errUnknownStackVariable);
2065 void ScInterpreter::ScStyle()
2067 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStyle" );
2068 BYTE nParamCount = GetByte();
2069 if (nParamCount >= 1 && nParamCount <= 3)
2071 String aStyle2; // Vorlage nach Timer
2072 if (nParamCount >= 3)
2073 aStyle2 = GetString();
2074 long nTimeOut = 0; // Timeout
2075 if (nParamCount >= 2)
2076 nTimeOut = (long)(GetDouble()*1000.0);
2077 String aStyle1 = GetString(); // Vorlage fuer sofort
2079 if (nTimeOut < 0)
2080 nTimeOut = 0;
2083 // Request ausfuehren, um Vorlage anzuwenden
2086 if ( !pDok->IsClipOrUndo() )
2088 SfxObjectShell* pShell = pDok->GetDocumentShell();
2089 if (pShell)
2091 //! notify object shell directly
2093 ScRange aRange(aPos);
2094 ScAutoStyleHint aHint( aRange, aStyle1, nTimeOut, aStyle2 );
2095 pShell->Broadcast( aHint );
2099 PushDouble(0.0);
2101 else
2102 PushIllegalParameter();
2105 ScDdeLink* lcl_GetDdeLink( SvxLinkManager* pLinkMgr,
2106 const String& rA, const String& rT, const String& rI, BYTE nM )
2108 USHORT nCount = pLinkMgr->GetLinks().Count();
2109 for (USHORT i=0; i<nCount; i++ )
2111 ::sfx2::SvBaseLink* pBase = *pLinkMgr->GetLinks()[i];
2112 if (pBase->ISA(ScDdeLink))
2114 ScDdeLink* pLink = (ScDdeLink*)pBase;
2115 if ( pLink->GetAppl() == rA &&
2116 pLink->GetTopic() == rT &&
2117 pLink->GetItem() == rI &&
2118 pLink->GetMode() == nM )
2119 return pLink;
2123 return NULL;
2126 void ScInterpreter::ScDde()
2128 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDde" );
2129 // Applikation, Datei, Bereich
2130 // Application, Topic, Item
2132 BYTE nParamCount = GetByte();
2133 if ( MustHaveParamCount( nParamCount, 3, 4 ) )
2135 BYTE nMode = SC_DDE_DEFAULT;
2136 if (nParamCount == 4)
2137 nMode = (BYTE) ::rtl::math::approxFloor(GetDouble());
2138 String aItem = GetString();
2139 String aTopic = GetString();
2140 String aAppl = GetString();
2142 if (nMode > SC_DDE_TEXT)
2143 nMode = SC_DDE_DEFAULT;
2145 // temporary documents (ScFunctionAccess) have no DocShell
2146 // and no LinkManager -> abort
2148 SvxLinkManager* pLinkMgr = pDok->GetLinkManager();
2149 if (!pLinkMgr)
2151 PushNoValue();
2152 return;
2155 // Nach dem Laden muss neu interpretiert werden (Verknuepfungen aufbauen)
2157 if ( pMyFormulaCell->GetCode()->IsRecalcModeNormal() )
2158 pMyFormulaCell->GetCode()->SetRecalcModeOnLoad();
2160 // solange der Link nicht ausgewertet ist, Idle abklemmen
2161 // (um zirkulaere Referenzen zu vermeiden)
2163 BOOL bOldDis = pDok->IsIdleDisabled();
2164 pDok->DisableIdle( TRUE );
2166 // Link-Objekt holen / anlegen
2168 ScDdeLink* pLink = lcl_GetDdeLink( pLinkMgr, aAppl, aTopic, aItem, nMode );
2170 //! Dde-Links (zusaetzlich) effizienter am Dokument speichern !!!!!
2171 // ScDdeLink* pLink = pDok->GetDdeLink( aAppl, aTopic, aItem );
2173 BOOL bWasError = ( pMyFormulaCell->GetRawError() != 0 );
2175 if (!pLink)
2177 pLink = new ScDdeLink( pDok, aAppl, aTopic, aItem, nMode );
2178 pLinkMgr->InsertDDELink( pLink, aAppl, aTopic, aItem );
2179 if ( pLinkMgr->GetLinks().Count() == 1 ) // erster ?
2181 SfxBindings* pBindings = pDok->GetViewBindings();
2182 if (pBindings)
2183 pBindings->Invalidate( SID_LINKS ); // Link-Manager enablen
2186 //! asynchron auswerten ???
2187 pLink->TryUpdate(); // TryUpdate ruft Update nicht mehrfach auf
2189 // StartListening erst nach dem Update, sonst circular reference
2190 pMyFormulaCell->StartListening( *pLink );
2192 else
2194 pMyFormulaCell->StartListening( *pLink );
2197 // Wenn aus dem Reschedule beim Ausfuehren des Links ein Fehler
2198 // (z.B. zirkulaere Referenz) entstanden ist, der vorher nicht da war,
2199 // das Fehler-Flag zuruecksetzen:
2201 if ( pMyFormulaCell->GetRawError() && !bWasError )
2202 pMyFormulaCell->SetErrCode(0);
2204 // Wert abfragen
2206 const ScMatrix* pLinkMat = pLink->GetResult();
2207 if (pLinkMat)
2209 SCSIZE nC, nR;
2210 pLinkMat->GetDimensions(nC, nR);
2211 ScMatrixRef pNewMat = GetNewMat( nC, nR);
2212 if (pNewMat)
2214 pLinkMat->MatCopy(*pNewMat); // kopieren
2215 PushMatrix( pNewMat );
2217 else
2218 PushIllegalArgument();
2220 else
2221 PushNA();
2223 pDok->DisableIdle( bOldDis );
2227 void ScInterpreter::ScBase()
2228 { // Value, Base [, MinLen]
2229 BYTE nParamCount = GetByte();
2230 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
2232 static const sal_Unicode __FAR_DATA pDigits[] = {
2233 '0','1','2','3','4','5','6','7','8','9',
2234 'A','B','C','D','E','F','G','H','I','J','K','L','M',
2235 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
2238 static const int nDigits = (sizeof(pDigits)/sizeof(sal_Unicode))-1;
2239 xub_StrLen nMinLen;
2240 if ( nParamCount == 3 )
2242 double fLen = ::rtl::math::approxFloor( GetDouble() );
2243 if ( 1.0 <= fLen && fLen < STRING_MAXLEN )
2244 nMinLen = (xub_StrLen) fLen;
2245 else if ( fLen == 0.0 )
2246 nMinLen = 1;
2247 else
2248 nMinLen = 0; // Error
2250 else
2251 nMinLen = 1;
2252 double fBase = ::rtl::math::approxFloor( GetDouble() );
2253 double fVal = ::rtl::math::approxFloor( GetDouble() );
2254 double fChars = ((fVal > 0.0 && fBase > 0.0) ?
2255 (ceil( log( fVal ) / log( fBase ) ) + 2.0) :
2256 2.0);
2257 if ( fChars >= STRING_MAXLEN )
2258 nMinLen = 0; // Error
2260 if ( !nGlobalError && nMinLen && 2 <= fBase && fBase <= nDigits && 0 <= fVal )
2262 const xub_StrLen nConstBuf = 128;
2263 sal_Unicode aBuf[nConstBuf];
2264 xub_StrLen nBuf = Max( (xub_StrLen) fChars, (xub_StrLen) (nMinLen+1) );
2265 sal_Unicode* pBuf = (nBuf <= nConstBuf ? aBuf : new sal_Unicode[nBuf]);
2266 for ( xub_StrLen j = 0; j < nBuf; ++j )
2268 pBuf[j] = '0';
2270 sal_Unicode* p = pBuf + nBuf - 1;
2271 *p = 0;
2272 if ( fVal <= (ULONG)(~0) )
2274 ULONG nVal = (ULONG) fVal;
2275 ULONG nBase = (ULONG) fBase;
2276 while ( nVal && p > pBuf )
2278 *--p = pDigits[ nVal % nBase ];
2279 nVal /= nBase;
2281 fVal = (double) nVal;
2283 else
2285 BOOL bDirt = FALSE;
2286 while ( fVal && p > pBuf )
2288 //! mit fmod Rundungsfehler ab 2**48
2289 // double fDig = ::rtl::math::approxFloor( fmod( fVal, fBase ) );
2290 // so ist es etwas besser
2291 double fInt = ::rtl::math::approxFloor( fVal / fBase );
2292 double fMult = fInt * fBase;
2293 #if OSL_DEBUG_LEVEL > 1
2294 // #53943# =BASIS(1e308;36) => GPF mit
2295 // nDig = (size_t) ::rtl::math::approxFloor( fVal - fMult );
2296 // trotz vorheriger Pruefung ob fVal >= fMult
2297 double fDebug1 = fVal - fMult;
2298 // fVal := 7,5975311883090e+290
2299 // fMult := 7,5975311883090e+290
2300 // fDebug1 := 1,3848924157003e+275 <- RoundOff-Error
2301 // fVal != fMult, aber: ::rtl::math::approxEqual( fVal, fMult ) == TRUE
2302 double fDebug2 = ::rtl::math::approxSub( fVal, fMult );
2303 // und ::rtl::math::approxSub( fVal, fMult ) == 0
2304 double fDebug3 = ( fInt ? fVal / fInt : 0.0 );
2305 // Nach dem strange fDebug1 und fVal < fMult ist eigentlich
2306 // fDebug2 == fBase, trotzdem wird das mit einem Vergleich
2307 // nicht erkannt, dann schlaegt bDirt zu und alles wird wieder gut..
2309 // prevent compiler warnings
2310 (void)fDebug1; (void)fDebug2; (void)fDebug3;
2311 #endif
2312 size_t nDig;
2313 if ( fVal < fMult )
2314 { // da ist was gekippt
2315 bDirt = TRUE;
2316 nDig = 0;
2318 else
2320 double fDig = ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal, fMult ) );
2321 if ( bDirt )
2323 bDirt = FALSE;
2324 --fDig;
2326 if ( fDig <= 0.0 )
2327 nDig = 0;
2328 else if ( fDig >= fBase )
2329 nDig = ((size_t) fBase) - 1;
2330 else
2331 nDig = (size_t) fDig;
2333 *--p = pDigits[ nDig ];
2334 fVal = fInt;
2337 if ( fVal )
2338 PushError( errStringOverflow );
2339 else
2341 if ( nBuf - (p - pBuf) <= nMinLen )
2342 p = pBuf + nBuf - 1 - nMinLen;
2343 PushStringBuffer( p );
2345 if ( pBuf != aBuf )
2346 delete [] pBuf;
2348 else
2349 PushIllegalArgument();
2354 void ScInterpreter::ScDecimal()
2355 { // Text, Base
2356 if ( MustHaveParamCount( GetByte(), 2 ) )
2358 double fBase = ::rtl::math::approxFloor( GetDouble() );
2359 String aStr( GetString() );
2360 if ( !nGlobalError && 2 <= fBase && fBase <= 36 )
2362 double fVal = 0.0;
2363 int nBase = (int) fBase;
2364 register const sal_Unicode* p = aStr.GetBuffer();
2365 while ( *p == ' ' || *p == '\t' )
2366 p++; // strip leading white space
2367 if ( nBase == 16 )
2368 { // evtl. hex-prefix strippen
2369 if ( *p == 'x' || *p == 'X' )
2370 p++;
2371 else if ( *p == '0' && (*(p+1) == 'x' || *(p+1) == 'X') )
2372 p += 2;
2374 while ( *p )
2376 int n;
2377 if ( '0' <= *p && *p <= '9' )
2378 n = *p - '0';
2379 else if ( 'A' <= *p && *p <= 'Z' )
2380 n = 10 + (*p - 'A');
2381 else if ( 'a' <= *p && *p <= 'z' )
2382 n = 10 + (*p - 'a');
2383 else
2384 n = nBase;
2385 if ( nBase <= n )
2387 if ( *(p+1) == 0 &&
2388 ( (nBase == 2 && (*p == 'b' || *p == 'B'))
2389 ||(nBase == 16 && (*p == 'h' || *p == 'H')) )
2391 ; // 101b und F00Dh sind ok
2392 else
2394 PushIllegalArgument();
2395 return ;
2398 else
2399 fVal = fVal * fBase + n;
2400 p++;
2403 PushDouble( fVal );
2405 else
2406 PushIllegalArgument();
2411 void ScInterpreter::ScConvert()
2412 { // Value, FromUnit, ToUnit
2413 if ( MustHaveParamCount( GetByte(), 3 ) )
2415 String aToUnit( GetString() );
2416 String aFromUnit( GetString() );
2417 double fVal = GetDouble();
2418 if ( nGlobalError )
2419 PushError( nGlobalError);
2420 else
2421 { // erst die angegebene Reihenfolge suchen, wenn nicht gefunden den Kehrwert
2422 double fConv;
2423 if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aFromUnit, aToUnit ) )
2424 PushDouble( fVal * fConv );
2425 else if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aToUnit, aFromUnit ) )
2426 PushDouble( fVal / fConv );
2427 else
2428 PushNA();
2434 void ScInterpreter::ScRoman()
2435 { // Value [Mode]
2436 BYTE nParamCount = GetByte();
2437 if( MustHaveParamCount( nParamCount, 1, 2 ) )
2439 double fMode = (nParamCount == 2) ? ::rtl::math::approxFloor( GetDouble() ) : 0.0;
2440 double fVal = ::rtl::math::approxFloor( GetDouble() );
2441 if( nGlobalError )
2442 PushError( nGlobalError);
2443 else if( (fMode >= 0.0) && (fMode < 5.0) && (fVal >= 0.0) && (fVal < 4000.0) )
2445 static const sal_Unicode pChars[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
2446 static const USHORT pValues[] = { 1000, 500, 100, 50, 10, 5, 1 };
2447 static const USHORT nMaxIndex = (USHORT)(sizeof(pValues) / sizeof(pValues[0]) - 1);
2449 String aRoman;
2450 USHORT nVal = (USHORT) fVal;
2451 USHORT nMode = (USHORT) fMode;
2453 for( UINT16 i = 0; i <= nMaxIndex / 2; i++ )
2455 USHORT nIndex = 2 * i;
2456 USHORT nDigit = nVal / pValues[ nIndex ];
2458 if( (nDigit % 5) == 4 )
2460 USHORT nIndex2 = (nDigit == 4) ? nIndex - 1 : nIndex - 2;
2461 USHORT nSteps = 0;
2462 while( (nSteps < nMode) && (nIndex < nMaxIndex) )
2464 nSteps++;
2465 if( pValues[ nIndex2 ] - pValues[ nIndex + 1 ] <= nVal )
2466 nIndex++;
2467 else
2468 nSteps = nMode;
2470 aRoman += pChars[ nIndex ];
2471 aRoman += pChars[ nIndex2 ];
2472 nVal = sal::static_int_cast<USHORT>( nVal + pValues[ nIndex ] );
2473 nVal = sal::static_int_cast<USHORT>( nVal - pValues[ nIndex2 ] );
2475 else
2477 if( nDigit > 4 )
2478 aRoman += pChars[ nIndex - 1 ];
2479 aRoman.Expand( aRoman.Len() + (nDigit % 5), pChars[ nIndex ] );
2480 nVal %= pValues[ nIndex ];
2484 PushString( aRoman );
2486 else
2487 PushIllegalArgument();
2492 BOOL lcl_GetArabicValue( sal_Unicode cChar, USHORT& rnValue, BOOL& rbIsDec )
2494 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBase" );
2495 switch( cChar )
2497 case 'M': rnValue = 1000; rbIsDec = TRUE; break;
2498 case 'D': rnValue = 500; rbIsDec = FALSE; break;
2499 case 'C': rnValue = 100; rbIsDec = TRUE; break;
2500 case 'L': rnValue = 50; rbIsDec = FALSE; break;
2501 case 'X': rnValue = 10; rbIsDec = TRUE; break;
2502 case 'V': rnValue = 5; rbIsDec = FALSE; break;
2503 case 'I': rnValue = 1; rbIsDec = TRUE; break;
2504 default: return FALSE;
2506 return TRUE;
2510 void ScInterpreter::ScArabic()
2512 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArabic" );
2513 String aRoman( GetString() );
2514 if( nGlobalError )
2515 PushError( nGlobalError);
2516 else
2518 aRoman.ToUpperAscii();
2520 USHORT nValue = 0;
2521 USHORT nValidRest = 3999;
2522 USHORT nCharIndex = 0;
2523 USHORT nCharCount = aRoman.Len();
2524 BOOL bValid = TRUE;
2526 while( bValid && (nCharIndex < nCharCount) )
2528 USHORT nDigit1 = 0;
2529 USHORT nDigit2 = 0;
2530 BOOL bIsDec1 = FALSE;
2531 BOOL bIsDec2 = FALSE;
2532 bValid = lcl_GetArabicValue( aRoman.GetChar( nCharIndex ), nDigit1, bIsDec1 );
2533 if( bValid && (nCharIndex + 1 < nCharCount) )
2534 bValid = lcl_GetArabicValue( aRoman.GetChar( nCharIndex + 1 ), nDigit2, bIsDec2 );
2535 if( bValid )
2537 if( nDigit1 >= nDigit2 )
2539 nValue = sal::static_int_cast<USHORT>( nValue + nDigit1 );
2540 nValidRest %= (nDigit1 * (bIsDec1 ? 5 : 2));
2541 bValid = (nValidRest >= nDigit1);
2542 if( bValid )
2543 nValidRest = sal::static_int_cast<USHORT>( nValidRest - nDigit1 );
2544 nCharIndex++;
2546 else if( nDigit1 * 2 != nDigit2 )
2548 USHORT nDiff = nDigit2 - nDigit1;
2549 nValue = sal::static_int_cast<USHORT>( nValue + nDiff );
2550 bValid = (nValidRest >= nDiff);
2551 if( bValid )
2552 nValidRest = nDigit1 - 1;
2553 nCharIndex += 2;
2555 else
2556 bValid = FALSE;
2559 if( bValid )
2560 PushInt( nValue );
2561 else
2562 PushIllegalArgument();
2567 void ScInterpreter::ScHyperLink()
2569 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHyperLink" );
2570 BYTE nParamCount = GetByte();
2571 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
2573 double fVal = 0.0;
2574 String aStr;
2575 ScMatValType nResultType = SC_MATVAL_STRING;
2577 if ( nParamCount == 2 )
2579 switch ( GetStackType() )
2581 case svDouble:
2582 fVal = GetDouble();
2583 nResultType = SC_MATVAL_VALUE;
2584 break;
2585 case svString:
2586 aStr = GetString();
2587 break;
2588 case svSingleRef:
2589 case svDoubleRef:
2591 ScAddress aAdr;
2592 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2593 break;
2594 ScBaseCell* pCell = GetCell( aAdr );
2595 if (HasCellEmptyData( pCell))
2596 nResultType = SC_MATVAL_EMPTY;
2597 else
2599 USHORT nErr = GetCellErrCode( pCell );
2600 if (nErr)
2601 SetError( nErr);
2602 else if (HasCellValueData( pCell))
2604 fVal = GetCellValue( aAdr, pCell );
2605 nResultType = SC_MATVAL_VALUE;
2607 else
2608 GetCellString( aStr, pCell );
2611 break;
2612 case svMatrix:
2613 nResultType = GetDoubleOrStringFromMatrix( fVal, aStr);
2614 break;
2615 case svMissing:
2616 case svEmptyCell:
2617 Pop();
2618 // mimic xcl
2619 fVal = 0.0;
2620 nResultType = SC_MATVAL_VALUE;
2621 break;
2622 default:
2623 PopError();
2624 SetError( errIllegalArgument);
2627 String aUrl = GetString();
2628 ScMatrixRef pResMat = GetNewMat( 1, 2);
2629 if (nGlobalError)
2631 fVal = CreateDoubleError( nGlobalError);
2632 nResultType = SC_MATVAL_VALUE;
2634 if (nParamCount == 2 || nGlobalError)
2636 if (ScMatrix::IsValueType( nResultType))
2637 pResMat->PutDouble( fVal, 0);
2638 else if (ScMatrix::IsRealStringType( nResultType))
2639 pResMat->PutString( aStr, 0);
2640 else // EmptyType, EmptyPathType, mimic xcl
2641 pResMat->PutDouble( 0.0, 0 );
2643 else
2644 pResMat->PutString( aUrl, 0 );
2645 pResMat->PutString( aUrl, 1 );
2646 bMatrixFormula = true;
2647 PushMatrix(pResMat);
2652 BOOL lclConvertMoney( const String& aSearchUnit, double& rfRate, int& rnDec )
2654 struct ConvertInfo
2656 const sal_Char* pCurrText;
2657 double fRate;
2658 int nDec;
2660 ConvertInfo aConvertTable[] = {
2661 { "EUR", 1.0, 2 },
2662 { "ATS", 13.7603, 2 },
2663 { "BEF", 40.3399, 0 },
2664 { "DEM", 1.95583, 2 },
2665 { "ESP", 166.386, 0 },
2666 { "FIM", 5.94573, 2 },
2667 { "FRF", 6.55957, 2 },
2668 { "IEP", 0.787564, 2 },
2669 { "ITL", 1936.27, 0 },
2670 { "LUF", 40.3399, 0 },
2671 { "NLG", 2.20371, 2 },
2672 { "PTE", 200.482, 2 },
2673 { "GRD", 340.750, 2 },
2674 { "SIT", 239.640, 2 },
2675 { "MTL", 0.429300, 2 },
2676 { "CYP", 0.585274, 2 },
2677 { "SKK", 30.1260, 2 }
2680 const size_t nConversionCount = sizeof( aConvertTable ) / sizeof( aConvertTable[0] );
2681 for ( size_t i = 0; i < nConversionCount; i++ )
2682 if ( aSearchUnit.EqualsIgnoreCaseAscii( aConvertTable[i].pCurrText ) )
2684 rfRate = aConvertTable[i].fRate;
2685 rnDec = aConvertTable[i].nDec;
2686 return TRUE;
2688 return FALSE;
2691 void ScInterpreter::ScEuroConvert()
2692 { //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]]
2693 BYTE nParamCount = GetByte();
2694 if ( MustHaveParamCount( nParamCount, 3, 5 ) )
2696 double nPrecision = 0.0;
2697 if ( nParamCount == 5 )
2699 nPrecision = ::rtl::math::approxFloor(GetDouble());
2700 if ( nPrecision < 3 )
2702 PushIllegalArgument();
2703 return;
2706 BOOL bFullPrecision = FALSE;
2707 if ( nParamCount >= 4 )
2708 bFullPrecision = GetBool();
2709 String aToUnit( GetString() );
2710 String aFromUnit( GetString() );
2711 double fVal = GetDouble();
2712 if ( nGlobalError )
2713 PushError( nGlobalError);
2714 else
2716 double fRes;
2717 double fFromRate;
2718 double fToRate;
2719 int nFromDec;
2720 int nToDec;
2721 String aEur( RTL_CONSTASCII_USTRINGPARAM("EUR"));
2722 if ( lclConvertMoney( aFromUnit, fFromRate, nFromDec )
2723 && lclConvertMoney( aToUnit, fToRate, nToDec ) )
2725 if ( aFromUnit.EqualsIgnoreCaseAscii( aToUnit ) )
2726 fRes = fVal;
2727 else
2729 if ( aFromUnit.EqualsIgnoreCaseAscii( aEur ) )
2730 fRes = fVal * fToRate;
2731 else
2733 double fIntermediate = fVal / fFromRate;
2734 if ( nPrecision )
2735 fIntermediate = ::rtl::math::round( fIntermediate,
2736 (int) nPrecision );
2737 fRes = fIntermediate * fToRate;
2739 if ( !bFullPrecision )
2740 fRes = ::rtl::math::round( fRes, nToDec );
2742 PushDouble( fRes );
2744 else
2745 PushIllegalArgument();
2751 // BAHTTEXT ===================================================================
2753 #define UTF8_TH_0 "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214"
2754 #define UTF8_TH_1 "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207"
2755 #define UTF8_TH_2 "\340\270\252\340\270\255\340\270\207"
2756 #define UTF8_TH_3 "\340\270\252\340\270\262\340\270\241"
2757 #define UTF8_TH_4 "\340\270\252\340\270\265\340\271\210"
2758 #define UTF8_TH_5 "\340\270\253\340\271\211\340\270\262"
2759 #define UTF8_TH_6 "\340\270\253\340\270\201"
2760 #define UTF8_TH_7 "\340\271\200\340\270\210\340\271\207\340\270\224"
2761 #define UTF8_TH_8 "\340\271\201\340\270\233\340\270\224"
2762 #define UTF8_TH_9 "\340\271\200\340\270\201\340\271\211\340\270\262"
2763 #define UTF8_TH_10 "\340\270\252\340\270\264\340\270\232"
2764 #define UTF8_TH_11 "\340\271\200\340\270\255\340\271\207\340\270\224"
2765 #define UTF8_TH_20 "\340\270\242\340\270\265\340\271\210"
2766 #define UTF8_TH_1E2 "\340\270\243\340\271\211\340\270\255\340\270\242"
2767 #define UTF8_TH_1E3 "\340\270\236\340\270\261\340\270\231"
2768 #define UTF8_TH_1E4 "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231"
2769 #define UTF8_TH_1E5 "\340\271\201\340\270\252\340\270\231"
2770 #define UTF8_TH_1E6 "\340\270\245\340\271\211\340\270\262\340\270\231"
2771 #define UTF8_TH_DOT0 "\340\270\226\340\271\211\340\270\247\340\270\231"
2772 #define UTF8_TH_BAHT "\340\270\232\340\270\262\340\270\227"
2773 #define UTF8_TH_SATANG "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214"
2774 #define UTF8_TH_MINUS "\340\270\245\340\270\232"
2776 #define UTF8_STRINGPARAM( ascii ) ascii, static_cast< xub_StrLen >( sizeof( ascii ) - 1 )
2777 #define UTF8_CREATE( ascii ) ByteString( UTF8_STRINGPARAM( ascii ) )
2778 #define UTF8_APPEND( ascii ) Append( UTF8_STRINGPARAM( ascii ) )
2779 #define UTF8_PREPEND( ascii ) Insert( UTF8_CREATE( ascii ), 0 )
2781 // local functions ------------------------------------------------------------
2783 namespace {
2785 inline void lclSplitBlock( double& rfInt, sal_Int32& rnBlock, double fValue, double fSize )
2787 rnBlock = static_cast< sal_Int32 >( modf( (fValue + 0.1) / fSize, &rfInt ) * fSize + 0.1 );
2790 /** Appends a digit (0 to 9) to the passed string. */
2791 void lclAppendDigit( ByteString& rText, sal_Int32 nDigit )
2793 switch( nDigit )
2795 case 0: rText.UTF8_APPEND( UTF8_TH_0 ); break;
2796 case 1: rText.UTF8_APPEND( UTF8_TH_1 ); break;
2797 case 2: rText.UTF8_APPEND( UTF8_TH_2 ); break;
2798 case 3: rText.UTF8_APPEND( UTF8_TH_3 ); break;
2799 case 4: rText.UTF8_APPEND( UTF8_TH_4 ); break;
2800 case 5: rText.UTF8_APPEND( UTF8_TH_5 ); break;
2801 case 6: rText.UTF8_APPEND( UTF8_TH_6 ); break;
2802 case 7: rText.UTF8_APPEND( UTF8_TH_7 ); break;
2803 case 8: rText.UTF8_APPEND( UTF8_TH_8 ); break;
2804 case 9: rText.UTF8_APPEND( UTF8_TH_9 ); break;
2805 default: DBG_ERRORFILE( "lclAppendDigit - illegal digit" );
2809 /** Appends a value raised to a power of 10: nDigit*10^nPow10.
2810 @param nDigit A digit in the range from 1 to 9.
2811 @param nPow10 A value in the range from 2 to 5.
2813 void lclAppendPow10( ByteString& rText, sal_Int32 nDigit, sal_Int32 nPow10 )
2815 DBG_ASSERT( (1 <= nDigit) && (nDigit <= 9), "lclAppendPow10 - illegal digit" );
2816 lclAppendDigit( rText, nDigit );
2817 switch( nPow10 )
2819 case 2: rText.UTF8_APPEND( UTF8_TH_1E2 ); break;
2820 case 3: rText.UTF8_APPEND( UTF8_TH_1E3 ); break;
2821 case 4: rText.UTF8_APPEND( UTF8_TH_1E4 ); break;
2822 case 5: rText.UTF8_APPEND( UTF8_TH_1E5 ); break;
2823 default: DBG_ERRORFILE( "lclAppendPow10 - illegal power" );
2827 /** Appends a block of 6 digits (value from 1 to 999,999) to the passed string. */
2828 void lclAppendBlock( ByteString& rText, sal_Int32 nValue )
2830 DBG_ASSERT( (1 <= nValue) && (nValue <= 999999), "lclAppendBlock - illegal value" );
2831 if( nValue >= 100000 )
2833 lclAppendPow10( rText, nValue / 100000, 5 );
2834 nValue %= 100000;
2836 if( nValue >= 10000 )
2838 lclAppendPow10( rText, nValue / 10000, 4 );
2839 nValue %= 10000;
2841 if( nValue >= 1000 )
2843 lclAppendPow10( rText, nValue / 1000, 3 );
2844 nValue %= 1000;
2846 if( nValue >= 100 )
2848 lclAppendPow10( rText, nValue / 100, 2 );
2849 nValue %= 100;
2851 if( nValue > 0 )
2853 sal_Int32 nTen = nValue / 10;
2854 sal_Int32 nOne = nValue % 10;
2855 if( nTen >= 1 )
2857 if( nTen >= 3 )
2858 lclAppendDigit( rText, nTen );
2859 else if( nTen == 2 )
2860 rText.UTF8_APPEND( UTF8_TH_20 );
2861 rText.UTF8_APPEND( UTF8_TH_10 );
2863 if( (nTen > 0) && (nOne == 1) )
2864 rText.UTF8_APPEND( UTF8_TH_11 );
2865 else if( nOne > 0 )
2866 lclAppendDigit( rText, nOne );
2870 } // namespace
2872 // ----------------------------------------------------------------------------
2874 void ScInterpreter::ScBahtText()
2876 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBahtText" );
2877 BYTE nParamCount = GetByte();
2878 if ( MustHaveParamCount( nParamCount, 1 ) )
2880 double fValue = GetDouble();
2881 if( nGlobalError )
2883 PushError( nGlobalError);
2884 return;
2887 // sign
2888 bool bMinus = fValue < 0.0;
2889 fValue = fabs( fValue );
2891 // round to 2 digits after decimal point, fValue contains Satang as integer
2892 fValue = ::rtl::math::approxFloor( fValue * 100.0 + 0.5 );
2894 // split Baht and Satang
2895 double fBaht = 0.0;
2896 sal_Int32 nSatang = 0;
2897 lclSplitBlock( fBaht, nSatang, fValue, 100.0 );
2899 ByteString aText;
2901 // generate text for Baht value
2902 if( fBaht == 0.0 )
2904 if( nSatang == 0 )
2905 aText.UTF8_APPEND( UTF8_TH_0 );
2907 else while( fBaht > 0.0 )
2909 ByteString aBlock;
2910 sal_Int32 nBlock = 0;
2911 lclSplitBlock( fBaht, nBlock, fBaht, 1.0e6 );
2912 if( nBlock > 0 )
2913 lclAppendBlock( aBlock, nBlock );
2914 // add leading "million", if there will come more blocks
2915 if( fBaht > 0.0 )
2916 aBlock.UTF8_PREPEND( UTF8_TH_1E6 );
2917 aText.Insert( aBlock, 0 );
2919 if( aText.Len() > 0 )
2920 aText.UTF8_APPEND( UTF8_TH_BAHT );
2922 // generate text for Satang value
2923 if( nSatang == 0 )
2925 aText.UTF8_APPEND( UTF8_TH_DOT0 );
2927 else
2929 lclAppendBlock( aText, nSatang );
2930 aText.UTF8_APPEND( UTF8_TH_SATANG );
2933 // add the minus sign
2934 if( bMinus )
2935 aText.UTF8_PREPEND( UTF8_TH_MINUS );
2937 PushString( String( aText, RTL_TEXTENCODING_UTF8 ) );
2941 // ============================================================================
2943 void ScInterpreter::ScGetPivotData()
2945 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetPivotData" );
2946 BYTE nParamCount = GetByte();
2948 if ( MustHaveParamCount( nParamCount, 2, 30 ) )
2950 // there must be an even number of args
2951 // target, ref, then field/item pairs
2952 if( (nParamCount % 2) == 1)
2953 goto failed;
2955 bool bOldSyntax = false;
2956 if ( nParamCount == 2 )
2958 // if the first parameter is a ref, assume old syntax
2959 StackVar eFirstType = GetStackType( 2 );
2960 if ( eFirstType == svSingleRef || eFirstType == svDoubleRef )
2961 bOldSyntax = true;
2964 ScDPGetPivotDataField aTarget; // target field, and returns result
2965 std::vector< ScDPGetPivotDataField > aFilters;
2966 String aFilterList;
2967 if ( bOldSyntax )
2968 aFilterList = GetString(); // old syntax: second parameter is list of constraints
2969 else
2971 // new syntax: separate name/value pairs
2973 USHORT nFilterCount = nParamCount / 2 - 1;
2974 aFilters.resize( nFilterCount );
2976 USHORT i = nFilterCount;
2977 while( i-- > 0 )
2979 //! should allow numeric constraint values
2980 aFilters[i].mbValIsStr = TRUE;
2981 aFilters[i].maValStr = GetString();
2983 aFilters[i].maFieldName = GetString();
2987 // common to both syntaxes: a reference to the data pilot table
2989 ScRange aBlock;
2990 switch ( GetStackType() )
2992 case svDoubleRef :
2993 PopDoubleRef( aBlock );
2994 break;
2996 case svSingleRef :
2998 ScAddress aAddr;
2999 PopSingleRef( aAddr );
3000 aBlock = aAddr;
3001 break;
3003 default:
3004 goto failed;
3006 // NOTE : MS Excel docs claim to use the 'most recent' which is not
3007 // exactly the same as what we do in ScDocument::GetDPAtBlock
3008 // However we do need to use GetDPABlock
3009 ScDPObject* pDPObj = pDok->GetDPAtBlock ( aBlock );
3010 if( NULL == pDPObj)
3011 goto failed;
3013 if ( bOldSyntax )
3015 // fill aFilters / aTarget from aFilterList string
3016 if ( !pDPObj->ParseFilters( aTarget, aFilters, aFilterList ) )
3017 goto failed;
3019 else
3020 aTarget.maFieldName = GetString(); // new syntax: first parameter is data field name
3022 if( pDPObj->GetPivotData( aTarget, aFilters ) )
3024 if( aTarget.mbValIsStr )
3025 PushString( aTarget.maValStr );
3026 else
3027 PushDouble( aTarget.mnValNum );
3028 return;
3032 failed :
3033 PushError( errNoRef );