1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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"
46 #include "ddelink.hxx"
47 #include "scmatrix.hxx"
48 #include "compiler.hxx"
50 #include "document.hxx"
51 #include "dociter.hxx"
52 #include "docoptio.hxx"
53 #include "unitconv.hxx"
54 #include "globstr.hrc"
56 #include "dpobject.hxx"
62 using namespace formula
;
63 // STATIC DATA -----------------------------------------------------------
65 #define D_TIMEFACTOR 86400.0
66 #define SCdEpsilon 1.0E-7
68 //-----------------------------------------------------------------------------
70 //-----------------------------------------------------------------------------
72 double ScInterpreter::GetDate(INT16 nYear
, INT16 nMonth
, INT16 nDay
)
74 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetDate" );
76 nYear
= pFormatter
->ExpandTwoDigitYear( nYear
);
80 nY
= nYear
+ (nMonth
-1) / 12;
81 nM
= ((nMonth
-1) % 12) + 1;
85 nY
= nYear
+ (nMonth
-12) / 12;
86 nM
= 12 - (-nMonth
) % 12;
88 Date
aDate(1, nM
, nY
);
91 return (double) (aDate
- *(pFormatter
->GetNullDate()));
99 //-----------------------------------------------------------------------------
101 //-----------------------------------------------------------------------------
103 void ScInterpreter::ScGetActDate()
105 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetActDate" );
106 nFuncFmtType
= NUMBERFORMAT_DATE
;
108 long nDiff
= aActDate
- *(pFormatter
->GetNullDate());
109 PushDouble((double) nDiff
);
112 void ScInterpreter::ScGetActTime()
114 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetActTime" );
115 nFuncFmtType
= NUMBERFORMAT_DATETIME
;
117 long nDiff
= aActDate
- *(pFormatter
->GetNullDate());
119 double nTime
= ((double)aActTime
.Get100Sec() / 100 +
120 (double)(aActTime
.GetSec() +
121 (aActTime
.GetMin() * 60) +
122 (aActTime
.GetHour() * 3600))) / D_TIMEFACTOR
;
123 PushDouble( (double) nDiff
+ nTime
);
126 void ScInterpreter::ScGetYear()
128 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetYear" );
129 Date aDate
= *(pFormatter
->GetNullDate());
130 aDate
+= (long) ::rtl::math::approxFloor(GetDouble());
131 PushDouble( (double) aDate
.GetYear() );
134 void ScInterpreter::ScGetMonth()
136 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetMonth" );
137 Date aDate
= *(pFormatter
->GetNullDate());
138 aDate
+= (long) ::rtl::math::approxFloor(GetDouble());
139 PushDouble( (double) aDate
.GetMonth() );
142 void ScInterpreter::ScGetDay()
144 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetDay" );
145 Date aDate
= *(pFormatter
->GetNullDate());
146 aDate
+= (long)::rtl::math::approxFloor(GetDouble());
147 PushDouble((double) aDate
.GetDay());
150 void ScInterpreter::ScGetMin()
152 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetMin" );
153 double fTime
= GetDouble();
154 fTime
-= ::rtl::math::approxFloor(fTime
); // Datumsanteil weg
155 long nVal
= (long)::rtl::math::approxFloor(fTime
*D_TIMEFACTOR
+0.5) % 3600;
156 PushDouble( (double) (nVal
/60) );
159 void ScInterpreter::ScGetSec()
161 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetSec" );
162 double fTime
= GetDouble();
163 fTime
-= ::rtl::math::approxFloor(fTime
); // Datumsanteil weg
164 long nVal
= (long)::rtl::math::approxFloor(fTime
*D_TIMEFACTOR
+0.5) % 60;
165 PushDouble( (double) nVal
);
168 void ScInterpreter::ScGetHour()
170 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetHour" );
171 double fTime
= GetDouble();
172 fTime
-= ::rtl::math::approxFloor(fTime
); // Datumsanteil weg
173 long nVal
= (long)::rtl::math::approxFloor(fTime
*D_TIMEFACTOR
+0.5) / 3600;
174 PushDouble((double) nVal
);
177 void ScInterpreter::ScGetDateValue()
179 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetDateValue" );
180 String aInputString
= GetString();
181 sal_uInt32 nFIndex
= 0; // damit default Land/Spr.
183 if (pFormatter
->IsNumberFormat(aInputString
, nFIndex
, fVal
))
185 short eType
= pFormatter
->GetType(nFIndex
);
186 if (eType
== NUMBERFORMAT_DATE
|| eType
== NUMBERFORMAT_DATETIME
)
187 PushDouble(::rtl::math::approxFloor(fVal
));
189 PushIllegalArgument();
192 PushIllegalArgument();
195 void ScInterpreter::ScGetDayOfWeek()
197 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetDayOfWeek" );
198 BYTE nParamCount
= GetByte();
199 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
202 if (nParamCount
== 2)
203 nFlag
= (short) ::rtl::math::approxFloor(GetDouble());
207 Date aDate
= *(pFormatter
->GetNullDate());
208 aDate
+= (long)::rtl::math::approxFloor(GetDouble());
209 int nVal
= (int) aDate
.GetDayOfWeek();
223 void ScInterpreter::ScGetWeekOfYear()
225 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetWeekOfYear" );
226 if ( MustHaveParamCount( GetByte(), 2 ) )
228 short nFlag
= (short) ::rtl::math::approxFloor(GetDouble());
230 Date aDate
= *(pFormatter
->GetNullDate());
231 aDate
+= (long)::rtl::math::approxFloor(GetDouble());
232 PushInt( (int) aDate
.GetWeekOfYear( nFlag
== 1 ? SUNDAY
: MONDAY
));
236 void ScInterpreter::ScEasterSunday()
238 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScEasterSunday" );
239 nFuncFmtType
= NUMBERFORMAT_DATE
;
240 if ( MustHaveParamCount( GetByte(), 1 ) )
242 INT16 nDay
, nMonth
, nYear
;
243 nYear
= (INT16
) ::rtl::math::approxFloor( GetDouble() );
245 nYear
= pFormatter
->ExpandTwoDigitYear( nYear
);
246 // don't worry, be happy :)
247 int B
,C
,D
,E
,F
,G
,H
,I
,K
,L
,M
,N
,O
;
249 B
= int(nYear
/ 100);
253 F
= int((B
+ 8) / 25);
254 G
= int((B
- F
+ 1) / 3);
255 H
= (19 * N
+ B
- D
- G
+ 15) % 30;
258 L
= (32 + 2 * E
+ 2 * I
- H
- K
) % 7;
259 M
= int((N
+ 11 * H
+ 22 * L
) / 451);
260 O
= H
+ L
- 7 * M
+ 114;
261 nDay
= sal::static_int_cast
<INT16
>( O
% 31 + 1 );
262 nMonth
= sal::static_int_cast
<INT16
>( int(O
/ 31) );
263 PushDouble( GetDate( nYear
, nMonth
, nDay
) );
267 void ScInterpreter::ScGetDate()
269 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetDate" );
270 nFuncFmtType
= NUMBERFORMAT_DATE
;
271 if ( MustHaveParamCount( GetByte(), 3 ) )
273 INT16 nDay
= (INT16
) ::rtl::math::approxFloor(GetDouble());
274 INT16 nMonth
= (INT16
) ::rtl::math::approxFloor(GetDouble());
275 INT16 nYear
= (INT16
) ::rtl::math::approxFloor(GetDouble());
277 PushIllegalArgument();
280 PushDouble(GetDate(nYear
, nMonth
, nDay
));
285 void ScInterpreter::ScGetTime()
287 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetTime" );
288 nFuncFmtType
= NUMBERFORMAT_TIME
;
289 if ( MustHaveParamCount( GetByte(), 3 ) )
291 double nSec
= GetDouble();
292 double nMin
= GetDouble();
293 double nHour
= GetDouble();
294 PushDouble( ( (nHour
* 3600) + (nMin
* 60) + nSec
) / D_TIMEFACTOR
);
298 void ScInterpreter::ScGetDiffDate()
300 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetDiffDate" );
301 if ( MustHaveParamCount( GetByte(), 2 ) )
303 double nDate2
= GetDouble();
304 double nDate1
= GetDouble();
305 PushDouble(nDate1
- nDate2
);
309 void ScInterpreter::ScGetDiffDate360()
311 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetDiffDate360" );
312 /* Implementation follows
313 * http://www.bondmarkets.com/eCommerce/SMD_Fields_030802.pdf
314 * Appendix B: Day-Count Bases, there are 7 different ways to calculate the
315 * 30-days count. That document also claims that Excel implements the "PSA
316 * 30" or "NASD 30" method (funny enough they also state that Excel is the
317 * only tool that does so).
319 * Note that the definiton given in
320 * http://msdn.microsoft.com/library/en-us/office97/html/SEB7C.asp
321 * is _not_ the way how it is actually calculated by Excel (that would not
322 * even match any of the 7 methods mentioned above) and would result in the
323 * following test cases producing wrong results according to that appendix B:
325 * 28-Feb-95 31-Aug-95 181 instead of 180
326 * 29-Feb-96 31-Aug-96 181 instead of 180
327 * 30-Jan-96 31-Mar-96 61 instead of 60
328 * 31-Jan-96 31-Mar-96 61 instead of 60
330 * Still, there is a difference between OOoCalc and Excel:
332 * 02-Feb-99 31-Mar-00 results in 419
333 * 31-Mar-00 02-Feb-99 results in -418
334 * In Calc the result is 419 respectively -419. I consider the -418 a bug in Excel.
337 BYTE nParamCount
= GetByte();
338 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
341 if (nParamCount
== 3)
345 double nDate2
= GetDouble();
346 double nDate1
= GetDouble();
349 PushError( nGlobalError
);
352 // #i84934# only for non-US European algorithm swap dates. Else
353 // follow Excel's meaningless extrapolation for "interoperability".
354 if (bFlag
&& (nDate2
< nDate1
))
363 Date aDate1
= *(pFormatter
->GetNullDate());
364 aDate1
+= (long) ::rtl::math::approxFloor(nDate1
);
365 Date aDate2
= *(pFormatter
->GetNullDate());
366 aDate2
+= (long) ::rtl::math::approxFloor(nDate2
);
367 if (aDate1
.GetDay() == 31)
371 if (aDate1
.GetMonth() == 2)
373 switch ( aDate1
.GetDay() )
376 if ( !aDate1
.IsLeapYear() )
385 if (aDate2
.GetDay() == 31)
389 if (aDate1
.GetDay() == 30)
395 PushDouble( fSign
* (double)
396 ( (double) aDate2
.GetDay() + (double) aDate2
.GetMonth() * 30.0 +
397 (double) aDate2
.GetYear() * 360.0
398 - (double) aDate1
.GetDay() - (double) aDate1
.GetMonth() * 30.0
399 - (double)aDate1
.GetYear() * 360.0) );
404 void ScInterpreter::ScGetTimeValue()
406 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetTimeValue" );
407 String aInputString
= GetString();
408 sal_uInt32 nFIndex
= 0; // damit default Land/Spr.
410 if (pFormatter
->IsNumberFormat(aInputString
, nFIndex
, fVal
))
412 short eType
= pFormatter
->GetType(nFIndex
);
413 if (eType
== NUMBERFORMAT_TIME
|| eType
== NUMBERFORMAT_DATETIME
)
415 double fDateVal
= rtl::math::approxFloor(fVal
);
416 double fTimeVal
= fVal
- fDateVal
;
417 PushDouble(fTimeVal
);
420 PushIllegalArgument();
423 PushIllegalArgument();
426 void ScInterpreter::ScPlusMinus()
428 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPlusMinus" );
429 double nVal
= GetDouble();
438 void ScInterpreter::ScAbs()
440 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAbs" );
441 PushDouble(fabs(GetDouble()));
444 void ScInterpreter::ScInt()
446 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScInt" );
447 PushDouble(::rtl::math::approxFloor(GetDouble()));
451 void ScInterpreter::RoundNumber( rtl_math_RoundingMode eMode
)
453 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::RoundNumber" );
454 BYTE nParamCount
= GetByte();
455 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
458 if (nParamCount
== 1)
459 fVal
= ::rtl::math::round( GetDouble(), 0, eMode
);
462 INT32 nDec
= (INT32
) ::rtl::math::approxFloor(GetDouble());
463 if( nDec
< -20 || nDec
> 20 )
464 PushIllegalArgument();
466 fVal
= ::rtl::math::round( GetDouble(), (short)nDec
, eMode
);
472 void ScInterpreter::ScRound()
474 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRound" );
475 RoundNumber( rtl_math_RoundingMode_Corrected
);
478 void ScInterpreter::ScRoundDown()
480 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRoundDown" );
481 RoundNumber( rtl_math_RoundingMode_Down
);
484 void ScInterpreter::ScRoundUp()
486 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRoundUp" );
487 RoundNumber( rtl_math_RoundingMode_Up
);
490 void ScInterpreter::ScCeil()
492 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCeil" );
493 BYTE nParamCount
= GetByte();
494 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
496 BOOL bAbs
= ( nParamCount
== 3 ? GetBool() : FALSE
);
497 double fDec
= GetDouble();
498 double fVal
= GetDouble();
501 else if (fVal
*fDec
< 0.0)
502 PushIllegalArgument();
505 if ( !bAbs
&& fVal
< 0.0 )
506 PushDouble(::rtl::math::approxFloor(fVal
/fDec
) * fDec
);
508 PushDouble(::rtl::math::approxCeil(fVal
/fDec
) * fDec
);
513 void ScInterpreter::ScFloor()
515 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFloor" );
516 BYTE nParamCount
= GetByte();
517 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
519 BOOL bAbs
= ( nParamCount
== 3 ? GetBool() : FALSE
);
520 double fDec
= GetDouble();
521 double fVal
= GetDouble();
524 else if (fVal
*fDec
< 0.0)
525 PushIllegalArgument();
528 if ( !bAbs
&& fVal
< 0.0 )
529 PushDouble(::rtl::math::approxCeil(fVal
/fDec
) * fDec
);
531 PushDouble(::rtl::math::approxFloor(fVal
/fDec
) * fDec
);
536 void ScInterpreter::ScEven()
538 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScEven" );
539 double fVal
= GetDouble();
541 PushDouble(::rtl::math::approxFloor(fVal
/2.0) * 2.0);
543 PushDouble(::rtl::math::approxCeil(fVal
/2.0) * 2.0);
546 void ScInterpreter::ScOdd()
548 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScOdd" );
549 double fVal
= GetDouble();
552 fVal
= ::rtl::math::approxCeil(fVal
);
553 if (fmod(fVal
, 2.0) == 0.0)
558 fVal
= ::rtl::math::approxFloor(fVal
);
559 if (fmod(fVal
, 2.0) == 0.0)
565 void ScInterpreter::ScArcTan2()
567 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcTan2" );
568 if ( MustHaveParamCount( GetByte(), 2 ) )
570 double nVal2
= GetDouble();
571 double nVal1
= GetDouble();
572 PushDouble(atan2(nVal2
, nVal1
));
576 void ScInterpreter::ScLog()
578 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLog" );
579 BYTE nParamCount
= GetByte();
580 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
583 if (nParamCount
== 2)
587 double nVal
= GetDouble();
588 if (nVal
> 0.0 && nBase
> 0.0 && nBase
!= 1.0)
589 PushDouble(log(nVal
) / log(nBase
));
591 PushIllegalArgument();
595 void ScInterpreter::ScLn()
597 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLn" );
598 double fVal
= GetDouble();
600 PushDouble(log(fVal
));
602 PushIllegalArgument();
605 void ScInterpreter::ScLog10()
607 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLog10" );
608 double fVal
= GetDouble();
610 PushDouble(log10(fVal
));
612 PushIllegalArgument();
615 void ScInterpreter::ScNPV()
617 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNPV" );
618 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
619 short nParamCount
= GetByte();
620 if ( MustHaveParamCount( nParamCount
, 2, 31 ) )
623 // Wir drehen den Stack um!!
624 FormulaToken
* pTemp
[ 31 ];
625 for( short i
= 0; i
< nParamCount
; i
++ )
626 pTemp
[ i
] = pStack
[ sp
- i
- 1 ];
627 memcpy( &pStack
[ sp
- nParamCount
], pTemp
, nParamCount
* sizeof( FormulaToken
* ) );
628 if (nGlobalError
== 0)
631 double nZins
= GetDouble();
633 size_t nRefInList
= 0;
635 while (nParamCount
-- > 0)
637 switch (GetStackType())
641 nVal
+= (GetDouble() / pow(1.0 + nZins
, (double)nCount
));
647 nVal
+= (GetDouble() / pow(1.0 + nZins
, (double)nCount
));
656 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
657 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
658 if (aValIter
.GetFirst(nCellVal
, nErr
))
660 nVal
+= (nCellVal
/ pow(1.0 + nZins
, (double)nCount
));
662 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
664 nVal
+= (nCellVal
/ pow(1.0 + nZins
, (double)nCount
));
671 default : SetError(errIllegalParameter
); break;
679 #if defined(WIN) && defined(MSC)
680 #pragma optimize("",off)
683 void ScInterpreter::ScIRR()
685 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIRR" );
687 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
688 BYTE nParamCount
= GetByte();
689 if ( !MustHaveParamCount( nParamCount
, 1, 2 ) )
691 if (nParamCount
== 2)
692 fSchaetzwert
= GetDouble();
695 USHORT sPos
= sp
; // Stack-Position merken
697 double x
, xNeu
, fWert
, fZaehler
, fNenner
, nCount
;
698 if (fSchaetzwert
== -1.0)
699 x
= 0.1; // default gegen Nulldivisionen
701 x
= fSchaetzwert
; // Startwert
702 switch (GetStackType())
708 PushIllegalParameter();
712 const USHORT nIterationsMax
= 20;
715 while (fEps
> SCdEpsilon
&& nItCount
< nIterationsMax
)
716 { // Newton-Verfahren:
717 sp
= sPos
; // Stack zuruecksetzen
722 PopDoubleRef( aRange
);
723 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
724 if (aValIter
.GetFirst(fWert
, nErr
))
726 fZaehler
+= fWert
/ pow(1.0+x
,(double)nCount
);
727 fNenner
+= -nCount
* fWert
/ pow(1.0+x
,nCount
+1.0);
729 while ((nErr
== 0) && aValIter
.GetNext(fWert
, nErr
))
731 fZaehler
+= fWert
/ pow(1.0+x
,(double)nCount
);
732 fNenner
+= -nCount
* fWert
/ pow(1.0+x
,nCount
+1.0);
737 xNeu
= x
- fZaehler
/ fNenner
; // x(i+1) = x(i)-f(x(i))/f'(x(i))
739 fEps
= fabs(xNeu
- x
);
742 if (fSchaetzwert
== 0.0 && fabs(x
) < SCdEpsilon
)
743 x
= 0.0; // auf Null normieren
744 if (fEps
< SCdEpsilon
)
747 PushError( errNoConvergence
);
749 #if defined(WIN) && defined(MSC)
750 #pragma optimize("",on)
754 void ScInterpreter::ScMIRR()
755 { // range_of_values ; rate_invest ; rate_reinvest
756 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
757 if( MustHaveParamCount( GetByte(), 3 ) )
759 double fRate1_reinvest
= GetDouble() + 1;
760 double fNPV_reinvest
= 0.0;
761 double fPow_reinvest
= 1.0;
763 double fRate1_invest
= GetDouble() + 1;
764 double fNPV_invest
= 0.0;
765 double fPow_invest
= 1.0;
768 PopDoubleRef( aRange
);
771 PushError( nGlobalError
);
774 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
);
777 USHORT nIterError
= 0;
779 BOOL bLoop
= aValIter
.GetFirst( fCellValue
, nIterError
);
782 if( fCellValue
> 0.0 ) // reinvestments
783 fNPV_reinvest
+= fCellValue
* fPow_reinvest
;
784 else if( fCellValue
< 0.0 ) // investments
785 fNPV_invest
+= fCellValue
* fPow_invest
;
786 fPow_reinvest
/= fRate1_reinvest
;
787 fPow_invest
/= fRate1_invest
;
790 bLoop
= aValIter
.GetNext( fCellValue
, nIterError
);
793 PushError( nIterError
);
796 double fResult
= -fNPV_reinvest
/ fNPV_invest
;
797 fResult
*= pow( fRate1_reinvest
, (double) nCount
- 1 );
798 fResult
= pow( fResult
, 1.0 / (nCount
- 1) );
799 PushDouble( fResult
- 1.0 );
806 void ScInterpreter::ScISPMT()
807 { // rate ; period ; total_periods ; invest
808 if( MustHaveParamCount( GetByte(), 4 ) )
810 double fInvest
= GetDouble();
811 double fTotal
= GetDouble();
812 double fPeriod
= GetDouble();
813 double fRate
= GetDouble();
816 PushError( nGlobalError
);
818 PushDouble( fInvest
* fRate
* (fPeriod
/ fTotal
- 1.0) );
823 //----------------------- Finanzfunktionen ------------------------------------
825 double ScInterpreter::ScGetBw(double fZins
, double fZzr
, double fRmz
,
826 double fZw
, double fF
)
828 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMIRR" );
831 fBw
= fZw
+ fRmz
* fZzr
;
833 fBw
= (fZw
* pow(1.0 + fZins
, -fZzr
))
834 + (fRmz
* (1.0 - pow(1.0 + fZins
, -fZzr
+ 1.0)) / fZins
)
837 fBw
= (fZw
* pow(1.0 + fZins
, -fZzr
))
838 + (fRmz
* (1.0 - pow(1.0 + fZins
, -fZzr
)) / fZins
);
842 void ScInterpreter::ScBW()
844 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScBW" );
845 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
846 double nRmz
, nZzr
, nZins
, nZw
= 0, nFlag
= 0;
847 BYTE nParamCount
= GetByte();
848 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
850 if (nParamCount
== 5)
852 if (nParamCount
>= 4)
857 PushDouble(ScGetBw(nZins
, nZzr
, nRmz
, nZw
, nFlag
));
860 void ScInterpreter::ScDIA()
862 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDIA" );
863 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
864 if ( MustHaveParamCount( GetByte(), 4 ) )
866 double nZr
= GetDouble();
867 double nDauer
= GetDouble();
868 double nRest
= GetDouble();
869 double nWert
= GetDouble();
870 double nDia
= ((nWert
- nRest
) * (nDauer
- nZr
+ 1.0)) /
871 ((nDauer
* (nDauer
+ 1.0)) / 2.0);
876 double ScInterpreter::ScGetGDA(double fWert
, double fRest
, double fDauer
,
877 double fPeriode
, double fFaktor
)
879 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetGDA" );
880 double fGda
, fZins
, fAlterWert
, fNeuerWert
;
881 fZins
= fFaktor
/ fDauer
;
891 fAlterWert
= fWert
* pow(1.0 - fZins
, fPeriode
- 1.0);
892 fNeuerWert
= fWert
* pow(1.0 - fZins
, fPeriode
);
894 if (fNeuerWert
< fRest
)
895 fGda
= fAlterWert
- fRest
;
897 fGda
= fAlterWert
- fNeuerWert
;
903 void ScInterpreter::ScGDA()
905 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGDA" );
906 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
907 BYTE nParamCount
= GetByte();
908 if ( MustHaveParamCount( nParamCount
, 4, 5 ) )
911 if (nParamCount
== 5)
912 nFaktor
= GetDouble();
915 double nPeriode
= GetDouble();
916 double nDauer
= GetDouble();
917 double nRest
= GetDouble();
918 double nWert
= GetDouble();
919 if (nWert
< 0.0 || nRest
< 0.0 || nFaktor
<= 0.0 || nRest
> nWert
920 || nPeriode
< 1.0 || nPeriode
> nDauer
)
921 PushIllegalArgument();
923 PushDouble(ScGetGDA(nWert
, nRest
, nDauer
, nPeriode
, nFaktor
));
927 void ScInterpreter::ScGDA2()
929 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGDA2" );
930 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
931 BYTE nParamCount
= GetByte();
932 if ( !MustHaveParamCount( nParamCount
, 4, 5 ) )
935 if (nParamCount
== 4)
938 nMonate
= ::rtl::math::approxFloor(GetDouble());
939 double nPeriode
= GetDouble();
940 double nDauer
= GetDouble();
941 double nRest
= GetDouble();
942 double nWert
= GetDouble();
943 if (nMonate
< 1.0 || nMonate
> 12.0 || nDauer
> 1200.0 || nRest
< 0.0 ||
944 nPeriode
> (nDauer
+ 1.0) || nRest
> nWert
|| nWert
< 0.0)
946 PushIllegalArgument();
949 double nAbRate
= 1.0 - pow(nRest
/ nWert
, 1.0 / nDauer
);
950 nAbRate
= ::rtl::math::approxFloor((nAbRate
* 1000.0) + 0.5) / 1000.0;
951 double nErsteAbRate
= nWert
* nAbRate
* nMonate
/ 12.0;
953 if (::rtl::math::approxFloor(nPeriode
) == 1)
954 nGda2
= nErsteAbRate
;
957 double nSummAbRate
= nErsteAbRate
;
958 double nMin
= nDauer
;
959 if (nMin
> nPeriode
) nMin
= nPeriode
;
960 USHORT iMax
= (USHORT
)::rtl::math::approxFloor(nMin
);
961 for (USHORT i
= 2; i
<= iMax
; i
++)
963 nGda2
= (nWert
- nSummAbRate
) * nAbRate
;
964 nSummAbRate
+= nGda2
;
966 if (nPeriode
> nDauer
)
967 nGda2
= ((nWert
- nSummAbRate
) * nAbRate
* (12.0 - nMonate
)) / 12.0;
973 double ScInterpreter::ScInterVDB(double fWert
,double fRest
,double fDauer
,
974 double fDauer1
,double fPeriode
,double fFaktor
)
976 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScInterVDB" );
978 double fIntEnd
= ::rtl::math::approxCeil(fPeriode
);
979 ULONG nLoopEnd
= (ULONG
) fIntEnd
;
982 double fRestwert
= fWert
- fRest
;
983 BOOL bNowLia
= FALSE
;
988 for ( i
= 1; i
<= nLoopEnd
; i
++)
992 fGda
= ScGetGDA(fWert
, fRest
, fDauer
, (double) i
, fFaktor
);
993 fLia
= fRestwert
/ (fDauer1
- (double) (i
-1));
1012 fTerm
*= ( fPeriode
+ 1.0 - fIntEnd
);
1020 inline double DblMin( double a
, double b
)
1022 return (a
< b
) ? a
: b
;
1025 void ScInterpreter::ScVDB()
1027 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVDB" );
1028 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1029 BYTE nParamCount
= GetByte();
1030 if ( MustHaveParamCount( nParamCount
, 5, 7 ) )
1032 double fWert
, fRest
, fDauer
, fAnfang
, fEnde
, fFaktor
, fVdb
= 0.0;
1034 if (nParamCount
== 7)
1038 if (nParamCount
>= 6)
1039 fFaktor
= GetDouble();
1042 fEnde
= GetDouble();
1043 fAnfang
= GetDouble();
1044 fDauer
= GetDouble();
1045 fRest
= GetDouble();
1046 fWert
= GetDouble();
1047 if (fAnfang
< 0.0 || fEnde
< fAnfang
|| fEnde
> fDauer
|| fWert
< 0.0
1048 || fRest
> fWert
|| fFaktor
<= 0.0)
1049 PushIllegalArgument();
1052 double fIntStart
= ::rtl::math::approxFloor(fAnfang
);
1053 double fIntEnd
= ::rtl::math::approxCeil(fEnde
);
1054 ULONG nLoopStart
= (ULONG
) fIntStart
;
1055 ULONG nLoopEnd
= (ULONG
) fIntEnd
;
1060 for (ULONG i
= nLoopStart
+ 1; i
<= nLoopEnd
; i
++)
1062 double fTerm
= ScGetGDA(fWert
, fRest
, fDauer
, (double) i
, fFaktor
);
1064 // Teilperioden am Anfang / Ende beruecksichtigen:
1065 if ( i
== nLoopStart
+1 )
1066 fTerm
*= ( DblMin( fEnde
, fIntStart
+ 1.0 ) - fAnfang
);
1067 else if ( i
== nLoopEnd
)
1068 fTerm
*= ( fEnde
+ 1.0 - fIntEnd
);
1076 double fDauer1
=fDauer
;
1079 //@Die Frage aller Fragen: "Ist das hier richtig"
1080 if(!::rtl::math::approxEqual(fAnfang
,::rtl::math::approxFloor(fAnfang
)))
1084 if(fAnfang
>fDauer
/2 || ::rtl::math::approxEqual(fAnfang
,fDauer
/2))
1086 fPart
=fAnfang
-fDauer
/2;
1094 fWert
-=ScInterVDB(fWert
,fRest
,fDauer
,fDauer1
,fAnfang
,fFaktor
);
1095 fVdb
=ScInterVDB(fWert
,fRest
,fDauer
,fDauer
-fAnfang
,fEnde
-fAnfang
,fFaktor
);
1102 void ScInterpreter::ScLaufz()
1104 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLaufz" );
1105 if ( MustHaveParamCount( GetByte(), 3 ) )
1107 double nZukunft
= GetDouble();
1108 double nGegenwart
= GetDouble();
1109 double nZins
= GetDouble();
1110 PushDouble(log(nZukunft
/ nGegenwart
) / log(1.0 + nZins
));
1114 void ScInterpreter::ScLIA()
1116 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLIA" );
1117 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1118 if ( MustHaveParamCount( GetByte(), 3 ) )
1120 double nDauer
= GetDouble();
1121 double nRest
= GetDouble();
1122 double nWert
= GetDouble();
1123 PushDouble((nWert
- nRest
) / nDauer
);
1127 double ScInterpreter::ScGetRmz(double fZins
, double fZzr
, double fBw
,
1128 double fZw
, double fF
)
1130 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetRmz" );
1133 fRmz
= (fBw
+ fZw
) / fZzr
;
1136 double fTerm
= pow(1.0 + fZins
, fZzr
);
1138 fRmz
= (fZw
* fZins
/ (fTerm
- 1.0)
1139 + fBw
* fZins
/ (1.0 - 1.0 / fTerm
)) / (1.0+fZins
);
1141 fRmz
= fZw
* fZins
/ (fTerm
- 1.0)
1142 + fBw
* fZins
/ (1.0 - 1.0 / fTerm
);
1147 void ScInterpreter::ScRMZ()
1149 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRMZ" );
1150 double nZins
, nZzr
, nBw
, nZw
= 0, nFlag
= 0;
1151 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1152 BYTE nParamCount
= GetByte();
1153 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
1155 if (nParamCount
== 5)
1156 nFlag
= GetDouble();
1157 if (nParamCount
>= 4)
1161 nZins
= GetDouble();
1162 PushDouble(ScGetRmz(nZins
, nZzr
, nBw
, nZw
, nFlag
));
1165 void ScInterpreter::ScZGZ()
1167 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScZGZ" );
1168 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1169 if ( MustHaveParamCount( GetByte(), 3 ) )
1171 double nZukunftswert
= GetDouble();
1172 double nGegenwartswert
= GetDouble();
1173 double nZeitraum
= GetDouble();
1174 PushDouble(pow(nZukunftswert
/ nGegenwartswert
, 1.0 / nZeitraum
) - 1.0);
1178 double ScInterpreter::ScGetZw(double fZins
, double fZzr
, double fRmz
,
1179 double fBw
, double fF
)
1181 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetZw" );
1184 fZw
= fBw
+ fRmz
* fZzr
;
1187 double fTerm
= pow(1.0 + fZins
, fZzr
);
1189 fZw
= fBw
* fTerm
+ fRmz
*(1.0 + fZins
)*(fTerm
- 1.0)/fZins
;
1191 fZw
= fBw
* fTerm
+ fRmz
*(fTerm
- 1.0)/fZins
;
1196 void ScInterpreter::ScZW()
1198 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScZW" );
1199 double nZins
, nZzr
, nRmz
, nBw
= 0, nFlag
= 0;
1200 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1201 BYTE nParamCount
= GetByte();
1202 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
1204 if (nParamCount
== 5)
1205 nFlag
= GetDouble();
1206 if (nParamCount
>= 4)
1210 nZins
= GetDouble();
1211 PushDouble(ScGetZw(nZins
, nZzr
, nRmz
, nBw
, nFlag
));
1214 void ScInterpreter::ScZZR()
1216 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScZZR" );
1217 double nZins
, nRmz
, nBw
, nZw
= 0, nFlag
= 0;
1218 BYTE nParamCount
= GetByte();
1219 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
1221 if (nParamCount
== 5)
1222 nFlag
= GetDouble();
1223 if (nParamCount
>= 4)
1227 nZins
= GetDouble();
1229 PushDouble(-(nBw
+ nZw
)/nRmz
);
1230 else if (nFlag
> 0.0)
1231 PushDouble(log(-(nZins
*nZw
-nRmz
*(1.0+nZins
))/(nZins
*nBw
+nRmz
*(1.0+nZins
)))
1234 PushDouble(log(-(nZins
*nZw
-nRmz
)/(nZins
*nBw
+nRmz
))/log(1.0+nZins
));
1237 bool ScInterpreter::RateIteration( double fNper
, double fPayment
, double fPv
,
1238 double fFv
, double fPayType
, double & fGuess
)
1240 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::RateIteration" );
1241 // See also #i15090#
1242 // Newton-Raphson method: x(i+1) = x(i) - f(x(i)) / f'(x(i))
1243 // This solution handles integer and non-integer values of Nper different.
1244 // If ODFF will constraint Nper to integer, the distinction of cases can be
1245 // removed; only the integer-part is needed then.
1246 bool bValid
= true, bFound
= false;
1247 double fX
, fXnew
, fTerm
, fTermDerivation
;
1248 double fGeoSeries
, fGeoSeriesDerivation
;
1249 const USHORT nIterationsMax
= 150;
1251 const double fEpsilonSmall
= 1.0E-14;
1252 // convert any fPayType situation to fPayType == zero situation
1253 fFv
= fFv
- fPayment
* fPayType
;
1254 fPv
= fPv
+ fPayment
* fPayType
;
1255 if (fNper
== ::rtl::math::round( fNper
, 0, rtl_math_RoundingMode_Corrected
))
1256 { // Nper is an integer value
1258 double fPowN
, fPowNminus1
; // for (1.0+fX)^Nper and (1.0+fX)^(Nper-1)
1259 while (!bFound
&& nCount
< nIterationsMax
)
1261 fPowNminus1
= pow( 1.0+fX
, fNper
-1.0);
1262 fPowN
= fPowNminus1
* (1.0+fX
);
1263 if (rtl::math::approxEqual( fabs(fX
), 0.0))
1266 fGeoSeriesDerivation
= fNper
* (fNper
-1.0)/2.0;
1270 fGeoSeries
= (fPowN
-1.0)/fX
;
1271 fGeoSeriesDerivation
= fNper
* fPowNminus1
/ fX
- fGeoSeries
/ fX
;
1273 fTerm
= fFv
+ fPv
*fPowN
+ fPayment
* fGeoSeries
;
1274 fTermDerivation
= fPv
* fNper
* fPowNminus1
+ fPayment
* fGeoSeriesDerivation
;
1275 if (fabs(fTerm
) < fEpsilonSmall
)
1276 bFound
= true; // will catch root which is at an extreme
1279 if (rtl::math::approxEqual( fabs(fTermDerivation
), 0.0))
1280 fXnew
= fX
+ 1.1 * SCdEpsilon
; // move away from zero slope
1282 fXnew
= fX
- fTerm
/ fTermDerivation
;
1284 // more accuracy not possible in oscillating cases
1285 bFound
= (fabs(fXnew
- fX
) < SCdEpsilon
);
1289 // Gnumeric returns roots < -1, Excel gives an error in that cases,
1290 // ODFF says nothing about it. Enable the statement, if you want Excel's
1292 //bValid =(fX >=-1.0);
1295 { // Nper is not an integer value.
1296 fX
= (fGuess
< -1.0) ? -1.0 : fGuess
; // start with a valid fX
1297 while (bValid
&& !bFound
&& nCount
< nIterationsMax
)
1299 if (rtl::math::approxEqual( fabs(fX
), 0.0))
1302 fGeoSeriesDerivation
= fNper
* (fNper
-1.0)/2.0;
1306 fGeoSeries
= (pow( 1.0+fX
, fNper
) - 1.0) / fX
;
1307 fGeoSeriesDerivation
= fNper
* pow( 1.0+fX
, fNper
-1.0) / fX
- fGeoSeries
/ fX
;
1309 fTerm
= fFv
+ fPv
*pow(1.0 + fX
,fNper
)+ fPayment
* fGeoSeries
;
1310 fTermDerivation
= fPv
* fNper
* pow( 1.0+fX
, fNper
-1.0) + fPayment
* fGeoSeriesDerivation
;
1311 if (fabs(fTerm
) < fEpsilonSmall
)
1312 bFound
= true; // will catch root which is at an extreme
1315 if (rtl::math::approxEqual( fabs(fTermDerivation
), 0.0))
1316 fXnew
= fX
+ 1.1 * SCdEpsilon
; // move away from zero slope
1318 fXnew
= fX
- fTerm
/ fTermDerivation
;
1320 // more accuracy not possible in oscillating cases
1321 bFound
= (fabs(fXnew
- fX
) < SCdEpsilon
);
1323 bValid
= (fX
>= -1.0); // otherwise pow(1.0+fX,fNper) will fail
1327 fGuess
= fX
; // return approximate root
1328 return bValid
&& bFound
;
1331 // In Calc UI it is the function RATE(Nper;Pmt;Pv;Fv;Type;Guess)
1332 void ScInterpreter::ScZins()
1334 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScZins" );
1335 double fPv
, fPayment
, fNper
;
1336 // defaults for missing arguments, see ODFF spec
1337 double fFv
= 0, fPayType
= 0, fGuess
= 0.1;
1339 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1340 BYTE nParamCount
= GetByte();
1341 if ( !MustHaveParamCount( nParamCount
, 3, 6 ) )
1343 if (nParamCount
== 6)
1344 fGuess
= GetDouble();
1345 if (nParamCount
>= 5)
1346 fPayType
= GetDouble();
1347 if (nParamCount
>= 4)
1350 fPayment
= GetDouble();
1351 fNper
= GetDouble();
1352 if (fNper
<= 0.0) // constraint from ODFF spec
1354 PushIllegalArgument();
1357 // other values for fPayType might be meaningful,
1358 // ODFF spec is not clear yet, enable statement if you want only 0 and 1
1359 //if (fPayType != 0.0) fPayType = 1.0;
1360 bValid
= RateIteration(fNper
, fPayment
, fPv
, fFv
, fPayType
, fGuess
);
1362 SetError(errNoConvergence
);
1366 double ScInterpreter::ScGetZinsZ(double fZins
, double fZr
, double fZzr
, double fBw
,
1367 double fZw
, double fF
, double& fRmz
)
1369 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetZinsZ" );
1370 fRmz
= ScGetRmz(fZins
, fZzr
, fBw
, fZw
, fF
); // fuer kapz auch bei fZr == 1
1372 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1383 fZinsZ
= ScGetZw(fZins
, fZr
-2.0, fRmz
, fBw
, 1.0) - fRmz
;
1385 fZinsZ
= ScGetZw(fZins
, fZr
-1.0, fRmz
, fBw
, 0.0);
1387 return fZinsZ
* fZins
;
1390 void ScInterpreter::ScZinsZ()
1392 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScZinsZ" );
1393 double nZins
, nZr
, nRmz
, nZzr
, nBw
, nZw
= 0, nFlag
= 0;
1394 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1395 BYTE nParamCount
= GetByte();
1396 if ( !MustHaveParamCount( nParamCount
, 4, 6 ) )
1398 if (nParamCount
== 6)
1399 nFlag
= GetDouble();
1400 if (nParamCount
>= 5)
1405 nZins
= GetDouble();
1406 if (nZr
< 1.0 || nZr
> nZzr
)
1407 PushIllegalArgument();
1409 PushDouble(ScGetZinsZ(nZins
, nZr
, nZzr
, nBw
, nZw
, nFlag
, nRmz
));
1412 void ScInterpreter::ScKapz()
1414 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScKapz" );
1415 double nZins
, nZr
, nZzr
, nBw
, nZw
= 0, nFlag
= 0, nRmz
, nZinsz
;
1416 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1417 BYTE nParamCount
= GetByte();
1418 if ( !MustHaveParamCount( nParamCount
, 4, 6 ) )
1420 if (nParamCount
== 6)
1421 nFlag
= GetDouble();
1422 if (nParamCount
>= 5)
1427 nZins
= GetDouble();
1428 if (nZr
< 1.0 || nZr
> nZzr
)
1429 PushIllegalArgument();
1432 nZinsz
= ScGetZinsZ(nZins
, nZr
, nZzr
, nBw
, nZw
, nFlag
, nRmz
);
1433 PushDouble(nRmz
- nZinsz
);
1437 void ScInterpreter::ScKumZinsZ()
1439 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScKumZinsZ" );
1440 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1441 if ( MustHaveParamCount( GetByte(), 6 ) )
1443 double fZins
, fZzr
, fBw
, fAnfang
, fEnde
, fF
, fRmz
, fZinsZ
;
1445 fEnde
= ::rtl::math::approxFloor(GetDouble());
1446 fAnfang
= ::rtl::math::approxFloor(GetDouble());
1449 fZins
= GetDouble();
1450 if (fAnfang
< 1.0 || fEnde
< fAnfang
|| fZins
<= 0.0 ||
1451 fEnde
> fZzr
|| fZzr
<= 0.0 || fBw
<= 0.0)
1452 PushIllegalArgument();
1455 ULONG nAnfang
= (ULONG
) fAnfang
;
1456 ULONG nEnde
= (ULONG
) fEnde
;
1457 fRmz
= ScGetRmz(fZins
, fZzr
, fBw
, 0.0, fF
);
1465 for (ULONG i
= nAnfang
; i
<= nEnde
; i
++)
1468 fZinsZ
+= ScGetZw(fZins
, (double)(i
-2), fRmz
, fBw
, 1.0) - fRmz
;
1470 fZinsZ
+= ScGetZw(fZins
, (double)(i
-1), fRmz
, fBw
, 0.0);
1478 void ScInterpreter::ScKumKapZ()
1480 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScKumKapZ" );
1481 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1482 if ( MustHaveParamCount( GetByte(), 6 ) )
1484 double fZins
, fZzr
, fBw
, fAnfang
, fEnde
, fF
, fRmz
, fKapZ
;
1486 fEnde
= ::rtl::math::approxFloor(GetDouble());
1487 fAnfang
= ::rtl::math::approxFloor(GetDouble());
1490 fZins
= GetDouble();
1491 if (fAnfang
< 1.0 || fEnde
< fAnfang
|| fZins
<= 0.0 ||
1492 fEnde
> fZzr
|| fZzr
<= 0.0 || fBw
<= 0.0)
1493 PushIllegalArgument();
1496 fRmz
= ScGetRmz(fZins
, fZzr
, fBw
, 0.0, fF
);
1498 ULONG nAnfang
= (ULONG
) fAnfang
;
1499 ULONG nEnde
= (ULONG
) fEnde
;
1503 fKapZ
= fRmz
+ fBw
* fZins
;
1508 for (ULONG i
= nAnfang
; i
<= nEnde
; i
++)
1511 fKapZ
+= fRmz
- (ScGetZw(fZins
, (double)(i
-2), fRmz
, fBw
, 1.0) - fRmz
) * fZins
;
1513 fKapZ
+= fRmz
- ScGetZw(fZins
, (double)(i
-1), fRmz
, fBw
, 0.0) * fZins
;
1520 void ScInterpreter::ScEffektiv()
1522 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScEffektiv" );
1523 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1524 if ( MustHaveParamCount( GetByte(), 2 ) )
1526 double fPerioden
= GetDouble();
1527 double fNominal
= GetDouble();
1528 if (fPerioden
< 1.0 || fNominal
<= 0.0)
1529 PushIllegalArgument();
1532 fPerioden
= ::rtl::math::approxFloor(fPerioden
);
1533 PushDouble(pow(1.0 + fNominal
/fPerioden
, fPerioden
) - 1.0);
1538 void ScInterpreter::ScNominal()
1540 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNominal" );
1541 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1542 if ( MustHaveParamCount( GetByte(), 2 ) )
1544 double fPerioden
= GetDouble();
1545 double fEffektiv
= GetDouble();
1546 if (fPerioden
< 1.0 || fEffektiv
<= 0.0)
1547 PushIllegalArgument();
1550 fPerioden
= ::rtl::math::approxFloor(fPerioden
);
1551 PushDouble( (pow(fEffektiv
+ 1.0, 1.0 / fPerioden
) - 1.0) * fPerioden
);
1556 void ScInterpreter::ScMod()
1558 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMod" );
1559 if ( MustHaveParamCount( GetByte(), 2 ) )
1561 double nVal2
= GetDouble();
1562 double nVal1
= GetDouble();
1563 PushDouble( ::rtl::math::approxSub( nVal1
,
1564 ::rtl::math::approxFloor(nVal1
/ nVal2
) * nVal2
));
1568 /** (Goal Seek) Find a value of x that is a root of f(x)
1570 This function is used internally for the goal seek operation. It uses the
1571 Regula Falsi (aka false position) algorithm to find a root of f(x). The
1572 start value and the target value are to be given by the user in the
1573 goal seek dialog. The f(x) in this case is defined as the formula in the
1574 formula cell minus target value. This function may also perform additional
1575 search in the horizontal directions when the f(x) is discrete in order to
1576 ensure a non-zero slope necessary for deriving a subsequent x that is
1577 reasonably close to the root of interest.
1579 @change 24.10.2004 by Kohei Yoshida (kohei@openoffice.org)
1583 void ScInterpreter::ScBackSolver()
1585 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScBackSolver" );
1586 if ( MustHaveParamCount( GetByte(), 3 ) )
1588 BOOL bDoneIteration
= FALSE
;
1589 ScAddress aValueAdr
, aFormulaAdr
;
1590 double fTargetVal
= GetDouble();
1591 PopSingleRef( aFormulaAdr
);
1592 PopSingleRef( aValueAdr
);
1594 if (nGlobalError
== 0)
1596 ScBaseCell
* pVCell
= GetCell( aValueAdr
);
1597 // CELLTYPE_NOTE: kein Value aber von Formel referiert
1598 BOOL bTempCell
= (!pVCell
|| pVCell
->GetCellType() == CELLTYPE_NOTE
);
1599 ScBaseCell
* pFCell
= GetCell( aFormulaAdr
);
1601 if ( ((pVCell
&& pVCell
->GetCellType() == CELLTYPE_VALUE
) || bTempCell
)
1602 && pFCell
&& pFCell
->GetCellType() == CELLTYPE_FORMULA
)
1604 ScRange
aVRange( aValueAdr
, aValueAdr
); // fuer SetDirty
1605 double fSaveVal
; // Original value to be restored later if necessary
1606 ScPostIt
* pNote
= 0;
1610 pNote
= pVCell
? pVCell
->ReleaseNote() : 0;
1612 pVCell
= new ScValueCell( fSaveVal
);
1613 pDok
->PutCell( aValueAdr
, pVCell
);
1616 fSaveVal
= GetCellValue( aValueAdr
, pVCell
);
1618 const USHORT nMaxIter
= 100;
1619 const double fEps
= 1E-10;
1620 const double fDelta
= 1E-6;
1622 double fBestX
, fXPrev
;
1623 double fBestF
, fFPrev
;
1624 fBestX
= fXPrev
= fSaveVal
;
1626 ScFormulaCell
* pFormula
= (ScFormulaCell
*) pFCell
;
1627 ScValueCell
* pValue
= (ScValueCell
*) pVCell
;
1629 pFormula
->Interpret();
1630 BOOL bError
= ( pFormula
->GetErrCode() != 0 );
1631 // bError always corresponds with fF
1633 fFPrev
= pFormula
->GetValue() - fTargetVal
;
1635 fBestF
= fabs( fFPrev
);
1636 if ( fBestF
< fDelta
)
1637 bDoneIteration
= TRUE
;
1639 double fX
= fXPrev
+ fEps
;
1645 BOOL bHorMoveError
= FALSE
;
1646 // Nach der Regula Falsi Methode
1647 while ( !bDoneIteration
&& ( nIter
++ < nMaxIter
) )
1649 pValue
->SetValue( fX
);
1650 pDok
->SetDirty( aVRange
);
1651 pFormula
->Interpret();
1652 bError
= ( pFormula
->GetErrCode() != 0 );
1653 fF
= pFormula
->GetValue() - fTargetVal
;
1655 if ( fF
== fFPrev
&& !bError
)
1657 // HORIZONTAL SEARCH: Keep moving x in both directions until the f(x)
1658 // becomes different from the previous f(x). This routine is needed
1659 // when a given function is discrete, in which case the resulting slope
1660 // may become zero which ultimately causes the goal seek operation
1661 // to fail. #i28955#
1663 USHORT nHorIter
= 0;
1664 const double fHorStepAngle
= 5.0;
1665 const double fHorMaxAngle
= 80.0;
1666 int nHorMaxIter
= static_cast<int>( fHorMaxAngle
/ fHorStepAngle
);
1667 BOOL bDoneHorMove
= FALSE
;
1669 while ( !bDoneHorMove
&& !bHorMoveError
&& nHorIter
++ < nHorMaxIter
)
1671 double fHorAngle
= fHorStepAngle
* static_cast<double>( nHorIter
);
1672 double fHorTangent
= ::rtl::math::tan( fHorAngle
* F_PI
/ 180 );
1675 while( nIdx
++ < 2 && !bDoneHorMove
)
1679 fHorX
= fX
+ fabs(fF
)*fHorTangent
;
1681 fHorX
= fX
- fabs(fF
)*fHorTangent
;
1683 pValue
->SetValue( fHorX
);
1684 pDok
->SetDirty( aVRange
);
1685 pFormula
->Interpret();
1686 bHorMoveError
= ( pFormula
->GetErrCode() != 0 );
1687 if ( bHorMoveError
)
1690 fF
= pFormula
->GetValue() - fTargetVal
;
1694 bDoneHorMove
= TRUE
;
1698 if ( !bDoneHorMove
)
1699 bHorMoveError
= TRUE
;
1704 // move closer to last valid value (fXPrev), keep fXPrev & fFPrev
1705 double fDiff
= ( fXPrev
- fX
) / 2;
1706 if (fabs(fDiff
) < fEps
)
1707 fDiff
= (fDiff
< 0.0) ? - fEps
: fEps
;
1710 else if ( bHorMoveError
)
1712 else if ( fabs(fF
) < fDelta
)
1714 // converged to root
1716 bDoneIteration
= TRUE
;
1720 if ( fabs(fF
) + fDelta
< fBestF
)
1726 if ( ( fXPrev
- fX
) != 0 )
1728 fSlope
= ( fFPrev
- fF
) / ( fXPrev
- fX
);
1729 if ( fabs( fSlope
) < fEps
)
1730 fSlope
= fSlope
< 0.0 ? -fEps
: fEps
;
1737 fX
= fX
- ( fF
/ fSlope
);
1741 // Try a nice rounded input value if possible.
1742 const double fNiceDelta
= (bDoneIteration
&& fabs(fBestX
) >= 1e-3 ? 1e-3 : fDelta
);
1743 double nX
= ::rtl::math::approxFloor((fBestX
/ fNiceDelta
) + 0.5) * fNiceDelta
;
1744 // double nX = ::rtl::math::approxFloor((fBestX / fDelta) + 0.5) * fDelta;
1746 if ( bDoneIteration
)
1748 pValue
->SetValue( nX
);
1749 pDok
->SetDirty( aVRange
);
1750 pFormula
->Interpret();
1751 if ( fabs( pFormula
->GetValue() - fTargetVal
) > fabs( fF
) )
1754 else if ( bError
|| bHorMoveError
)
1760 pVCell
= pNote
? new ScNoteCell( pNote
) : 0;
1761 pDok
->PutCell( aValueAdr
, pVCell
);
1764 pValue
->SetValue( fSaveVal
);
1765 pDok
->SetDirty( aVRange
);
1766 pFormula
->Interpret();
1767 if ( !bDoneIteration
)
1768 SetError(NOTAVAILABLE
);
1773 if ( !bDoneIteration
)
1774 SetError(NOTAVAILABLE
);
1775 PushInt(0); // falsche Zelltypen
1780 if ( !bDoneIteration
)
1781 SetError(NOTAVAILABLE
);
1782 PushInt(0); // nGlobalError
1787 void ScInterpreter::ScIntersect()
1789 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIntersect" );
1790 formula::FormulaTokenRef p2nd
= PopToken();
1791 formula::FormulaTokenRef p1st
= PopToken();
1793 if (nGlobalError
|| !p2nd
|| !p1st
)
1795 PushIllegalArgument();
1797 } // if (nGlobalError || !xT2 || !xT1)
1799 StackVar sv1
= p1st
->GetType();
1800 StackVar sv2
= p2nd
->GetType();
1801 if ((sv1
!= svSingleRef
&& sv1
!= svDoubleRef
&& sv1
!= svRefList
) ||
1802 (sv2
!= svSingleRef
&& sv2
!= svDoubleRef
&& sv2
!= svRefList
))
1804 PushIllegalArgument();
1808 ScToken
* x1
= static_cast<ScToken
*>(p1st
.get());
1809 ScToken
* x2
= static_cast<ScToken
*>(p2nd
.get());
1810 if (sv1
== svRefList
|| sv2
== svRefList
)
1812 // Now this is a bit nasty but it simplifies things, and having
1813 // intersections with lists isn't too common, if at all..
1814 // Convert a reference to list.
1815 ScToken
* xt
[2] = { x1
, x2
};
1816 StackVar sv
[2] = { sv1
, sv2
};
1817 for (size_t i
=0; i
<2; ++i
)
1819 if (sv
[i
] == svSingleRef
)
1821 ScComplexRefData aRef
;
1822 aRef
.Ref1
= aRef
.Ref2
= xt
[i
]->GetSingleRef();
1823 xt
[i
] = new ScRefListToken
;
1824 xt
[i
]->GetRefList()->push_back( aRef
);
1826 else if (sv
[i
] == svDoubleRef
)
1828 ScComplexRefData aRef
= xt
[i
]->GetDoubleRef();
1829 xt
[i
] = new ScRefListToken
;
1830 xt
[i
]->GetRefList()->push_back( aRef
);
1833 x1
= xt
[0], x2
= xt
[1];
1835 x1
->CalcAbsIfRel( aPos
);
1836 x2
->CalcAbsIfRel( aPos
);
1837 ScTokenRef xRes
= new ScRefListToken
;
1838 ScRefList
* pRefList
= xRes
->GetRefList();
1839 ScRefList::const_iterator
end1( x1
->GetRefList()->end());
1840 ScRefList::const_iterator
end2( x2
->GetRefList()->end());
1841 for (ScRefList::const_iterator
it1( x1
->GetRefList()->begin());
1844 const ScSingleRefData
& r11
= (*it1
).Ref1
;
1845 const ScSingleRefData
& r12
= (*it1
).Ref2
;
1846 for (ScRefList::const_iterator
it2( x2
->GetRefList()->begin());
1849 const ScSingleRefData
& r21
= (*it2
).Ref1
;
1850 const ScSingleRefData
& r22
= (*it2
).Ref2
;
1851 SCCOL nCol1
= ::std::max( r11
.nCol
, r21
.nCol
);
1852 SCROW nRow1
= ::std::max( r11
.nRow
, r21
.nRow
);
1853 SCTAB nTab1
= ::std::max( r11
.nTab
, r21
.nTab
);
1854 SCCOL nCol2
= ::std::min( r12
.nCol
, r22
.nCol
);
1855 SCROW nRow2
= ::std::min( r12
.nRow
, r22
.nRow
);
1856 SCTAB nTab2
= ::std::min( r12
.nTab
, r22
.nTab
);
1857 if (nCol2
< nCol1
|| nRow2
< nRow1
|| nTab2
< nTab1
)
1861 ScComplexRefData aRef
;
1862 aRef
.InitRange( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
1863 pRefList
->push_back( aRef
);
1867 size_t n
= pRefList
->size();
1869 PushError( errNoRef
);
1872 const ScComplexRefData
& rRef
= (*pRefList
)[0];
1873 if (rRef
.Ref1
== rRef
.Ref2
)
1874 PushTempToken( new ScSingleRefToken( rRef
.Ref1
));
1876 PushTempToken( new ScDoubleRefToken( rRef
));
1879 PushTempToken( xRes
);
1883 ScToken
* pt
[2] = { x1
, x2
};
1884 StackVar sv
[2] = { sv1
, sv2
};
1885 SCCOL nC1
[2], nC2
[2];
1886 SCROW nR1
[2], nR2
[2];
1887 SCTAB nT1
[2], nT2
[2];
1888 for (size_t i
=0; i
<2; ++i
)
1894 pt
[i
]->CalcAbsIfRel( aPos
);
1896 const ScSingleRefData
& r
= pt
[i
]->GetSingleRef();
1901 if (sv
[i
] == svDoubleRef
)
1903 const ScSingleRefData
& r
= pt
[i
]->GetSingleRef2();
1916 ; // nothing, prevent compiler warning
1919 SCCOL nCol1
= ::std::max( nC1
[0], nC1
[1]);
1920 SCROW nRow1
= ::std::max( nR1
[0], nR1
[1]);
1921 SCTAB nTab1
= ::std::max( nT1
[0], nT1
[1]);
1922 SCCOL nCol2
= ::std::min( nC2
[0], nC2
[1]);
1923 SCROW nRow2
= ::std::min( nR2
[0], nR2
[1]);
1924 SCTAB nTab2
= ::std::min( nT2
[0], nT2
[1]);
1925 if (nCol2
< nCol1
|| nRow2
< nRow1
|| nTab2
< nTab1
)
1926 PushError( errNoRef
);
1927 else if (nCol2
== nCol1
&& nRow2
== nRow1
&& nTab2
== nTab1
)
1928 PushSingleRef( nCol1
, nRow1
, nTab1
);
1930 PushDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
1935 void ScInterpreter::ScRangeFunc()
1937 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRangeFunc" );
1938 formula::FormulaTokenRef x2
= PopToken();
1939 formula::FormulaTokenRef x1
= PopToken();
1941 if (nGlobalError
|| !x2
|| !x1
)
1943 PushIllegalArgument();
1945 } // if (nGlobalError || !xT2 || !xT1)
1946 FormulaTokenRef xRes
= ScToken::ExtendRangeReference( *x1
, *x2
, aPos
, false);
1948 PushIllegalArgument();
1950 PushTempToken( xRes
);
1954 void ScInterpreter::ScUnionFunc()
1956 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScUnionFunc" );
1957 formula::FormulaTokenRef p2nd
= PopToken();
1958 formula::FormulaTokenRef p1st
= PopToken();
1960 if (nGlobalError
|| !p2nd
|| !p1st
)
1962 PushIllegalArgument();
1964 } // if (nGlobalError || !xT2 || !xT1)
1966 StackVar sv1
= p1st
->GetType();
1967 StackVar sv2
= p2nd
->GetType();
1968 if ((sv1
!= svSingleRef
&& sv1
!= svDoubleRef
&& sv1
!= svRefList
) ||
1969 (sv2
!= svSingleRef
&& sv2
!= svDoubleRef
&& sv2
!= svRefList
))
1971 PushIllegalArgument();
1975 ScToken
* x1
= static_cast<ScToken
*>(p1st
.get());
1976 ScToken
* x2
= static_cast<ScToken
*>(p2nd
.get());
1980 // Append to an existing RefList if there is one.
1981 if (sv1
== svRefList
)
1984 sv1
= svUnknown
; // mark as handled
1986 else if (sv2
== svRefList
)
1989 sv2
= svUnknown
; // mark as handled
1992 xRes
= new ScRefListToken
;
1993 ScRefList
* pRes
= xRes
->GetRefList();
1994 ScToken
* pt
[2] = { x1
, x2
};
1995 StackVar sv
[2] = { sv1
, sv2
};
1996 for (size_t i
=0; i
<2; ++i
)
2004 ScComplexRefData aRef
;
2005 aRef
.Ref1
= aRef
.Ref2
= pt
[i
]->GetSingleRef();
2006 pRes
->push_back( aRef
);
2010 pRes
->push_back( pt
[i
]->GetDoubleRef());
2014 const ScRefList
* p
= pt
[i
]->GetRefList();
2015 ScRefList::const_iterator
it( p
->begin());
2016 ScRefList::const_iterator
end( p
->end());
2017 for ( ; it
!= end
; ++it
)
2019 pRes
->push_back( *it
);
2024 ; // nothing, prevent compiler warning
2027 ValidateRef( *pRes
); // set #REF! if needed
2028 PushTempToken( xRes
);
2032 void ScInterpreter::ScCurrent()
2034 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCurrent" );
2035 FormulaTokenRef
xTok( PopToken());
2038 PushTempToken( xTok
);
2039 PushTempToken( xTok
);
2042 PushError( errUnknownStackVariable
);
2045 void ScInterpreter::ScStyle()
2047 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScStyle" );
2048 BYTE nParamCount
= GetByte();
2049 if (nParamCount
>= 1 && nParamCount
<= 3)
2051 String aStyle2
; // Vorlage nach Timer
2052 if (nParamCount
>= 3)
2053 aStyle2
= GetString();
2054 long nTimeOut
= 0; // Timeout
2055 if (nParamCount
>= 2)
2056 nTimeOut
= (long)(GetDouble()*1000.0);
2057 String aStyle1
= GetString(); // Vorlage fuer sofort
2063 // Request ausfuehren, um Vorlage anzuwenden
2066 if ( !pDok
->IsClipOrUndo() )
2068 SfxObjectShell
* pShell
= pDok
->GetDocumentShell();
2071 //! notify object shell directly
2073 ScRange
aRange(aPos
);
2074 ScAutoStyleHint
aHint( aRange
, aStyle1
, nTimeOut
, aStyle2
);
2075 pShell
->Broadcast( aHint
);
2082 PushIllegalParameter();
2085 ScDdeLink
* lcl_GetDdeLink( SvxLinkManager
* pLinkMgr
,
2086 const String
& rA
, const String
& rT
, const String
& rI
, BYTE nM
)
2088 USHORT nCount
= pLinkMgr
->GetLinks().Count();
2089 for (USHORT i
=0; i
<nCount
; i
++ )
2091 ::sfx2::SvBaseLink
* pBase
= *pLinkMgr
->GetLinks()[i
];
2092 if (pBase
->ISA(ScDdeLink
))
2094 ScDdeLink
* pLink
= (ScDdeLink
*)pBase
;
2095 if ( pLink
->GetAppl() == rA
&&
2096 pLink
->GetTopic() == rT
&&
2097 pLink
->GetItem() == rI
&&
2098 pLink
->GetMode() == nM
)
2106 void ScInterpreter::ScDde()
2108 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDde" );
2109 // Applikation, Datei, Bereich
2110 // Application, Topic, Item
2112 BYTE nParamCount
= GetByte();
2113 if ( MustHaveParamCount( nParamCount
, 3, 4 ) )
2115 BYTE nMode
= SC_DDE_DEFAULT
;
2116 if (nParamCount
== 4)
2117 nMode
= (BYTE
) ::rtl::math::approxFloor(GetDouble());
2118 String aItem
= GetString();
2119 String aTopic
= GetString();
2120 String aAppl
= GetString();
2122 if (nMode
> SC_DDE_TEXT
)
2123 nMode
= SC_DDE_DEFAULT
;
2125 // temporary documents (ScFunctionAccess) have no DocShell
2126 // and no LinkManager -> abort
2128 SvxLinkManager
* pLinkMgr
= pDok
->GetLinkManager();
2135 // Nach dem Laden muss neu interpretiert werden (Verknuepfungen aufbauen)
2137 if ( pMyFormulaCell
->GetCode()->IsRecalcModeNormal() )
2138 pMyFormulaCell
->GetCode()->SetRecalcModeOnLoad();
2140 // solange der Link nicht ausgewertet ist, Idle abklemmen
2141 // (um zirkulaere Referenzen zu vermeiden)
2143 BOOL bOldDis
= pDok
->IsIdleDisabled();
2144 pDok
->DisableIdle( TRUE
);
2146 // Link-Objekt holen / anlegen
2148 ScDdeLink
* pLink
= lcl_GetDdeLink( pLinkMgr
, aAppl
, aTopic
, aItem
, nMode
);
2150 //! Dde-Links (zusaetzlich) effizienter am Dokument speichern !!!!!
2151 // ScDdeLink* pLink = pDok->GetDdeLink( aAppl, aTopic, aItem );
2153 BOOL bWasError
= ( pMyFormulaCell
->GetRawError() != 0 );
2157 pLink
= new ScDdeLink( pDok
, aAppl
, aTopic
, aItem
, nMode
);
2158 pLinkMgr
->InsertDDELink( pLink
, aAppl
, aTopic
, aItem
);
2159 if ( pLinkMgr
->GetLinks().Count() == 1 ) // erster ?
2161 SfxBindings
* pBindings
= pDok
->GetViewBindings();
2163 pBindings
->Invalidate( SID_LINKS
); // Link-Manager enablen
2166 //! asynchron auswerten ???
2167 pLink
->TryUpdate(); // TryUpdate ruft Update nicht mehrfach auf
2169 // StartListening erst nach dem Update, sonst circular reference
2170 pMyFormulaCell
->StartListening( *pLink
);
2174 pMyFormulaCell
->StartListening( *pLink
);
2177 // Wenn aus dem Reschedule beim Ausfuehren des Links ein Fehler
2178 // (z.B. zirkulaere Referenz) entstanden ist, der vorher nicht da war,
2179 // das Fehler-Flag zuruecksetzen:
2181 if ( pMyFormulaCell
->GetRawError() && !bWasError
)
2182 pMyFormulaCell
->SetErrCode(0);
2186 const ScMatrix
* pLinkMat
= pLink
->GetResult();
2190 pLinkMat
->GetDimensions(nC
, nR
);
2191 ScMatrixRef pNewMat
= GetNewMat( nC
, nR
);
2194 pLinkMat
->MatCopy(*pNewMat
); // kopieren
2195 PushMatrix( pNewMat
);
2198 PushIllegalArgument();
2203 pDok
->DisableIdle( bOldDis
);
2207 void ScInterpreter::ScBase()
2208 { // Value, Base [, MinLen]
2209 BYTE nParamCount
= GetByte();
2210 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
2212 static const sal_Unicode __FAR_DATA pDigits
[] = {
2213 '0','1','2','3','4','5','6','7','8','9',
2214 'A','B','C','D','E','F','G','H','I','J','K','L','M',
2215 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
2218 static const int nDigits
= (sizeof(pDigits
)/sizeof(sal_Unicode
))-1;
2220 if ( nParamCount
== 3 )
2222 double fLen
= ::rtl::math::approxFloor( GetDouble() );
2223 if ( 1.0 <= fLen
&& fLen
< STRING_MAXLEN
)
2224 nMinLen
= (xub_StrLen
) fLen
;
2225 else if ( fLen
== 0.0 )
2228 nMinLen
= 0; // Error
2232 double fBase
= ::rtl::math::approxFloor( GetDouble() );
2233 double fVal
= ::rtl::math::approxFloor( GetDouble() );
2234 double fChars
= ((fVal
> 0.0 && fBase
> 0.0) ?
2235 (ceil( log( fVal
) / log( fBase
) ) + 2.0) :
2237 if ( fChars
>= STRING_MAXLEN
)
2238 nMinLen
= 0; // Error
2240 if ( !nGlobalError
&& nMinLen
&& 2 <= fBase
&& fBase
<= nDigits
&& 0 <= fVal
)
2242 const xub_StrLen nConstBuf
= 128;
2243 sal_Unicode aBuf
[nConstBuf
];
2244 xub_StrLen nBuf
= Max( (xub_StrLen
) fChars
, (xub_StrLen
) (nMinLen
+1) );
2245 sal_Unicode
* pBuf
= (nBuf
<= nConstBuf
? aBuf
: new sal_Unicode
[nBuf
]);
2246 for ( xub_StrLen j
= 0; j
< nBuf
; ++j
)
2250 sal_Unicode
* p
= pBuf
+ nBuf
- 1;
2252 if ( fVal
<= (ULONG
)(~0) )
2254 ULONG nVal
= (ULONG
) fVal
;
2255 ULONG nBase
= (ULONG
) fBase
;
2256 while ( nVal
&& p
> pBuf
)
2258 *--p
= pDigits
[ nVal
% nBase
];
2261 fVal
= (double) nVal
;
2266 while ( fVal
&& p
> pBuf
)
2268 //! mit fmod Rundungsfehler ab 2**48
2269 // double fDig = ::rtl::math::approxFloor( fmod( fVal, fBase ) );
2270 // so ist es etwas besser
2271 double fInt
= ::rtl::math::approxFloor( fVal
/ fBase
);
2272 double fMult
= fInt
* fBase
;
2273 #if OSL_DEBUG_LEVEL > 1
2274 // #53943# =BASIS(1e308;36) => GPF mit
2275 // nDig = (size_t) ::rtl::math::approxFloor( fVal - fMult );
2276 // trotz vorheriger Pruefung ob fVal >= fMult
2277 double fDebug1
= fVal
- fMult
;
2278 // fVal := 7,5975311883090e+290
2279 // fMult := 7,5975311883090e+290
2280 // fDebug1 := 1,3848924157003e+275 <- RoundOff-Error
2281 // fVal != fMult, aber: ::rtl::math::approxEqual( fVal, fMult ) == TRUE
2282 double fDebug2
= ::rtl::math::approxSub( fVal
, fMult
);
2283 // und ::rtl::math::approxSub( fVal, fMult ) == 0
2284 double fDebug3
= ( fInt
? fVal
/ fInt
: 0.0 );
2285 // Nach dem strange fDebug1 und fVal < fMult ist eigentlich
2286 // fDebug2 == fBase, trotzdem wird das mit einem Vergleich
2287 // nicht erkannt, dann schlaegt bDirt zu und alles wird wieder gut..
2289 // prevent compiler warnings
2290 (void)fDebug1
; (void)fDebug2
; (void)fDebug3
;
2294 { // da ist was gekippt
2300 double fDig
= ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal
, fMult
) );
2308 else if ( fDig
>= fBase
)
2309 nDig
= ((size_t) fBase
) - 1;
2311 nDig
= (size_t) fDig
;
2313 *--p
= pDigits
[ nDig
];
2318 PushError( errStringOverflow
);
2321 if ( nBuf
- (p
- pBuf
) <= nMinLen
)
2322 p
= pBuf
+ nBuf
- 1 - nMinLen
;
2323 PushStringBuffer( p
);
2329 PushIllegalArgument();
2334 void ScInterpreter::ScDecimal()
2336 if ( MustHaveParamCount( GetByte(), 2 ) )
2338 double fBase
= ::rtl::math::approxFloor( GetDouble() );
2339 String
aStr( GetString() );
2340 if ( !nGlobalError
&& 2 <= fBase
&& fBase
<= 36 )
2343 int nBase
= (int) fBase
;
2344 register const sal_Unicode
* p
= aStr
.GetBuffer();
2345 while ( *p
== ' ' || *p
== '\t' )
2346 p
++; // strip leading white space
2348 { // evtl. hex-prefix strippen
2349 if ( *p
== 'x' || *p
== 'X' )
2351 else if ( *p
== '0' && (*(p
+1) == 'x' || *(p
+1) == 'X') )
2357 if ( '0' <= *p
&& *p
<= '9' )
2359 else if ( 'A' <= *p
&& *p
<= 'Z' )
2360 n
= 10 + (*p
- 'A');
2361 else if ( 'a' <= *p
&& *p
<= 'z' )
2362 n
= 10 + (*p
- 'a');
2368 ( (nBase
== 2 && (*p
== 'b' || *p
== 'B'))
2369 ||(nBase
== 16 && (*p
== 'h' || *p
== 'H')) )
2371 ; // 101b und F00Dh sind ok
2374 PushIllegalArgument();
2379 fVal
= fVal
* fBase
+ n
;
2386 PushIllegalArgument();
2391 void ScInterpreter::ScConvert()
2392 { // Value, FromUnit, ToUnit
2393 if ( MustHaveParamCount( GetByte(), 3 ) )
2395 String
aToUnit( GetString() );
2396 String
aFromUnit( GetString() );
2397 double fVal
= GetDouble();
2399 PushError( nGlobalError
);
2401 { // erst die angegebene Reihenfolge suchen, wenn nicht gefunden den Kehrwert
2403 if ( ScGlobal::GetUnitConverter()->GetValue( fConv
, aFromUnit
, aToUnit
) )
2404 PushDouble( fVal
* fConv
);
2405 else if ( ScGlobal::GetUnitConverter()->GetValue( fConv
, aToUnit
, aFromUnit
) )
2406 PushDouble( fVal
/ fConv
);
2414 void ScInterpreter::ScRoman()
2416 BYTE nParamCount
= GetByte();
2417 if( MustHaveParamCount( nParamCount
, 1, 2 ) )
2419 double fMode
= (nParamCount
== 2) ? ::rtl::math::approxFloor( GetDouble() ) : 0.0;
2420 double fVal
= ::rtl::math::approxFloor( GetDouble() );
2422 PushError( nGlobalError
);
2423 else if( (fMode
>= 0.0) && (fMode
< 5.0) && (fVal
>= 0.0) && (fVal
< 4000.0) )
2425 static const sal_Unicode pChars
[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
2426 static const USHORT pValues
[] = { 1000, 500, 100, 50, 10, 5, 1 };
2427 static const USHORT nMaxIndex
= (USHORT
)(sizeof(pValues
) / sizeof(pValues
[0]) - 1);
2430 USHORT nVal
= (USHORT
) fVal
;
2431 USHORT nMode
= (USHORT
) fMode
;
2433 for( UINT16 i
= 0; i
<= nMaxIndex
/ 2; i
++ )
2435 USHORT nIndex
= 2 * i
;
2436 USHORT nDigit
= nVal
/ pValues
[ nIndex
];
2438 if( (nDigit
% 5) == 4 )
2440 USHORT nIndex2
= (nDigit
== 4) ? nIndex
- 1 : nIndex
- 2;
2442 while( (nSteps
< nMode
) && (nIndex
< nMaxIndex
) )
2445 if( pValues
[ nIndex2
] - pValues
[ nIndex
+ 1 ] <= nVal
)
2450 aRoman
+= pChars
[ nIndex
];
2451 aRoman
+= pChars
[ nIndex2
];
2452 nVal
= sal::static_int_cast
<USHORT
>( nVal
+ pValues
[ nIndex
] );
2453 nVal
= sal::static_int_cast
<USHORT
>( nVal
- pValues
[ nIndex2
] );
2458 aRoman
+= pChars
[ nIndex
- 1 ];
2459 aRoman
.Expand( aRoman
.Len() + (nDigit
% 5), pChars
[ nIndex
] );
2460 nVal
%= pValues
[ nIndex
];
2464 PushString( aRoman
);
2467 PushIllegalArgument();
2472 BOOL
lcl_GetArabicValue( sal_Unicode cChar
, USHORT
& rnValue
, BOOL
& rbIsDec
)
2474 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScBase" );
2477 case 'M': rnValue
= 1000; rbIsDec
= TRUE
; break;
2478 case 'D': rnValue
= 500; rbIsDec
= FALSE
; break;
2479 case 'C': rnValue
= 100; rbIsDec
= TRUE
; break;
2480 case 'L': rnValue
= 50; rbIsDec
= FALSE
; break;
2481 case 'X': rnValue
= 10; rbIsDec
= TRUE
; break;
2482 case 'V': rnValue
= 5; rbIsDec
= FALSE
; break;
2483 case 'I': rnValue
= 1; rbIsDec
= TRUE
; break;
2484 default: return FALSE
;
2490 void ScInterpreter::ScArabic()
2492 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArabic" );
2493 String
aRoman( GetString() );
2495 PushError( nGlobalError
);
2498 aRoman
.ToUpperAscii();
2501 USHORT nValidRest
= 3999;
2502 USHORT nCharIndex
= 0;
2503 USHORT nCharCount
= aRoman
.Len();
2506 while( bValid
&& (nCharIndex
< nCharCount
) )
2510 BOOL bIsDec1
= FALSE
;
2511 BOOL bIsDec2
= FALSE
;
2512 bValid
= lcl_GetArabicValue( aRoman
.GetChar( nCharIndex
), nDigit1
, bIsDec1
);
2513 if( bValid
&& (nCharIndex
+ 1 < nCharCount
) )
2514 bValid
= lcl_GetArabicValue( aRoman
.GetChar( nCharIndex
+ 1 ), nDigit2
, bIsDec2
);
2517 if( nDigit1
>= nDigit2
)
2519 nValue
= sal::static_int_cast
<USHORT
>( nValue
+ nDigit1
);
2520 nValidRest
%= (nDigit1
* (bIsDec1
? 5 : 2));
2521 bValid
= (nValidRest
>= nDigit1
);
2523 nValidRest
= sal::static_int_cast
<USHORT
>( nValidRest
- nDigit1
);
2526 else if( nDigit1
* 2 != nDigit2
)
2528 USHORT nDiff
= nDigit2
- nDigit1
;
2529 nValue
= sal::static_int_cast
<USHORT
>( nValue
+ nDiff
);
2530 bValid
= (nValidRest
>= nDiff
);
2532 nValidRest
= nDigit1
- 1;
2542 PushIllegalArgument();
2547 void ScInterpreter::ScHyperLink()
2549 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScHyperLink" );
2550 BYTE nParamCount
= GetByte();
2551 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
2553 String aCellText
= GetString();
2554 ScMatrixRef pResMat
= GetNewMat(1,2);
2555 pResMat
->PutString(aCellText
,0);
2556 pResMat
->PutString((nParamCount
== 2) ? GetString() : aCellText
, 1);
2557 bMatrixFormula
= true;
2558 PushMatrix(pResMat
);
2561 BOOL
lclConvertMoney( const String
& aSearchUnit
, double& rfRate
, int& rnDec
)
2565 const sal_Char
* pCurrText
;
2569 ConvertInfo aConvertTable
[] = {
2571 { "ATS", 13.7603, 2 },
2572 { "BEF", 40.3399, 0 },
2573 { "DEM", 1.95583, 2 },
2574 { "ESP", 166.386, 0 },
2575 { "FIM", 5.94573, 2 },
2576 { "FRF", 6.55957, 2 },
2577 { "IEP", 0.787564, 2 },
2578 { "ITL", 1936.27, 0 },
2579 { "LUF", 40.3399, 0 },
2580 { "NLG", 2.20371, 2 },
2581 { "PTE", 200.482, 2 },
2582 { "GRD", 340.750, 2 },
2583 { "SIT", 239.640, 2 },
2584 { "MTL", 0.429300, 2 },
2585 { "CYP", 0.585274, 2 },
2586 { "SKK", 30.1260, 2 }
2589 const size_t nConversionCount
= sizeof( aConvertTable
) / sizeof( aConvertTable
[0] );
2590 for ( size_t i
= 0; i
< nConversionCount
; i
++ )
2591 if ( aSearchUnit
.EqualsIgnoreCaseAscii( aConvertTable
[i
].pCurrText
) )
2593 rfRate
= aConvertTable
[i
].fRate
;
2594 rnDec
= aConvertTable
[i
].nDec
;
2600 void ScInterpreter::ScEuroConvert()
2601 { //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]]
2602 BYTE nParamCount
= GetByte();
2603 if ( MustHaveParamCount( nParamCount
, 3, 5 ) )
2605 double nPrecision
= 0.0;
2606 if ( nParamCount
== 5 )
2608 nPrecision
= ::rtl::math::approxFloor(GetDouble());
2609 if ( nPrecision
< 3 )
2611 PushIllegalArgument();
2615 BOOL bFullPrecision
= FALSE
;
2616 if ( nParamCount
>= 4 )
2617 bFullPrecision
= GetBool();
2618 String
aToUnit( GetString() );
2619 String
aFromUnit( GetString() );
2620 double fVal
= GetDouble();
2622 PushError( nGlobalError
);
2630 String
aEur( RTL_CONSTASCII_USTRINGPARAM("EUR"));
2631 if ( lclConvertMoney( aFromUnit
, fFromRate
, nFromDec
)
2632 && lclConvertMoney( aToUnit
, fToRate
, nToDec
) )
2634 if ( aFromUnit
.EqualsIgnoreCaseAscii( aToUnit
) )
2638 if ( aFromUnit
.EqualsIgnoreCaseAscii( aEur
) )
2639 fRes
= fVal
* fToRate
;
2642 double fIntermediate
= fVal
/ fFromRate
;
2644 fIntermediate
= ::rtl::math::round( fIntermediate
,
2646 fRes
= fIntermediate
* fToRate
;
2648 if ( !bFullPrecision
)
2649 fRes
= ::rtl::math::round( fRes
, nToDec
);
2654 PushIllegalArgument();
2660 // BAHTTEXT ===================================================================
2662 #define UTF8_TH_0 "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214"
2663 #define UTF8_TH_1 "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207"
2664 #define UTF8_TH_2 "\340\270\252\340\270\255\340\270\207"
2665 #define UTF8_TH_3 "\340\270\252\340\270\262\340\270\241"
2666 #define UTF8_TH_4 "\340\270\252\340\270\265\340\271\210"
2667 #define UTF8_TH_5 "\340\270\253\340\271\211\340\270\262"
2668 #define UTF8_TH_6 "\340\270\253\340\270\201"
2669 #define UTF8_TH_7 "\340\271\200\340\270\210\340\271\207\340\270\224"
2670 #define UTF8_TH_8 "\340\271\201\340\270\233\340\270\224"
2671 #define UTF8_TH_9 "\340\271\200\340\270\201\340\271\211\340\270\262"
2672 #define UTF8_TH_10 "\340\270\252\340\270\264\340\270\232"
2673 #define UTF8_TH_11 "\340\271\200\340\270\255\340\271\207\340\270\224"
2674 #define UTF8_TH_20 "\340\270\242\340\270\265\340\271\210"
2675 #define UTF8_TH_1E2 "\340\270\243\340\271\211\340\270\255\340\270\242"
2676 #define UTF8_TH_1E3 "\340\270\236\340\270\261\340\270\231"
2677 #define UTF8_TH_1E4 "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231"
2678 #define UTF8_TH_1E5 "\340\271\201\340\270\252\340\270\231"
2679 #define UTF8_TH_1E6 "\340\270\245\340\271\211\340\270\262\340\270\231"
2680 #define UTF8_TH_DOT0 "\340\270\226\340\271\211\340\270\247\340\270\231"
2681 #define UTF8_TH_BAHT "\340\270\232\340\270\262\340\270\227"
2682 #define UTF8_TH_SATANG "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214"
2683 #define UTF8_TH_MINUS "\340\270\245\340\270\232"
2685 #define UTF8_STRINGPARAM( ascii ) ascii, static_cast< xub_StrLen >( sizeof( ascii ) - 1 )
2686 #define UTF8_CREATE( ascii ) ByteString( UTF8_STRINGPARAM( ascii ) )
2687 #define UTF8_APPEND( ascii ) Append( UTF8_STRINGPARAM( ascii ) )
2688 #define UTF8_PREPEND( ascii ) Insert( UTF8_CREATE( ascii ), 0 )
2690 // local functions ------------------------------------------------------------
2694 inline void lclSplitBlock( double& rfInt
, sal_Int32
& rnBlock
, double fValue
, double fSize
)
2696 rnBlock
= static_cast< sal_Int32
>( modf( (fValue
+ 0.1) / fSize
, &rfInt
) * fSize
+ 0.1 );
2699 /** Appends a digit (0 to 9) to the passed string. */
2700 void lclAppendDigit( ByteString
& rText
, sal_Int32 nDigit
)
2704 case 0: rText
.UTF8_APPEND( UTF8_TH_0
); break;
2705 case 1: rText
.UTF8_APPEND( UTF8_TH_1
); break;
2706 case 2: rText
.UTF8_APPEND( UTF8_TH_2
); break;
2707 case 3: rText
.UTF8_APPEND( UTF8_TH_3
); break;
2708 case 4: rText
.UTF8_APPEND( UTF8_TH_4
); break;
2709 case 5: rText
.UTF8_APPEND( UTF8_TH_5
); break;
2710 case 6: rText
.UTF8_APPEND( UTF8_TH_6
); break;
2711 case 7: rText
.UTF8_APPEND( UTF8_TH_7
); break;
2712 case 8: rText
.UTF8_APPEND( UTF8_TH_8
); break;
2713 case 9: rText
.UTF8_APPEND( UTF8_TH_9
); break;
2714 default: DBG_ERRORFILE( "lclAppendDigit - illegal digit" );
2718 /** Appends a value raised to a power of 10: nDigit*10^nPow10.
2719 @param nDigit A digit in the range from 1 to 9.
2720 @param nPow10 A value in the range from 2 to 5.
2722 void lclAppendPow10( ByteString
& rText
, sal_Int32 nDigit
, sal_Int32 nPow10
)
2724 DBG_ASSERT( (1 <= nDigit
) && (nDigit
<= 9), "lclAppendPow10 - illegal digit" );
2725 lclAppendDigit( rText
, nDigit
);
2728 case 2: rText
.UTF8_APPEND( UTF8_TH_1E2
); break;
2729 case 3: rText
.UTF8_APPEND( UTF8_TH_1E3
); break;
2730 case 4: rText
.UTF8_APPEND( UTF8_TH_1E4
); break;
2731 case 5: rText
.UTF8_APPEND( UTF8_TH_1E5
); break;
2732 default: DBG_ERRORFILE( "lclAppendPow10 - illegal power" );
2736 /** Appends a block of 6 digits (value from 1 to 999,999) to the passed string. */
2737 void lclAppendBlock( ByteString
& rText
, sal_Int32 nValue
)
2739 DBG_ASSERT( (1 <= nValue
) && (nValue
<= 999999), "lclAppendBlock - illegal value" );
2740 if( nValue
>= 100000 )
2742 lclAppendPow10( rText
, nValue
/ 100000, 5 );
2745 if( nValue
>= 10000 )
2747 lclAppendPow10( rText
, nValue
/ 10000, 4 );
2750 if( nValue
>= 1000 )
2752 lclAppendPow10( rText
, nValue
/ 1000, 3 );
2757 lclAppendPow10( rText
, nValue
/ 100, 2 );
2762 sal_Int32 nTen
= nValue
/ 10;
2763 sal_Int32 nOne
= nValue
% 10;
2767 lclAppendDigit( rText
, nTen
);
2768 else if( nTen
== 2 )
2769 rText
.UTF8_APPEND( UTF8_TH_20
);
2770 rText
.UTF8_APPEND( UTF8_TH_10
);
2772 if( (nTen
> 0) && (nOne
== 1) )
2773 rText
.UTF8_APPEND( UTF8_TH_11
);
2775 lclAppendDigit( rText
, nOne
);
2781 // ----------------------------------------------------------------------------
2783 void ScInterpreter::ScBahtText()
2785 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScBahtText" );
2786 BYTE nParamCount
= GetByte();
2787 if ( MustHaveParamCount( nParamCount
, 1 ) )
2789 double fValue
= GetDouble();
2792 PushError( nGlobalError
);
2797 bool bMinus
= fValue
< 0.0;
2798 fValue
= fabs( fValue
);
2800 // round to 2 digits after decimal point, fValue contains Satang as integer
2801 fValue
= ::rtl::math::approxFloor( fValue
* 100.0 + 0.5 );
2803 // split Baht and Satang
2805 sal_Int32 nSatang
= 0;
2806 lclSplitBlock( fBaht
, nSatang
, fValue
, 100.0 );
2810 // generate text for Baht value
2814 aText
.UTF8_APPEND( UTF8_TH_0
);
2816 else while( fBaht
> 0.0 )
2819 sal_Int32 nBlock
= 0;
2820 lclSplitBlock( fBaht
, nBlock
, fBaht
, 1.0e6
);
2822 lclAppendBlock( aBlock
, nBlock
);
2823 // add leading "million", if there will come more blocks
2825 aBlock
.UTF8_PREPEND( UTF8_TH_1E6
);
2826 aText
.Insert( aBlock
, 0 );
2828 if( aText
.Len() > 0 )
2829 aText
.UTF8_APPEND( UTF8_TH_BAHT
);
2831 // generate text for Satang value
2834 aText
.UTF8_APPEND( UTF8_TH_DOT0
);
2838 lclAppendBlock( aText
, nSatang
);
2839 aText
.UTF8_APPEND( UTF8_TH_SATANG
);
2842 // add the minus sign
2844 aText
.UTF8_PREPEND( UTF8_TH_MINUS
);
2846 PushString( String( aText
, RTL_TEXTENCODING_UTF8
) );
2850 // ============================================================================
2852 void ScInterpreter::ScPhoneticString()
2854 BYTE nParamCount
= GetByte();
2855 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
2857 String aPhoneticText
;
2858 while( nParamCount
-- )
2862 PushError(nGlobalError
);
2866 switch ( GetStackType() )
2871 PopSingleRef( aAdr
);
2874 PushError(nGlobalError
);
2878 ScBaseCell
* pCell
= GetCell( aAdr
);
2879 if ( HasCellStringData( pCell
) )
2882 GetCellPhoneticString( aStr
, pCell
);
2883 aPhoneticText
+= aStr
;
2890 PopDoubleRef( aRange
);
2893 PushError(nGlobalError
);
2897 ScCellIterator
aIter( pDok
, aRange
);
2898 ScBaseCell
*pCell
= aIter
.GetFirst();
2901 if ( HasCellStringData( pCell
) )
2904 GetCellPhoneticString( aStr
, pCell
);
2905 aPhoneticText
+= aStr
;
2907 pCell
= aIter
.GetNext();
2912 PushError(errIllegalParameter
);
2916 PushString( aPhoneticText
);
2920 // ============================================================================
2922 void ScInterpreter::ScGetPivotData()
2924 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGetPivotData" );
2925 BYTE nParamCount
= GetByte();
2927 if ( MustHaveParamCount( nParamCount
, 2, 30 ) )
2929 // there must be an even number of args
2930 // target, ref, then field/item pairs
2931 if( (nParamCount
% 2) == 1)
2934 bool bOldSyntax
= false;
2935 if ( nParamCount
== 2 )
2937 // if the first parameter is a ref, assume old syntax
2938 StackVar eFirstType
= GetStackType( 2 );
2939 if ( eFirstType
== svSingleRef
|| eFirstType
== svDoubleRef
)
2943 ScDPGetPivotDataField aTarget
; // target field, and returns result
2944 std::vector
< ScDPGetPivotDataField
> aFilters
;
2947 aFilterList
= GetString(); // old syntax: second parameter is list of constraints
2950 // new syntax: separate name/value pairs
2952 USHORT nFilterCount
= nParamCount
/ 2 - 1;
2953 aFilters
.resize( nFilterCount
);
2955 USHORT i
= nFilterCount
;
2958 //! should allow numeric constraint values
2959 aFilters
[i
].mbValIsStr
= TRUE
;
2960 aFilters
[i
].maValStr
= GetString();
2962 aFilters
[i
].maFieldName
= GetString();
2966 // common to both syntaxes: a reference to the data pilot table
2969 switch ( GetStackType() )
2972 PopDoubleRef( aBlock
);
2978 PopSingleRef( aAddr
);
2985 // NOTE : MS Excel docs claim to use the 'most recent' which is not
2986 // exactly the same as what we do in ScDocument::GetDPAtBlock
2987 // However we do need to use GetDPABlock
2988 ScDPObject
* pDPObj
= pDok
->GetDPAtBlock ( aBlock
);
2994 // fill aFilters / aTarget from aFilterList string
2995 if ( !pDPObj
->ParseFilters( aTarget
, aFilters
, aFilterList
) )
2999 aTarget
.maFieldName
= GetString(); // new syntax: first parameter is data field name
3001 if( pDPObj
->GetPivotData( aTarget
, aFilters
) )
3003 if( aTarget
.mbValIsStr
)
3004 PushString( aTarget
.maValStr
);
3006 PushDouble( aTarget
.mnValNum
);
3012 PushError( errNoRef
);