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::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.
81 nY
= nYear
, nM
= nMonth
, nD
= nDay
;
86 nY
= nYear
+ (nMonth
-1) / 12;
87 nM
= ((nMonth
-1) % 12) + 1;
91 nY
= nYear
+ (nMonth
-12) / 12;
92 nM
= 12 - (-nMonth
) % 12;
96 Date
aDate( nD
, nM
, nY
);
100 return (double) (aDate
- *(pFormatter
->GetNullDate()));
103 SetError(errNoValue
);
108 //-----------------------------------------------------------------------------
110 //-----------------------------------------------------------------------------
112 void ScInterpreter::ScGetActDate()
114 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScGetActDate" );
115 nFuncFmtType
= NUMBERFORMAT_DATE
;
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
;
126 long nDiff
= aActDate
- *(pFormatter
->GetNullDate());
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.
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
));
198 PushIllegalArgument();
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 ) )
211 if (nParamCount
== 2)
212 nFlag
= (short) ::rtl::math::approxFloor(GetDouble());
216 Date aDate
= *(pFormatter
->GetNullDate());
217 aDate
+= (long)::rtl::math::approxFloor(GetDouble());
218 int nVal
= (int) aDate
.GetDayOfWeek();
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() );
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
;
258 B
= int(nYear
/ 100);
262 F
= int((B
+ 8) / 25);
263 G
= int((B
- F
+ 1) / 3);
264 H
= (19 * N
+ B
- D
- G
+ 15) % 30;
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());
286 PushIllegalArgument();
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:
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 ) )
350 if (nParamCount
== 3)
354 double nDate2
= GetDouble();
355 double nDate1
= GetDouble();
358 PushError( nGlobalError
);
361 // #i84934# only for non-US European algorithm swap dates. Else
362 // follow Excel's meaningless extrapolation for "interoperability".
363 if (bFlag
&& (nDate2
< nDate1
))
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)
380 if (aDate1
.GetMonth() == 2)
382 switch ( aDate1
.GetDay() )
385 if ( !aDate1
.IsLeapYear() )
394 if (aDate2
.GetDay() == 31)
398 if (aDate1
.GetDay() == 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.
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
);
429 PushIllegalArgument();
432 PushIllegalArgument();
435 void ScInterpreter::ScPlusMinus()
437 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScPlusMinus" );
438 double nVal
= GetDouble();
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 ) )
467 if (nParamCount
== 1)
468 fVal
= ::rtl::math::round( GetDouble(), 0, eMode
);
471 INT32 nDec
= (INT32
) ::rtl::math::approxFloor(GetDouble());
472 if( nDec
< -20 || nDec
> 20 )
473 PushIllegalArgument();
475 fVal
= ::rtl::math::round( GetDouble(), (short)nDec
, eMode
);
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();
510 else if (fVal
*fDec
< 0.0)
511 PushIllegalArgument();
514 if ( !bAbs
&& fVal
< 0.0 )
515 PushDouble(::rtl::math::approxFloor(fVal
/fDec
) * fDec
);
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();
533 else if (fVal
*fDec
< 0.0)
534 PushIllegalArgument();
537 if ( !bAbs
&& fVal
< 0.0 )
538 PushDouble(::rtl::math::approxCeil(fVal
/fDec
) * fDec
);
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();
550 PushDouble(::rtl::math::approxFloor(fVal
/2.0) * 2.0);
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();
561 fVal
= ::rtl::math::approxCeil(fVal
);
562 if (fmod(fVal
, 2.0) == 0.0)
567 fVal
= ::rtl::math::approxFloor(fVal
);
568 if (fmod(fVal
, 2.0) == 0.0)
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 ) )
592 if (nParamCount
== 2)
596 double nVal
= GetDouble();
597 if (nVal
> 0.0 && nBase
> 0.0 && nBase
!= 1.0)
598 PushDouble(log(nVal
) / log(nBase
));
600 PushIllegalArgument();
604 void ScInterpreter::ScLn()
606 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLn" );
607 double fVal
= GetDouble();
609 PushDouble(log(fVal
));
611 PushIllegalArgument();
614 void ScInterpreter::ScLog10()
616 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLog10" );
617 double fVal
= GetDouble();
619 PushDouble(log10(fVal
));
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 ) )
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)
640 double nZins
= GetDouble();
642 size_t nRefInList
= 0;
644 while (nParamCount
-- > 0)
646 switch (GetStackType())
650 nVal
+= (GetDouble() / pow(1.0 + nZins
, (double)nCount
));
656 nVal
+= (GetDouble() / pow(1.0 + nZins
, (double)nCount
));
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
));
671 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
673 nVal
+= (nCellVal
/ pow(1.0 + nZins
, (double)nCount
));
680 default : SetError(errIllegalParameter
); break;
688 #if defined(WIN) && defined(MSC)
689 #pragma optimize("",off)
692 void ScInterpreter::ScIRR()
694 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIRR" );
696 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
697 BYTE nParamCount
= GetByte();
698 if ( !MustHaveParamCount( nParamCount
, 1, 2 ) )
700 if (nParamCount
== 2)
701 fSchaetzwert
= GetDouble();
704 USHORT sPos
= sp
; // Stack-Position merken
706 double x
, xNeu
, fWert
, fZaehler
, fNenner
, nCount
;
707 if (fSchaetzwert
== -1.0)
708 x
= 0.1; // default gegen Nulldivisionen
710 x
= fSchaetzwert
; // Startwert
711 switch (GetStackType())
717 PushIllegalParameter();
721 const USHORT nIterationsMax
= 20;
724 while (fEps
> SCdEpsilon
&& nItCount
< nIterationsMax
)
725 { // Newton-Verfahren:
726 sp
= sPos
; // Stack zuruecksetzen
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);
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);
746 xNeu
= x
- fZaehler
/ fNenner
; // x(i+1) = x(i)-f(x(i))/f'(x(i))
748 fEps
= fabs(xNeu
- x
);
751 if (fSchaetzwert
== 0.0 && fabs(x
) < SCdEpsilon
)
752 x
= 0.0; // auf Null normieren
753 if (fEps
< SCdEpsilon
)
756 PushError( errNoConvergence
);
758 #if defined(WIN) && defined(MSC)
759 #pragma optimize("",on)
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;
777 PopDoubleRef( aRange
);
780 PushError( nGlobalError
);
783 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
);
786 USHORT nIterError
= 0;
788 BOOL bLoop
= aValIter
.GetFirst( fCellValue
, nIterError
);
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
;
799 bLoop
= aValIter
.GetNext( fCellValue
, nIterError
);
802 PushError( nIterError
);
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();
825 PushError( nGlobalError
);
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" );
840 fBw
= fZw
+ fRmz
* fZzr
;
842 fBw
= (fZw
* pow(1.0 + fZins
, -fZzr
))
843 + (fRmz
* (1.0 - pow(1.0 + fZins
, -fZzr
+ 1.0)) / fZins
)
846 fBw
= (fZw
* pow(1.0 + fZins
, -fZzr
))
847 + (fRmz
* (1.0 - pow(1.0 + fZins
, -fZzr
)) / fZins
);
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 ) )
859 if (nParamCount
== 5)
861 if (nParamCount
>= 4)
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);
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
;
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
;
906 fGda
= fAlterWert
- fNeuerWert
;
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 ) )
920 if (nParamCount
== 5)
921 nFaktor
= GetDouble();
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();
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 ) )
944 if (nParamCount
== 4)
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();
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;
962 if (::rtl::math::approxFloor(nPeriode
) == 1)
963 nGda2
= nErsteAbRate
;
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;
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" );
987 double fIntEnd
= ::rtl::math::approxCeil(fPeriode
);
988 ULONG nLoopEnd
= (ULONG
) fIntEnd
;
991 double fRestwert
= fWert
- fRest
;
992 BOOL bNowLia
= FALSE
;
997 for ( i
= 1; i
<= nLoopEnd
; i
++)
1001 fGda
= ScGetGDA(fWert
, fRest
, fDauer
, (double) i
, fFaktor
);
1002 fLia
= fRestwert
/ (fDauer1
- (double) (i
-1));
1021 fTerm
*= ( fPeriode
+ 1.0 - fIntEnd
);
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;
1043 if (nParamCount
== 7)
1047 if (nParamCount
>= 6)
1048 fFaktor
= GetDouble();
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();
1061 double fIntStart
= ::rtl::math::approxFloor(fAnfang
);
1062 double fIntEnd
= ::rtl::math::approxCeil(fEnde
);
1063 ULONG nLoopStart
= (ULONG
) fIntStart
;
1064 ULONG nLoopEnd
= (ULONG
) fIntEnd
;
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
);
1085 double fDauer1
=fDauer
;
1088 //@Die Frage aller Fragen: "Ist das hier richtig"
1089 if(!::rtl::math::approxEqual(fAnfang
,::rtl::math::approxFloor(fAnfang
)))
1093 if(fAnfang
>fDauer
/2 || ::rtl::math::approxEqual(fAnfang
,fDauer
/2))
1095 fPart
=fAnfang
-fDauer
/2;
1103 fWert
-=ScInterVDB(fWert
,fRest
,fDauer
,fDauer1
,fAnfang
,fFaktor
);
1104 fVdb
=ScInterVDB(fWert
,fRest
,fDauer
,fDauer
-fAnfang
,fEnde
-fAnfang
,fFaktor
);
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" );
1142 fRmz
= (fBw
+ fZw
) / fZzr
;
1145 double fTerm
= pow(1.0 + fZins
, fZzr
);
1147 fRmz
= (fZw
* fZins
/ (fTerm
- 1.0)
1148 + fBw
* fZins
/ (1.0 - 1.0 / fTerm
)) / (1.0+fZins
);
1150 fRmz
= fZw
* fZins
/ (fTerm
- 1.0)
1151 + fBw
* fZins
/ (1.0 - 1.0 / fTerm
);
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 ) )
1164 if (nParamCount
== 5)
1165 nFlag
= GetDouble();
1166 if (nParamCount
>= 4)
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" );
1193 fZw
= fBw
+ fRmz
* fZzr
;
1196 double fTerm
= pow(1.0 + fZins
, fZzr
);
1198 fZw
= fBw
* fTerm
+ fRmz
*(1.0 + fZins
)*(fTerm
- 1.0)/fZins
;
1200 fZw
= fBw
* fTerm
+ fRmz
*(fTerm
- 1.0)/fZins
;
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 ) )
1213 if (nParamCount
== 5)
1214 nFlag
= GetDouble();
1215 if (nParamCount
>= 4)
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 ) )
1230 if (nParamCount
== 5)
1231 nFlag
= GetDouble();
1232 if (nParamCount
>= 4)
1236 nZins
= GetDouble();
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
)))
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;
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
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))
1275 fGeoSeriesDerivation
= fNper
* (fNper
-1.0)/2.0;
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
1288 if (rtl::math::approxEqual( fabs(fTermDerivation
), 0.0))
1289 fXnew
= fX
+ 1.1 * SCdEpsilon
; // move away from zero slope
1291 fXnew
= fX
- fTerm
/ fTermDerivation
;
1293 // more accuracy not possible in oscillating cases
1294 bFound
= (fabs(fXnew
- fX
) < SCdEpsilon
);
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
1301 //bValid =(fX >=-1.0);
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))
1311 fGeoSeriesDerivation
= fNper
* (fNper
-1.0)/2.0;
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
1324 if (rtl::math::approxEqual( fabs(fTermDerivation
), 0.0))
1325 fXnew
= fX
+ 1.1 * SCdEpsilon
; // move away from zero slope
1327 fXnew
= fX
- fTerm
/ fTermDerivation
;
1329 // more accuracy not possible in oscillating cases
1330 bFound
= (fabs(fXnew
- fX
) < SCdEpsilon
);
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;
1348 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1349 BYTE nParamCount
= GetByte();
1350 if ( !MustHaveParamCount( nParamCount
, 3, 6 ) )
1352 if (nParamCount
== 6)
1353 fGuess
= GetDouble();
1354 if (nParamCount
>= 5)
1355 fPayType
= GetDouble();
1356 if (nParamCount
>= 4)
1359 fPayment
= GetDouble();
1360 fNper
= GetDouble();
1361 if (fNper
<= 0.0) // constraint from ODFF spec
1363 PushIllegalArgument();
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
);
1371 SetError(errNoConvergence
);
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
1381 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1392 fZinsZ
= ScGetZw(fZins
, fZr
-2.0, fRmz
, fBw
, 1.0) - fRmz
;
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 ) )
1407 if (nParamCount
== 6)
1408 nFlag
= GetDouble();
1409 if (nParamCount
>= 5)
1414 nZins
= GetDouble();
1415 if (nZr
< 1.0 || nZr
> nZzr
)
1416 PushIllegalArgument();
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 ) )
1429 if (nParamCount
== 6)
1430 nFlag
= GetDouble();
1431 if (nParamCount
>= 5)
1436 nZins
= GetDouble();
1437 if (nZr
< 1.0 || nZr
> nZzr
)
1438 PushIllegalArgument();
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
;
1454 fEnde
= ::rtl::math::approxFloor(GetDouble());
1455 fAnfang
= ::rtl::math::approxFloor(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();
1464 ULONG nAnfang
= (ULONG
) fAnfang
;
1465 ULONG nEnde
= (ULONG
) fEnde
;
1466 fRmz
= ScGetRmz(fZins
, fZzr
, fBw
, 0.0, fF
);
1474 for (ULONG i
= nAnfang
; i
<= nEnde
; i
++)
1477 fZinsZ
+= ScGetZw(fZins
, (double)(i
-2), fRmz
, fBw
, 1.0) - fRmz
;
1479 fZinsZ
+= ScGetZw(fZins
, (double)(i
-1), fRmz
, fBw
, 0.0);
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
;
1495 fEnde
= ::rtl::math::approxFloor(GetDouble());
1496 fAnfang
= ::rtl::math::approxFloor(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();
1505 fRmz
= ScGetRmz(fZins
, fZzr
, fBw
, 0.0, fF
);
1507 ULONG nAnfang
= (ULONG
) fAnfang
;
1508 ULONG nEnde
= (ULONG
) fEnde
;
1512 fKapZ
= fRmz
+ fBw
* fZins
;
1517 for (ULONG i
= nAnfang
; i
<= nEnde
; i
++)
1520 fKapZ
+= fRmz
- (ScGetZw(fZins
, (double)(i
-2), fRmz
, fBw
, 1.0) - fRmz
) * fZins
;
1522 fKapZ
+= fRmz
- ScGetZw(fZins
, (double)(i
-1), fRmz
, fBw
, 0.0) * fZins
;
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();
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();
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)))
1578 PushDouble( fResult
);
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)
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;
1630 pNote
= pVCell
? pVCell
->ReleaseNote() : 0;
1632 pVCell
= new ScValueCell( fSaveVal
);
1633 pDok
->PutCell( aValueAdr
, pVCell
);
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
;
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 );
1695 while( nIdx
++ < 2 && !bDoneHorMove
)
1699 fHorX
= fX
+ fabs(fF
)*fHorTangent
;
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
)
1710 fF
= pFormula
->GetValue() - fTargetVal
;
1714 bDoneHorMove
= TRUE
;
1718 if ( !bDoneHorMove
)
1719 bHorMoveError
= TRUE
;
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
;
1730 else if ( bHorMoveError
)
1732 else if ( fabs(fF
) < fDelta
)
1734 // converged to root
1736 bDoneIteration
= TRUE
;
1740 if ( fabs(fF
) + fDelta
< fBestF
)
1746 if ( ( fXPrev
- fX
) != 0 )
1748 fSlope
= ( fFPrev
- fF
) / ( fXPrev
- fX
);
1749 if ( fabs( fSlope
) < fEps
)
1750 fSlope
= fSlope
< 0.0 ? -fEps
: fEps
;
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
) )
1774 else if ( bError
|| bHorMoveError
)
1780 pVCell
= pNote
? new ScNoteCell( pNote
) : 0;
1781 pDok
->PutCell( aValueAdr
, pVCell
);
1784 pValue
->SetValue( fSaveVal
);
1785 pDok
->SetDirty( aVRange
);
1786 pFormula
->Interpret();
1787 if ( !bDoneIteration
)
1788 SetError(NOTAVAILABLE
);
1793 if ( !bDoneIteration
)
1794 SetError(NOTAVAILABLE
);
1795 PushInt(0); // falsche Zelltypen
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();
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();
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());
1864 const ScSingleRefData
& r11
= (*it1
).Ref1
;
1865 const ScSingleRefData
& r12
= (*it1
).Ref2
;
1866 for (ScRefList::const_iterator
it2( x2
->GetRefList()->begin());
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
)
1881 ScComplexRefData aRef
;
1882 aRef
.InitRange( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
1883 pRefList
->push_back( aRef
);
1887 size_t n
= pRefList
->size();
1889 PushError( errNoRef
);
1892 const ScComplexRefData
& rRef
= (*pRefList
)[0];
1893 if (rRef
.Ref1
== rRef
.Ref2
)
1894 PushTempToken( new ScSingleRefToken( rRef
.Ref1
));
1896 PushTempToken( new ScDoubleRefToken( rRef
));
1899 PushTempToken( xRes
);
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
)
1914 pt
[i
]->CalcAbsIfRel( aPos
);
1916 const ScSingleRefData
& r
= pt
[i
]->GetSingleRef();
1921 if (sv
[i
] == svDoubleRef
)
1923 const ScSingleRefData
& r
= pt
[i
]->GetSingleRef2();
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
);
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();
1965 } // if (nGlobalError || !xT2 || !xT1)
1966 FormulaTokenRef xRes
= ScToken::ExtendRangeReference( *x1
, *x2
, aPos
, false);
1968 PushIllegalArgument();
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();
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();
1995 ScToken
* x1
= static_cast<ScToken
*>(p1st
.get());
1996 ScToken
* x2
= static_cast<ScToken
*>(p2nd
.get());
2000 // Append to an existing RefList if there is one.
2001 if (sv1
== svRefList
)
2004 sv1
= svUnknown
; // mark as handled
2006 else if (sv2
== svRefList
)
2009 sv2
= svUnknown
; // mark as handled
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
)
2024 ScComplexRefData aRef
;
2025 aRef
.Ref1
= aRef
.Ref2
= pt
[i
]->GetSingleRef();
2026 pRes
->push_back( aRef
);
2030 pRes
->push_back( pt
[i
]->GetDoubleRef());
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
);
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());
2058 PushTempToken( xTok
);
2059 PushTempToken( xTok
);
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
2083 // Request ausfuehren, um Vorlage anzuwenden
2086 if ( !pDok
->IsClipOrUndo() )
2088 SfxObjectShell
* pShell
= pDok
->GetDocumentShell();
2091 //! notify object shell directly
2093 ScRange
aRange(aPos
);
2094 ScAutoStyleHint
aHint( aRange
, aStyle1
, nTimeOut
, aStyle2
);
2095 pShell
->Broadcast( aHint
);
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
)
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();
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 );
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();
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
);
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);
2206 const ScMatrix
* pLinkMat
= pLink
->GetResult();
2210 pLinkMat
->GetDimensions(nC
, nR
);
2211 ScMatrixRef pNewMat
= GetNewMat( nC
, nR
);
2214 pLinkMat
->MatCopy(*pNewMat
); // kopieren
2215 PushMatrix( pNewMat
);
2218 PushIllegalArgument();
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;
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 )
2248 nMinLen
= 0; // Error
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) :
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
)
2270 sal_Unicode
* p
= pBuf
+ nBuf
- 1;
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
];
2281 fVal
= (double) nVal
;
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
;
2314 { // da ist was gekippt
2320 double fDig
= ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal
, fMult
) );
2328 else if ( fDig
>= fBase
)
2329 nDig
= ((size_t) fBase
) - 1;
2331 nDig
= (size_t) fDig
;
2333 *--p
= pDigits
[ nDig
];
2338 PushError( errStringOverflow
);
2341 if ( nBuf
- (p
- pBuf
) <= nMinLen
)
2342 p
= pBuf
+ nBuf
- 1 - nMinLen
;
2343 PushStringBuffer( p
);
2349 PushIllegalArgument();
2354 void ScInterpreter::ScDecimal()
2356 if ( MustHaveParamCount( GetByte(), 2 ) )
2358 double fBase
= ::rtl::math::approxFloor( GetDouble() );
2359 String
aStr( GetString() );
2360 if ( !nGlobalError
&& 2 <= fBase
&& fBase
<= 36 )
2363 int nBase
= (int) fBase
;
2364 register const sal_Unicode
* p
= aStr
.GetBuffer();
2365 while ( *p
== ' ' || *p
== '\t' )
2366 p
++; // strip leading white space
2368 { // evtl. hex-prefix strippen
2369 if ( *p
== 'x' || *p
== 'X' )
2371 else if ( *p
== '0' && (*(p
+1) == 'x' || *(p
+1) == 'X') )
2377 if ( '0' <= *p
&& *p
<= '9' )
2379 else if ( 'A' <= *p
&& *p
<= 'Z' )
2380 n
= 10 + (*p
- 'A');
2381 else if ( 'a' <= *p
&& *p
<= 'z' )
2382 n
= 10 + (*p
- 'a');
2388 ( (nBase
== 2 && (*p
== 'b' || *p
== 'B'))
2389 ||(nBase
== 16 && (*p
== 'h' || *p
== 'H')) )
2391 ; // 101b und F00Dh sind ok
2394 PushIllegalArgument();
2399 fVal
= fVal
* fBase
+ n
;
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();
2419 PushError( nGlobalError
);
2421 { // erst die angegebene Reihenfolge suchen, wenn nicht gefunden den Kehrwert
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
);
2434 void ScInterpreter::ScRoman()
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() );
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);
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;
2462 while( (nSteps
< nMode
) && (nIndex
< nMaxIndex
) )
2465 if( pValues
[ nIndex2
] - pValues
[ nIndex
+ 1 ] <= nVal
)
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
] );
2478 aRoman
+= pChars
[ nIndex
- 1 ];
2479 aRoman
.Expand( aRoman
.Len() + (nDigit
% 5), pChars
[ nIndex
] );
2480 nVal
%= pValues
[ nIndex
];
2484 PushString( aRoman
);
2487 PushIllegalArgument();
2492 BOOL
lcl_GetArabicValue( sal_Unicode cChar
, USHORT
& rnValue
, BOOL
& rbIsDec
)
2494 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScBase" );
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
;
2510 void ScInterpreter::ScArabic()
2512 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScArabic" );
2513 String
aRoman( GetString() );
2515 PushError( nGlobalError
);
2518 aRoman
.ToUpperAscii();
2521 USHORT nValidRest
= 3999;
2522 USHORT nCharIndex
= 0;
2523 USHORT nCharCount
= aRoman
.Len();
2526 while( bValid
&& (nCharIndex
< nCharCount
) )
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
);
2537 if( nDigit1
>= nDigit2
)
2539 nValue
= sal::static_int_cast
<USHORT
>( nValue
+ nDigit1
);
2540 nValidRest
%= (nDigit1
* (bIsDec1
? 5 : 2));
2541 bValid
= (nValidRest
>= nDigit1
);
2543 nValidRest
= sal::static_int_cast
<USHORT
>( nValidRest
- nDigit1
);
2546 else if( nDigit1
* 2 != nDigit2
)
2548 USHORT nDiff
= nDigit2
- nDigit1
;
2549 nValue
= sal::static_int_cast
<USHORT
>( nValue
+ nDiff
);
2550 bValid
= (nValidRest
>= nDiff
);
2552 nValidRest
= nDigit1
- 1;
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 ) )
2575 ScMatValType nResultType
= SC_MATVAL_STRING
;
2577 if ( nParamCount
== 2 )
2579 switch ( GetStackType() )
2583 nResultType
= SC_MATVAL_VALUE
;
2592 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2594 ScBaseCell
* pCell
= GetCell( aAdr
);
2595 if (HasCellEmptyData( pCell
))
2596 nResultType
= SC_MATVAL_EMPTY
;
2599 USHORT nErr
= GetCellErrCode( pCell
);
2602 else if (HasCellValueData( pCell
))
2604 fVal
= GetCellValue( aAdr
, pCell
);
2605 nResultType
= SC_MATVAL_VALUE
;
2608 GetCellString( aStr
, pCell
);
2613 nResultType
= GetDoubleOrStringFromMatrix( fVal
, aStr
);
2620 nResultType
= SC_MATVAL_VALUE
;
2624 SetError( errIllegalArgument
);
2627 String aUrl
= GetString();
2628 ScMatrixRef pResMat
= GetNewMat( 1, 2);
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 );
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
)
2656 const sal_Char
* pCurrText
;
2660 ConvertInfo aConvertTable
[] = {
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
;
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();
2706 BOOL bFullPrecision
= FALSE
;
2707 if ( nParamCount
>= 4 )
2708 bFullPrecision
= GetBool();
2709 String
aToUnit( GetString() );
2710 String
aFromUnit( GetString() );
2711 double fVal
= GetDouble();
2713 PushError( nGlobalError
);
2721 String
aEur( RTL_CONSTASCII_USTRINGPARAM("EUR"));
2722 if ( lclConvertMoney( aFromUnit
, fFromRate
, nFromDec
)
2723 && lclConvertMoney( aToUnit
, fToRate
, nToDec
) )
2725 if ( aFromUnit
.EqualsIgnoreCaseAscii( aToUnit
) )
2729 if ( aFromUnit
.EqualsIgnoreCaseAscii( aEur
) )
2730 fRes
= fVal
* fToRate
;
2733 double fIntermediate
= fVal
/ fFromRate
;
2735 fIntermediate
= ::rtl::math::round( fIntermediate
,
2737 fRes
= fIntermediate
* fToRate
;
2739 if ( !bFullPrecision
)
2740 fRes
= ::rtl::math::round( fRes
, nToDec
);
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 ------------------------------------------------------------
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
)
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
);
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 );
2836 if( nValue
>= 10000 )
2838 lclAppendPow10( rText
, nValue
/ 10000, 4 );
2841 if( nValue
>= 1000 )
2843 lclAppendPow10( rText
, nValue
/ 1000, 3 );
2848 lclAppendPow10( rText
, nValue
/ 100, 2 );
2853 sal_Int32 nTen
= nValue
/ 10;
2854 sal_Int32 nOne
= nValue
% 10;
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
);
2866 lclAppendDigit( rText
, nOne
);
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();
2883 PushError( nGlobalError
);
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
2896 sal_Int32 nSatang
= 0;
2897 lclSplitBlock( fBaht
, nSatang
, fValue
, 100.0 );
2901 // generate text for Baht value
2905 aText
.UTF8_APPEND( UTF8_TH_0
);
2907 else while( fBaht
> 0.0 )
2910 sal_Int32 nBlock
= 0;
2911 lclSplitBlock( fBaht
, nBlock
, fBaht
, 1.0e6
);
2913 lclAppendBlock( aBlock
, nBlock
);
2914 // add leading "million", if there will come more blocks
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
2925 aText
.UTF8_APPEND( UTF8_TH_DOT0
);
2929 lclAppendBlock( aText
, nSatang
);
2930 aText
.UTF8_APPEND( UTF8_TH_SATANG
);
2933 // add the minus sign
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)
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
)
2964 ScDPGetPivotDataField aTarget
; // target field, and returns result
2965 std::vector
< ScDPGetPivotDataField
> aFilters
;
2968 aFilterList
= GetString(); // old syntax: second parameter is list of constraints
2971 // new syntax: separate name/value pairs
2973 USHORT nFilterCount
= nParamCount
/ 2 - 1;
2974 aFilters
.resize( nFilterCount
);
2976 USHORT i
= nFilterCount
;
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
2990 switch ( GetStackType() )
2993 PopDoubleRef( aBlock
);
2999 PopSingleRef( aAddr
);
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
);
3015 // fill aFilters / aTarget from aFilterList string
3016 if ( !pDPObj
->ParseFilters( aTarget
, aFilters
, aFilterList
) )
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
);
3027 PushDouble( aTarget
.mnValNum
);
3033 PushError( errNoRef
);