xref: /AOO41X/main/sc/source/core/tool/interpr2.cxx (revision 535b2a065d2d7970b82ff409ce46f57ad17a813d)
1b3f79822SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3b3f79822SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4b3f79822SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5b3f79822SAndrew Rist  * distributed with this work for additional information
6b3f79822SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7b3f79822SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8b3f79822SAndrew Rist  * "License"); you may not use this file except in compliance
9b3f79822SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11b3f79822SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13b3f79822SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14b3f79822SAndrew Rist  * software distributed under the License is distributed on an
15b3f79822SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16b3f79822SAndrew Rist  * KIND, either express or implied.  See the License for the
17b3f79822SAndrew Rist  * specific language governing permissions and limitations
18b3f79822SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20b3f79822SAndrew Rist  *************************************************************/
21b3f79822SAndrew Rist 
22b3f79822SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sc.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir // INCLUDE ---------------------------------------------------------------
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #include <sfx2/linkmgr.hxx>
30cdf0e10cSrcweir #include <sfx2/dispatch.hxx>
31cdf0e10cSrcweir #include <sfx2/objsh.hxx>
32cdf0e10cSrcweir #include <svl/stritem.hxx>
33cdf0e10cSrcweir #include <svl/zforlist.hxx>
34cdf0e10cSrcweir #include <rtl/logfile.hxx>
35cdf0e10cSrcweir 
36cdf0e10cSrcweir #include "interpre.hxx"
37cdf0e10cSrcweir #include "attrib.hxx"
38cdf0e10cSrcweir #include "sc.hrc"
39cdf0e10cSrcweir #include "ddelink.hxx"
40cdf0e10cSrcweir #include "scmatrix.hxx"
41cdf0e10cSrcweir #include "compiler.hxx"
42cdf0e10cSrcweir #include "cell.hxx"
43cdf0e10cSrcweir #include "document.hxx"
44cdf0e10cSrcweir #include "dociter.hxx"
45cdf0e10cSrcweir #include "docoptio.hxx"
46cdf0e10cSrcweir #include "unitconv.hxx"
47cdf0e10cSrcweir #include "globstr.hrc"
48cdf0e10cSrcweir #include "hints.hxx"
49cdf0e10cSrcweir #include "dpobject.hxx"
50cdf0e10cSrcweir #include "postit.hxx"
51cdf0e10cSrcweir 
52cdf0e10cSrcweir #include <string.h>
53cdf0e10cSrcweir #include <math.h>
54cdf0e10cSrcweir 
5576ea2deeSPedro Giffuni #include <boost/math/special_functions/expm1.hpp>
5676ea2deeSPedro Giffuni #include <boost/math/special_functions/log1p.hpp>
5776ea2deeSPedro Giffuni 
58cdf0e10cSrcweir using namespace formula;
59cdf0e10cSrcweir // STATIC DATA -----------------------------------------------------------
60cdf0e10cSrcweir 
61cdf0e10cSrcweir #define D_TIMEFACTOR              86400.0
62cdf0e10cSrcweir #define SCdEpsilon                1.0E-7
63cdf0e10cSrcweir 
64cdf0e10cSrcweir //-----------------------------------------------------------------------------
65cdf0e10cSrcweir // Datum und Zeit
66cdf0e10cSrcweir //-----------------------------------------------------------------------------
67cdf0e10cSrcweir 
GetDateSerial(sal_Int16 nYear,sal_Int16 nMonth,sal_Int16 nDay,bool bStrict)68cdf0e10cSrcweir double ScInterpreter::GetDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, bool bStrict )
69cdf0e10cSrcweir {
70cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDateSerial" );
71cdf0e10cSrcweir     if ( nYear < 100 && !bStrict )
72cdf0e10cSrcweir         nYear = pFormatter->ExpandTwoDigitYear( nYear );
73cdf0e10cSrcweir     // Do not use a default Date ctor here because it asks system time with a
74cdf0e10cSrcweir     // performance penalty.
75cdf0e10cSrcweir     sal_Int16 nY, nM, nD;
76cdf0e10cSrcweir     if (bStrict)
77cdf0e10cSrcweir         nY = nYear, nM = nMonth, nD = nDay;
78cdf0e10cSrcweir     else
79cdf0e10cSrcweir     {
80cdf0e10cSrcweir         if (nMonth > 0)
81cdf0e10cSrcweir         {
82cdf0e10cSrcweir             nY = nYear + (nMonth-1) / 12;
83cdf0e10cSrcweir             nM = ((nMonth-1) % 12) + 1;
84cdf0e10cSrcweir         }
85cdf0e10cSrcweir         else
86cdf0e10cSrcweir         {
87cdf0e10cSrcweir             nY = nYear + (nMonth-12) / 12;
88cdf0e10cSrcweir             nM = 12 - (-nMonth) % 12;
89cdf0e10cSrcweir         }
90cdf0e10cSrcweir         nD = 1;
91cdf0e10cSrcweir     }
92cdf0e10cSrcweir     Date aDate( nD, nM, nY);
93cdf0e10cSrcweir     if (!bStrict)
94cdf0e10cSrcweir         aDate += nDay - 1;
95cdf0e10cSrcweir     if (aDate.IsValid())
96cdf0e10cSrcweir         return (double) (aDate - *(pFormatter->GetNullDate()));
97cdf0e10cSrcweir     else
98cdf0e10cSrcweir     {
99cdf0e10cSrcweir         SetError(errNoValue);
100cdf0e10cSrcweir         return 0;
101cdf0e10cSrcweir     }
102cdf0e10cSrcweir }
103cdf0e10cSrcweir 
104cdf0e10cSrcweir //-----------------------------------------------------------------------------
105cdf0e10cSrcweir // Funktionen
106cdf0e10cSrcweir //-----------------------------------------------------------------------------
107cdf0e10cSrcweir 
ScGetActDate()108cdf0e10cSrcweir void ScInterpreter::ScGetActDate()
109cdf0e10cSrcweir {
110cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetActDate" );
111cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_DATE;
112cdf0e10cSrcweir     Date aActDate;
113cdf0e10cSrcweir     long nDiff = aActDate - *(pFormatter->GetNullDate());
114cdf0e10cSrcweir     PushDouble((double) nDiff);
115cdf0e10cSrcweir }
116cdf0e10cSrcweir 
ScGetActTime()117cdf0e10cSrcweir void ScInterpreter::ScGetActTime()
118cdf0e10cSrcweir {
119cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetActTime" );
120cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_DATETIME;
121cdf0e10cSrcweir     Date aActDate;
122cdf0e10cSrcweir     long nDiff = aActDate - *(pFormatter->GetNullDate());
123cdf0e10cSrcweir     Time aActTime;
124cdf0e10cSrcweir     double nTime = ((double)aActTime.Get100Sec() / 100 +
125cdf0e10cSrcweir                     (double)(aActTime.GetSec()        +
126cdf0e10cSrcweir                             (aActTime.GetMin()  * 60) +
127cdf0e10cSrcweir                             (aActTime.GetHour() * 3600))) / D_TIMEFACTOR;
128cdf0e10cSrcweir     PushDouble( (double) nDiff + nTime );
129cdf0e10cSrcweir }
130cdf0e10cSrcweir 
ScGetYear()131cdf0e10cSrcweir void ScInterpreter::ScGetYear()
132cdf0e10cSrcweir {
133cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetYear" );
134cdf0e10cSrcweir     Date aDate = *(pFormatter->GetNullDate());
135cdf0e10cSrcweir     aDate += (long) ::rtl::math::approxFloor(GetDouble());
136cdf0e10cSrcweir     PushDouble( (double) aDate.GetYear() );
137cdf0e10cSrcweir }
138cdf0e10cSrcweir 
ScGetMonth()139cdf0e10cSrcweir void ScInterpreter::ScGetMonth()
140cdf0e10cSrcweir {
141cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetMonth" );
142cdf0e10cSrcweir     Date aDate = *(pFormatter->GetNullDate());
143cdf0e10cSrcweir     aDate += (long) ::rtl::math::approxFloor(GetDouble());
144cdf0e10cSrcweir     PushDouble( (double) aDate.GetMonth() );
145cdf0e10cSrcweir }
146cdf0e10cSrcweir 
ScGetDay()147cdf0e10cSrcweir void ScInterpreter::ScGetDay()
148cdf0e10cSrcweir {
149cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDay" );
150cdf0e10cSrcweir     Date aDate = *(pFormatter->GetNullDate());
151cdf0e10cSrcweir     aDate += (long)::rtl::math::approxFloor(GetDouble());
152cdf0e10cSrcweir     PushDouble((double) aDate.GetDay());
153cdf0e10cSrcweir }
154cdf0e10cSrcweir 
ScGetMin()155cdf0e10cSrcweir void ScInterpreter::ScGetMin()
156cdf0e10cSrcweir {
157cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetMin" );
158cdf0e10cSrcweir     double fTime = GetDouble();
159cdf0e10cSrcweir     fTime -= ::rtl::math::approxFloor(fTime);       // Datumsanteil weg
160cdf0e10cSrcweir     long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) % 3600;
161cdf0e10cSrcweir     PushDouble( (double) (nVal/60) );
162cdf0e10cSrcweir }
163cdf0e10cSrcweir 
ScGetSec()164cdf0e10cSrcweir void ScInterpreter::ScGetSec()
165cdf0e10cSrcweir {
166cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetSec" );
167cdf0e10cSrcweir     double fTime = GetDouble();
168cdf0e10cSrcweir     fTime -= ::rtl::math::approxFloor(fTime);       // Datumsanteil weg
169cdf0e10cSrcweir     long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) % 60;
170cdf0e10cSrcweir     PushDouble( (double) nVal );
171cdf0e10cSrcweir }
172cdf0e10cSrcweir 
ScGetHour()173cdf0e10cSrcweir void ScInterpreter::ScGetHour()
174cdf0e10cSrcweir {
175cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetHour" );
176cdf0e10cSrcweir     double fTime = GetDouble();
177cdf0e10cSrcweir     fTime -= ::rtl::math::approxFloor(fTime);       // Datumsanteil weg
178cdf0e10cSrcweir     long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) / 3600;
179cdf0e10cSrcweir     PushDouble((double) nVal);
180cdf0e10cSrcweir }
181cdf0e10cSrcweir 
ScGetDateValue()182cdf0e10cSrcweir void ScInterpreter::ScGetDateValue()
183cdf0e10cSrcweir {
184cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDateValue" );
185cdf0e10cSrcweir     String aInputString = GetString();
186cdf0e10cSrcweir     sal_uInt32 nFIndex = 0;                 // damit default Land/Spr.
187cdf0e10cSrcweir     double fVal;
188cdf0e10cSrcweir     if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
189cdf0e10cSrcweir     {
190cdf0e10cSrcweir         short eType = pFormatter->GetType(nFIndex);
191cdf0e10cSrcweir         if (eType == NUMBERFORMAT_DATE || eType == NUMBERFORMAT_DATETIME)
192cdf0e10cSrcweir             PushDouble(::rtl::math::approxFloor(fVal));
193cdf0e10cSrcweir         else
194cdf0e10cSrcweir             PushIllegalArgument();
195cdf0e10cSrcweir     }
196cdf0e10cSrcweir     else
197cdf0e10cSrcweir         PushIllegalArgument();
198cdf0e10cSrcweir }
199cdf0e10cSrcweir 
ScGetDayOfWeek()200cdf0e10cSrcweir void ScInterpreter::ScGetDayOfWeek()
201cdf0e10cSrcweir {
202cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDayOfWeek" );
203cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
204cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
205cdf0e10cSrcweir     {
206cdf0e10cSrcweir         short nFlag;
207cdf0e10cSrcweir         if (nParamCount == 2)
208cdf0e10cSrcweir             nFlag = (short) ::rtl::math::approxFloor(GetDouble());
209cdf0e10cSrcweir         else
210cdf0e10cSrcweir             nFlag = 1;
211cdf0e10cSrcweir 
212cdf0e10cSrcweir         Date aDate = *(pFormatter->GetNullDate());
213cdf0e10cSrcweir         aDate += (long)::rtl::math::approxFloor(GetDouble());
214cdf0e10cSrcweir         int nVal = (int) aDate.GetDayOfWeek();
215cdf0e10cSrcweir         if (nFlag == 1)
216cdf0e10cSrcweir         {
217cdf0e10cSrcweir             if (nVal == 6)
218cdf0e10cSrcweir                 nVal = 1;
219cdf0e10cSrcweir             else
220cdf0e10cSrcweir                 nVal += 2;
221cdf0e10cSrcweir         }
222cdf0e10cSrcweir         else if (nFlag == 2)
223cdf0e10cSrcweir             nVal += 1;
224cdf0e10cSrcweir         PushInt( nVal );
225cdf0e10cSrcweir     }
226cdf0e10cSrcweir }
227cdf0e10cSrcweir 
ScGetWeekOfYear()228cdf0e10cSrcweir void ScInterpreter::ScGetWeekOfYear()
229cdf0e10cSrcweir {
230cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetWeekOfYear" );
231cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 2 ) )
232cdf0e10cSrcweir     {
233cdf0e10cSrcweir         short nFlag = (short) ::rtl::math::approxFloor(GetDouble());
234cdf0e10cSrcweir 
235cdf0e10cSrcweir         Date aDate = *(pFormatter->GetNullDate());
236cdf0e10cSrcweir         aDate += (long)::rtl::math::approxFloor(GetDouble());
237cdf0e10cSrcweir         PushInt( (int) aDate.GetWeekOfYear( nFlag == 1 ? SUNDAY : MONDAY ));
238cdf0e10cSrcweir     }
239cdf0e10cSrcweir }
240cdf0e10cSrcweir 
ScEasterSunday()241cdf0e10cSrcweir void ScInterpreter::ScEasterSunday()
242cdf0e10cSrcweir {
243cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEasterSunday" );
244cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_DATE;
245cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 1 ) )
246cdf0e10cSrcweir     {
247cdf0e10cSrcweir         sal_Int16 nDay, nMonth, nYear;
248cdf0e10cSrcweir         nYear = (sal_Int16) ::rtl::math::approxFloor( GetDouble() );
249cdf0e10cSrcweir         if ( nYear < 100 )
250cdf0e10cSrcweir             nYear = pFormatter->ExpandTwoDigitYear( nYear );
251cdf0e10cSrcweir         // don't worry, be happy :)
252cdf0e10cSrcweir         int B,C,D,E,F,G,H,I,K,L,M,N,O;
253cdf0e10cSrcweir         N = nYear % 19;
254cdf0e10cSrcweir         B = int(nYear / 100);
255cdf0e10cSrcweir         C = nYear % 100;
256cdf0e10cSrcweir         D = int(B / 4);
257cdf0e10cSrcweir         E = B % 4;
258cdf0e10cSrcweir         F = int((B + 8) / 25);
259cdf0e10cSrcweir         G = int((B - F + 1) / 3);
260cdf0e10cSrcweir         H = (19 * N + B - D - G + 15) % 30;
261cdf0e10cSrcweir         I = int(C / 4);
262cdf0e10cSrcweir         K = C % 4;
263cdf0e10cSrcweir         L = (32 + 2 * E + 2 * I - H - K) % 7;
264cdf0e10cSrcweir         M = int((N + 11 * H + 22 * L) / 451);
265cdf0e10cSrcweir         O = H + L - 7 * M + 114;
266cdf0e10cSrcweir         nDay = sal::static_int_cast<sal_Int16>( O % 31 + 1 );
267cdf0e10cSrcweir         nMonth = sal::static_int_cast<sal_Int16>( int(O / 31) );
268cdf0e10cSrcweir         PushDouble( GetDateSerial( nYear, nMonth, nDay, true ) );
269cdf0e10cSrcweir     }
270cdf0e10cSrcweir }
271cdf0e10cSrcweir 
ScGetDate()272cdf0e10cSrcweir void ScInterpreter::ScGetDate()
273cdf0e10cSrcweir {
274cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDate" );
275cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_DATE;
276cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 3 ) )
277cdf0e10cSrcweir     {
278cdf0e10cSrcweir         sal_Int16 nDay   = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
279cdf0e10cSrcweir         sal_Int16 nMonth = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
280cdf0e10cSrcweir         sal_Int16 nYear  = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
281cdf0e10cSrcweir         if (nYear < 0)
282cdf0e10cSrcweir             PushIllegalArgument();
283cdf0e10cSrcweir         else
284cdf0e10cSrcweir         {
285cdf0e10cSrcweir             PushDouble(GetDateSerial(nYear, nMonth, nDay, false));
286cdf0e10cSrcweir         }
287cdf0e10cSrcweir     }
288cdf0e10cSrcweir }
289cdf0e10cSrcweir 
ScGetTime()290cdf0e10cSrcweir void ScInterpreter::ScGetTime()
291cdf0e10cSrcweir {
292cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetTime" );
293cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_TIME;
294cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 3 ) )
295cdf0e10cSrcweir     {
296cdf0e10cSrcweir         double nSec = GetDouble();
297cdf0e10cSrcweir         double nMin = GetDouble();
298cdf0e10cSrcweir         double nHour = GetDouble();
299cdf0e10cSrcweir         double fTime = fmod( (nHour * 3600) + (nMin * 60) + nSec, D_TIMEFACTOR) / D_TIMEFACTOR;
300cdf0e10cSrcweir         if (fTime < 0)
301cdf0e10cSrcweir             PushIllegalArgument();
302cdf0e10cSrcweir         else
303cdf0e10cSrcweir             PushDouble( fTime);
304cdf0e10cSrcweir     }
305cdf0e10cSrcweir }
306cdf0e10cSrcweir 
ScGetDiffDate()307cdf0e10cSrcweir void ScInterpreter::ScGetDiffDate()
308cdf0e10cSrcweir {
309cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDiffDate" );
310cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 2 ) )
311cdf0e10cSrcweir     {
312cdf0e10cSrcweir         double nDate2 = GetDouble();
313cdf0e10cSrcweir         double nDate1 = GetDouble();
314cdf0e10cSrcweir         PushDouble(nDate1 - nDate2);
315cdf0e10cSrcweir     }
316cdf0e10cSrcweir }
317cdf0e10cSrcweir 
ScGetDiffDate360()318cdf0e10cSrcweir void ScInterpreter::ScGetDiffDate360()
319cdf0e10cSrcweir {
320cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDiffDate360" );
321cdf0e10cSrcweir     /* Implementation follows
322cdf0e10cSrcweir      * http://www.bondmarkets.com/eCommerce/SMD_Fields_030802.pdf
323cdf0e10cSrcweir      * Appendix B: Day-Count Bases, there are 7 different ways to calculate the
324cdf0e10cSrcweir      * 30-days count. That document also claims that Excel implements the "PSA
325cdf0e10cSrcweir      * 30" or "NASD 30" method (funny enough they also state that Excel is the
326cdf0e10cSrcweir      * only tool that does so).
327cdf0e10cSrcweir      *
328cdf0e10cSrcweir      * Note that the definiton given in
329cdf0e10cSrcweir      * http://msdn.microsoft.com/library/en-us/office97/html/SEB7C.asp
330cdf0e10cSrcweir      * is _not_ the way how it is actually calculated by Excel (that would not
331cdf0e10cSrcweir      * even match any of the 7 methods mentioned above) and would result in the
332cdf0e10cSrcweir      * following test cases producing wrong results according to that appendix B:
333cdf0e10cSrcweir      *
334cdf0e10cSrcweir      * 28-Feb-95  31-Aug-95  181 instead of 180
335cdf0e10cSrcweir      * 29-Feb-96  31-Aug-96  181 instead of 180
336cdf0e10cSrcweir      * 30-Jan-96  31-Mar-96   61 instead of  60
337cdf0e10cSrcweir      * 31-Jan-96  31-Mar-96   61 instead of  60
338cdf0e10cSrcweir      *
339cdf0e10cSrcweir      * Still, there is a difference between OOoCalc and Excel:
340cdf0e10cSrcweir      * In Excel:
341cdf0e10cSrcweir      * 02-Feb-99 31-Mar-00 results in  419
342cdf0e10cSrcweir      * 31-Mar-00 02-Feb-99 results in -418
343cdf0e10cSrcweir      * In Calc the result is 419 respectively -419. I consider the -418 a bug in Excel.
344cdf0e10cSrcweir      */
345cdf0e10cSrcweir 
346cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
347cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 2, 3 ) )
348cdf0e10cSrcweir     {
349cdf0e10cSrcweir         sal_Bool bFlag;
350cdf0e10cSrcweir         if (nParamCount == 3)
351cdf0e10cSrcweir             bFlag = GetBool();
352cdf0e10cSrcweir         else
353cdf0e10cSrcweir             bFlag = sal_False;
354cdf0e10cSrcweir         double nDate2 = GetDouble();
355cdf0e10cSrcweir         double nDate1 = GetDouble();
356cdf0e10cSrcweir         double fSign;
357cdf0e10cSrcweir         if (nGlobalError)
358cdf0e10cSrcweir             PushError( nGlobalError);
359cdf0e10cSrcweir         else
360cdf0e10cSrcweir         {
361cdf0e10cSrcweir             // #i84934# only for non-US European algorithm swap dates. Else
362cdf0e10cSrcweir             // follow Excel's meaningless extrapolation for "interoperability".
363cdf0e10cSrcweir             if (bFlag && (nDate2 < nDate1))
364cdf0e10cSrcweir             {
365cdf0e10cSrcweir                 fSign = nDate1;
366cdf0e10cSrcweir                 nDate1 = nDate2;
367cdf0e10cSrcweir                 nDate2 = fSign;
368cdf0e10cSrcweir                 fSign = -1.0;
369cdf0e10cSrcweir             }
370cdf0e10cSrcweir             else
371cdf0e10cSrcweir                 fSign = 1.0;
372cdf0e10cSrcweir             Date aDate1 = *(pFormatter->GetNullDate());
373cdf0e10cSrcweir             aDate1 += (long) ::rtl::math::approxFloor(nDate1);
374cdf0e10cSrcweir             Date aDate2 = *(pFormatter->GetNullDate());
375cdf0e10cSrcweir             aDate2 += (long) ::rtl::math::approxFloor(nDate2);
376cdf0e10cSrcweir             if (aDate1.GetDay() == 31)
377cdf0e10cSrcweir                 aDate1 -= (sal_uLong) 1;
378cdf0e10cSrcweir             else if (!bFlag)
379cdf0e10cSrcweir             {
380cdf0e10cSrcweir                 if (aDate1.GetMonth() == 2)
381cdf0e10cSrcweir                 {
382cdf0e10cSrcweir                     switch ( aDate1.GetDay() )
383cdf0e10cSrcweir                     {
384cdf0e10cSrcweir                         case 28 :
385cdf0e10cSrcweir                             if ( !aDate1.IsLeapYear() )
386cdf0e10cSrcweir                                 aDate1.SetDay(30);
387cdf0e10cSrcweir                         break;
388cdf0e10cSrcweir                         case 29 :
389cdf0e10cSrcweir                             aDate1.SetDay(30);
390cdf0e10cSrcweir                         break;
391cdf0e10cSrcweir                     }
392cdf0e10cSrcweir                 }
393cdf0e10cSrcweir             }
394cdf0e10cSrcweir             if (aDate2.GetDay() == 31)
395cdf0e10cSrcweir             {
396cdf0e10cSrcweir                 if (!bFlag )
397cdf0e10cSrcweir                 {
398cdf0e10cSrcweir                     if (aDate1.GetDay() == 30)
399cdf0e10cSrcweir                         aDate2 -= (sal_uLong) 1;
400cdf0e10cSrcweir                 }
401cdf0e10cSrcweir                 else
402cdf0e10cSrcweir                     aDate2.SetDay(30);
403cdf0e10cSrcweir             }
404cdf0e10cSrcweir             PushDouble( fSign * (double)
405cdf0e10cSrcweir                 (  (double) aDate2.GetDay() + (double) aDate2.GetMonth() * 30.0 +
406cdf0e10cSrcweir                    (double) aDate2.GetYear() * 360.0
407cdf0e10cSrcweir                  - (double) aDate1.GetDay() - (double) aDate1.GetMonth() * 30.0
408cdf0e10cSrcweir                  - (double)aDate1.GetYear() * 360.0) );
409cdf0e10cSrcweir         }
410cdf0e10cSrcweir     }
411cdf0e10cSrcweir }
412cdf0e10cSrcweir 
ScGetTimeValue()413cdf0e10cSrcweir void ScInterpreter::ScGetTimeValue()
414cdf0e10cSrcweir {
415cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetTimeValue" );
416cdf0e10cSrcweir     String aInputString = GetString();
417cdf0e10cSrcweir     sal_uInt32 nFIndex = 0;                 // damit default Land/Spr.
418cdf0e10cSrcweir     double fVal;
419cdf0e10cSrcweir     if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
420cdf0e10cSrcweir     {
421cdf0e10cSrcweir         short eType = pFormatter->GetType(nFIndex);
422cdf0e10cSrcweir         if (eType == NUMBERFORMAT_TIME || eType == NUMBERFORMAT_DATETIME)
423cdf0e10cSrcweir         {
424cdf0e10cSrcweir             double fDateVal = rtl::math::approxFloor(fVal);
425cdf0e10cSrcweir             double fTimeVal = fVal - fDateVal;
426cdf0e10cSrcweir             PushDouble(fTimeVal);
427cdf0e10cSrcweir         }
428cdf0e10cSrcweir         else
429cdf0e10cSrcweir             PushIllegalArgument();
430cdf0e10cSrcweir     }
431cdf0e10cSrcweir     else
432cdf0e10cSrcweir         PushIllegalArgument();
433cdf0e10cSrcweir }
434cdf0e10cSrcweir 
ScPlusMinus()435cdf0e10cSrcweir void ScInterpreter::ScPlusMinus()
436cdf0e10cSrcweir {
437cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPlusMinus" );
438cdf0e10cSrcweir     double nVal = GetDouble();
439cdf0e10cSrcweir     short n = 0;
440cdf0e10cSrcweir     if (nVal < 0.0)
441cdf0e10cSrcweir         n = -1;
442cdf0e10cSrcweir     else if (nVal > 0.0)
443cdf0e10cSrcweir         n = 1;
444cdf0e10cSrcweir     PushInt( n );
445cdf0e10cSrcweir }
446cdf0e10cSrcweir 
ScAbs()447cdf0e10cSrcweir void ScInterpreter::ScAbs()
448cdf0e10cSrcweir {
449cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAbs" );
450cdf0e10cSrcweir     PushDouble(fabs(GetDouble()));
451cdf0e10cSrcweir }
452cdf0e10cSrcweir 
ScInt()453cdf0e10cSrcweir void ScInterpreter::ScInt()
454cdf0e10cSrcweir {
455cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInt" );
456cdf0e10cSrcweir     PushDouble(::rtl::math::approxFloor(GetDouble()));
457cdf0e10cSrcweir }
458cdf0e10cSrcweir 
459cdf0e10cSrcweir 
RoundNumber(rtl_math_RoundingMode eMode)460cdf0e10cSrcweir void ScInterpreter::RoundNumber( rtl_math_RoundingMode eMode )
461cdf0e10cSrcweir {
462cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RoundNumber" );
463cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
464cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
465cdf0e10cSrcweir     {
466cdf0e10cSrcweir         double fVal = 0.0;
467cdf0e10cSrcweir         if (nParamCount == 1)
468cdf0e10cSrcweir             fVal = ::rtl::math::round( GetDouble(), 0, eMode );
469cdf0e10cSrcweir         else
470cdf0e10cSrcweir         {
471cdf0e10cSrcweir             sal_Int32 nDec = (sal_Int32) ::rtl::math::approxFloor(GetDouble());
472cdf0e10cSrcweir             if( nDec < -20 || nDec > 20 )
473cdf0e10cSrcweir                 PushIllegalArgument();
474cdf0e10cSrcweir             else
475cdf0e10cSrcweir                 fVal = ::rtl::math::round( GetDouble(), (short)nDec, eMode );
476cdf0e10cSrcweir         }
477cdf0e10cSrcweir         PushDouble(fVal);
478cdf0e10cSrcweir     }
479cdf0e10cSrcweir }
480cdf0e10cSrcweir 
ScRound()481cdf0e10cSrcweir void ScInterpreter::ScRound()
482cdf0e10cSrcweir {
483cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRound" );
484cdf0e10cSrcweir     RoundNumber( rtl_math_RoundingMode_Corrected );
485cdf0e10cSrcweir }
486cdf0e10cSrcweir 
ScRoundDown()487cdf0e10cSrcweir void ScInterpreter::ScRoundDown()
488cdf0e10cSrcweir {
489cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRoundDown" );
490cdf0e10cSrcweir     RoundNumber( rtl_math_RoundingMode_Down );
491cdf0e10cSrcweir }
492cdf0e10cSrcweir 
ScRoundUp()493cdf0e10cSrcweir void ScInterpreter::ScRoundUp()
494cdf0e10cSrcweir {
495cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRoundUp" );
496cdf0e10cSrcweir     RoundNumber( rtl_math_RoundingMode_Up );
497cdf0e10cSrcweir }
498cdf0e10cSrcweir 
ScCeil()499cdf0e10cSrcweir void ScInterpreter::ScCeil()
500cdf0e10cSrcweir {
501cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCeil" );
502cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
503cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 2, 3 ) )
504cdf0e10cSrcweir     {
505cdf0e10cSrcweir         sal_Bool bAbs = ( nParamCount == 3 ? GetBool() : sal_False );
506cdf0e10cSrcweir         double fDec = GetDouble();
507cdf0e10cSrcweir         double fVal = GetDouble();
508cdf0e10cSrcweir         if ( fDec == 0.0 )
509cdf0e10cSrcweir             PushInt(0);
510cdf0e10cSrcweir         else if (fVal*fDec < 0.0)
511cdf0e10cSrcweir             PushIllegalArgument();
512cdf0e10cSrcweir         else
513cdf0e10cSrcweir         {
514cdf0e10cSrcweir             if ( !bAbs && fVal < 0.0 )
515cdf0e10cSrcweir                 PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec);
516cdf0e10cSrcweir             else
517cdf0e10cSrcweir                 PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec);
518cdf0e10cSrcweir         }
519cdf0e10cSrcweir     }
520cdf0e10cSrcweir }
521cdf0e10cSrcweir 
ScFloor()522cdf0e10cSrcweir void ScInterpreter::ScFloor()
523cdf0e10cSrcweir {
524cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFloor" );
525cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
526cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 2, 3 ) )
527cdf0e10cSrcweir     {
528cdf0e10cSrcweir         sal_Bool bAbs = ( nParamCount == 3 ? GetBool() : sal_False );
529cdf0e10cSrcweir         double fDec = GetDouble();
530cdf0e10cSrcweir         double fVal = GetDouble();
531cdf0e10cSrcweir         if ( fDec == 0.0 )
532cdf0e10cSrcweir             PushInt(0);
533cdf0e10cSrcweir         else if (fVal*fDec < 0.0)
534cdf0e10cSrcweir             PushIllegalArgument();
535cdf0e10cSrcweir         else
536cdf0e10cSrcweir         {
537cdf0e10cSrcweir             if ( !bAbs && fVal < 0.0 )
538cdf0e10cSrcweir                 PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec);
539cdf0e10cSrcweir             else
540cdf0e10cSrcweir                 PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec);
541cdf0e10cSrcweir         }
542cdf0e10cSrcweir     }
543cdf0e10cSrcweir }
544cdf0e10cSrcweir 
ScEven()545cdf0e10cSrcweir void ScInterpreter::ScEven()
546cdf0e10cSrcweir {
547cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEven" );
548cdf0e10cSrcweir     double fVal = GetDouble();
549cdf0e10cSrcweir     if (fVal < 0.0)
550cdf0e10cSrcweir         PushDouble(::rtl::math::approxFloor(fVal/2.0) * 2.0);
551cdf0e10cSrcweir     else
552cdf0e10cSrcweir         PushDouble(::rtl::math::approxCeil(fVal/2.0) * 2.0);
553cdf0e10cSrcweir }
554cdf0e10cSrcweir 
ScOdd()555cdf0e10cSrcweir void ScInterpreter::ScOdd()
556cdf0e10cSrcweir {
557cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOdd" );
558cdf0e10cSrcweir     double fVal = GetDouble();
559cdf0e10cSrcweir     if (fVal >= 0.0)
560cdf0e10cSrcweir     {
561cdf0e10cSrcweir         fVal = ::rtl::math::approxCeil(fVal);
562cdf0e10cSrcweir         if (fmod(fVal, 2.0) == 0.0)
563cdf0e10cSrcweir             fVal += 1.0;
564cdf0e10cSrcweir     }
565cdf0e10cSrcweir     else
566cdf0e10cSrcweir     {
567cdf0e10cSrcweir         fVal = ::rtl::math::approxFloor(fVal);
568cdf0e10cSrcweir         if (fmod(fVal, 2.0) == 0.0)
569cdf0e10cSrcweir             fVal -= 1.0;
570cdf0e10cSrcweir     }
571cdf0e10cSrcweir     PushDouble(fVal);
572cdf0e10cSrcweir }
573cdf0e10cSrcweir 
ScArcTan2()574cdf0e10cSrcweir void ScInterpreter::ScArcTan2()
575cdf0e10cSrcweir {
576cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcTan2" );
577cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 2 ) )
578cdf0e10cSrcweir     {
579cdf0e10cSrcweir         double nVal2 = GetDouble();
580cdf0e10cSrcweir         double nVal1 = GetDouble();
581cdf0e10cSrcweir         PushDouble(atan2(nVal2, nVal1));
582cdf0e10cSrcweir     }
583cdf0e10cSrcweir }
584cdf0e10cSrcweir 
ScLog()585cdf0e10cSrcweir void ScInterpreter::ScLog()
586cdf0e10cSrcweir {
587cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLog" );
588cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
589cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
590cdf0e10cSrcweir     {
591cdf0e10cSrcweir         double nBase;
592cdf0e10cSrcweir         if (nParamCount == 2)
593cdf0e10cSrcweir             nBase = GetDouble();
594cdf0e10cSrcweir         else
595cdf0e10cSrcweir             nBase = 10.0;
596cdf0e10cSrcweir         double nVal = GetDouble();
597cdf0e10cSrcweir         if (nVal > 0.0 && nBase > 0.0 && nBase != 1.0)
598cdf0e10cSrcweir             PushDouble(log(nVal) / log(nBase));
599cdf0e10cSrcweir         else
600cdf0e10cSrcweir             PushIllegalArgument();
601cdf0e10cSrcweir     }
602cdf0e10cSrcweir }
603cdf0e10cSrcweir 
ScLn()604cdf0e10cSrcweir void ScInterpreter::ScLn()
605cdf0e10cSrcweir {
606cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLn" );
607cdf0e10cSrcweir     double fVal = GetDouble();
608cdf0e10cSrcweir     if (fVal > 0.0)
609cdf0e10cSrcweir         PushDouble(log(fVal));
610cdf0e10cSrcweir     else
611cdf0e10cSrcweir         PushIllegalArgument();
612cdf0e10cSrcweir }
613cdf0e10cSrcweir 
ScLog10()614cdf0e10cSrcweir void ScInterpreter::ScLog10()
615cdf0e10cSrcweir {
616cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLog10" );
617cdf0e10cSrcweir     double fVal = GetDouble();
618cdf0e10cSrcweir     if (fVal > 0.0)
619cdf0e10cSrcweir         PushDouble(log10(fVal));
620cdf0e10cSrcweir     else
621cdf0e10cSrcweir         PushIllegalArgument();
622cdf0e10cSrcweir }
623cdf0e10cSrcweir 
ScNPV()624cdf0e10cSrcweir void ScInterpreter::ScNPV()
625cdf0e10cSrcweir {
626cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNPV" );
627cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
628cdf0e10cSrcweir     short nParamCount = GetByte();
629cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 2, 31 ) )
630cdf0e10cSrcweir     {
631cdf0e10cSrcweir         double nVal = 0.0;
632cdf0e10cSrcweir         // Wir drehen den Stack um!!
633cdf0e10cSrcweir         FormulaToken* pTemp[ 31 ];
634cdf0e10cSrcweir         for( short i = 0; i < nParamCount; i++ )
635cdf0e10cSrcweir             pTemp[ i ] = pStack[ sp - i - 1 ];
636cdf0e10cSrcweir         memcpy( &pStack[ sp - nParamCount ], pTemp, nParamCount * sizeof( FormulaToken* ) );
637cdf0e10cSrcweir         if (nGlobalError == 0)
638cdf0e10cSrcweir         {
639cdf0e10cSrcweir             double  nCount = 1.0;
640cdf0e10cSrcweir             double  nZins = GetDouble();
641cdf0e10cSrcweir             --nParamCount;
642cdf0e10cSrcweir             size_t nRefInList = 0;
643cdf0e10cSrcweir             ScRange aRange;
644cdf0e10cSrcweir             while (nParamCount-- > 0)
645cdf0e10cSrcweir             {
646cdf0e10cSrcweir                 switch (GetStackType())
647cdf0e10cSrcweir                 {
648cdf0e10cSrcweir                     case svDouble :
649cdf0e10cSrcweir                     {
650cdf0e10cSrcweir                         nVal += (GetDouble() / pow(1.0 + nZins, (double)nCount));
651cdf0e10cSrcweir                         nCount++;
652cdf0e10cSrcweir                     }
653cdf0e10cSrcweir                     break;
654cdf0e10cSrcweir                     case svSingleRef :
655cdf0e10cSrcweir                     {
656cdf0e10cSrcweir                         ScAddress aAdr;
657cdf0e10cSrcweir                         PopSingleRef( aAdr );
658cdf0e10cSrcweir                         ScBaseCell* pCell = GetCell( aAdr );
659cdf0e10cSrcweir                         if (!HasCellEmptyData(pCell) && HasCellValueData(pCell))
660cdf0e10cSrcweir                         {
661cdf0e10cSrcweir                             double nCellVal = GetCellValue( aAdr, pCell );
662cdf0e10cSrcweir                             nVal += (nCellVal / pow(1.0 + nZins, (double)nCount));
663cdf0e10cSrcweir                             nCount++;
664cdf0e10cSrcweir                         }
665cdf0e10cSrcweir                     }
666cdf0e10cSrcweir                     break;
667cdf0e10cSrcweir                     case svDoubleRef :
668cdf0e10cSrcweir                     case svRefList :
669cdf0e10cSrcweir                     {
670cdf0e10cSrcweir                         sal_uInt16 nErr = 0;
671cdf0e10cSrcweir                         double nCellVal;
672cdf0e10cSrcweir                         PopDoubleRef( aRange, nParamCount, nRefInList);
673cdf0e10cSrcweir                         ScHorizontalValueIterator aValIter( pDok, aRange, glSubTotal);
674cdf0e10cSrcweir                         while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
675cdf0e10cSrcweir                         {
676cdf0e10cSrcweir                             nVal += (nCellVal / pow(1.0 + nZins, (double)nCount));
677cdf0e10cSrcweir                             nCount++;
678cdf0e10cSrcweir                         }
679cdf0e10cSrcweir                         if ( nErr != 0 )
680cdf0e10cSrcweir                             SetError(nErr);
681cdf0e10cSrcweir                     }
682cdf0e10cSrcweir                     break;
683cdf0e10cSrcweir                     default : SetError(errIllegalParameter); break;
684cdf0e10cSrcweir                 }
685cdf0e10cSrcweir             }
686cdf0e10cSrcweir         }
687cdf0e10cSrcweir         PushDouble(nVal);
688cdf0e10cSrcweir     }
689cdf0e10cSrcweir }
690cdf0e10cSrcweir 
ScIRR()691cdf0e10cSrcweir void ScInterpreter::ScIRR()
692cdf0e10cSrcweir {
693cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIRR" );
694cdf0e10cSrcweir     double fSchaetzwert;
695cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_PERCENT;
696cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
697cdf0e10cSrcweir     if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
698cdf0e10cSrcweir         return;
699cdf0e10cSrcweir     if (nParamCount == 2)
700cdf0e10cSrcweir         fSchaetzwert = GetDouble();
701cdf0e10cSrcweir     else
702cdf0e10cSrcweir         fSchaetzwert = 0.1;
703cdf0e10cSrcweir     sal_uInt16 sPos = sp;                       // Stack-Position merken
704cdf0e10cSrcweir     double fEps = 1.0;
705cdf0e10cSrcweir     double x, xNeu, fWert, fZaehler, fNenner, nCount;
706cdf0e10cSrcweir     if (fSchaetzwert == -1.0)
707cdf0e10cSrcweir         x = 0.1;                            // default gegen Nulldivisionen
708cdf0e10cSrcweir     else
709cdf0e10cSrcweir         x = fSchaetzwert;                   // Startwert
710cdf0e10cSrcweir     switch (GetStackType())
711cdf0e10cSrcweir     {
712cdf0e10cSrcweir         case svDoubleRef :
713cdf0e10cSrcweir         break;
714cdf0e10cSrcweir         default:
715cdf0e10cSrcweir         {
716cdf0e10cSrcweir             PushIllegalParameter();
717cdf0e10cSrcweir             return;
718cdf0e10cSrcweir         }
719cdf0e10cSrcweir     }
720cdf0e10cSrcweir     const sal_uInt16 nIterationsMax = 20;
721cdf0e10cSrcweir     sal_uInt16 nItCount = 0;
722cdf0e10cSrcweir     ScRange aRange;
723cdf0e10cSrcweir     while (fEps > SCdEpsilon && nItCount < nIterationsMax)
724cdf0e10cSrcweir     {                                       // Newton-Verfahren:
725cdf0e10cSrcweir         sp = sPos;                          // Stack zuruecksetzen
726cdf0e10cSrcweir         nCount = 0.0;
727cdf0e10cSrcweir         fZaehler = 0.0;
728cdf0e10cSrcweir         fNenner = 0.0;
729cdf0e10cSrcweir         sal_uInt16 nErr = 0;
730cdf0e10cSrcweir         PopDoubleRef( aRange );
731cdf0e10cSrcweir         ScValueIterator aValIter(pDok, aRange, glSubTotal);
732cdf0e10cSrcweir         if (aValIter.GetFirst(fWert, nErr))
733cdf0e10cSrcweir         {
734cdf0e10cSrcweir             fZaehler +=           fWert / pow(1.0+x,(double)nCount);
735cdf0e10cSrcweir             fNenner  += -nCount * fWert / pow(1.0+x,nCount+1.0);
736cdf0e10cSrcweir             nCount++;
737cdf0e10cSrcweir             while ((nErr == 0) && aValIter.GetNext(fWert, nErr))
738cdf0e10cSrcweir             {
739cdf0e10cSrcweir                 fZaehler +=           fWert / pow(1.0+x,(double)nCount);
740cdf0e10cSrcweir                 fNenner  += -nCount * fWert / pow(1.0+x,nCount+1.0);
741cdf0e10cSrcweir                 nCount++;
742cdf0e10cSrcweir             }
743cdf0e10cSrcweir             SetError(nErr);
744cdf0e10cSrcweir         }
745cdf0e10cSrcweir         xNeu = x - fZaehler / fNenner;  // x(i+1) = x(i)-f(x(i))/f'(x(i))
746cdf0e10cSrcweir         nItCount++;
747cdf0e10cSrcweir         fEps = fabs(xNeu - x);
748cdf0e10cSrcweir         x = xNeu;
749cdf0e10cSrcweir     }
750cdf0e10cSrcweir     if (fSchaetzwert == 0.0 && fabs(x) < SCdEpsilon)
751cdf0e10cSrcweir         x = 0.0;                        // auf Null normieren
752cdf0e10cSrcweir     if (fEps < SCdEpsilon)
753cdf0e10cSrcweir         PushDouble(x);
754cdf0e10cSrcweir     else
755cdf0e10cSrcweir         PushError( errNoConvergence);
756cdf0e10cSrcweir }
757cdf0e10cSrcweir 
ScMIRR()758cdf0e10cSrcweir void ScInterpreter::ScMIRR()
759cdf0e10cSrcweir {   // range_of_values ; rate_invest ; rate_reinvest
760cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_PERCENT;
761cdf0e10cSrcweir     if( MustHaveParamCount( GetByte(), 3 ) )
762cdf0e10cSrcweir     {
763cdf0e10cSrcweir         double fRate1_reinvest = GetDouble() + 1;
764cdf0e10cSrcweir         double fNPV_reinvest = 0.0;
765cdf0e10cSrcweir         double fPow_reinvest = 1.0;
766cdf0e10cSrcweir 
767cdf0e10cSrcweir         double fRate1_invest = GetDouble() + 1;
768cdf0e10cSrcweir         double fNPV_invest = 0.0;
769cdf0e10cSrcweir         double fPow_invest = 1.0;
770cdf0e10cSrcweir 
771cdf0e10cSrcweir         ScRange aRange;
772cdf0e10cSrcweir         PopDoubleRef( aRange );
773cdf0e10cSrcweir 
774cdf0e10cSrcweir         if( nGlobalError )
775cdf0e10cSrcweir             PushError( nGlobalError);
776cdf0e10cSrcweir         else
777cdf0e10cSrcweir         {
778cdf0e10cSrcweir             ScValueIterator aValIter( pDok, aRange, glSubTotal );
779cdf0e10cSrcweir             double fCellValue;
780cdf0e10cSrcweir             sal_uLong nCount = 0;
781cdf0e10cSrcweir             sal_uInt16 nIterError = 0;
782cdf0e10cSrcweir 
783cdf0e10cSrcweir             sal_Bool bLoop = aValIter.GetFirst( fCellValue, nIterError );
784cdf0e10cSrcweir             while( bLoop )
785cdf0e10cSrcweir             {
786cdf0e10cSrcweir                 if( fCellValue > 0.0 )          // reinvestments
787cdf0e10cSrcweir                     fNPV_reinvest += fCellValue * fPow_reinvest;
788cdf0e10cSrcweir                 else if( fCellValue < 0.0 )     // investments
789cdf0e10cSrcweir                     fNPV_invest += fCellValue * fPow_invest;
790cdf0e10cSrcweir                 fPow_reinvest /= fRate1_reinvest;
791cdf0e10cSrcweir                 fPow_invest /= fRate1_invest;
792cdf0e10cSrcweir                 nCount++;
793cdf0e10cSrcweir 
794cdf0e10cSrcweir                 bLoop = aValIter.GetNext( fCellValue, nIterError );
795cdf0e10cSrcweir             }
796cdf0e10cSrcweir             if( nIterError )
797cdf0e10cSrcweir                 PushError( nIterError );
798cdf0e10cSrcweir             else
799cdf0e10cSrcweir             {
800cdf0e10cSrcweir                 double fResult = -fNPV_reinvest / fNPV_invest;
801cdf0e10cSrcweir                 fResult *= pow( fRate1_reinvest, (double) nCount - 1 );
802cdf0e10cSrcweir                 fResult = pow( fResult, 1.0 / (nCount - 1) );
803cdf0e10cSrcweir                 PushDouble( fResult - 1.0 );
804cdf0e10cSrcweir             }
805cdf0e10cSrcweir         }
806cdf0e10cSrcweir     }
807cdf0e10cSrcweir }
808cdf0e10cSrcweir 
809cdf0e10cSrcweir 
ScISPMT()810cdf0e10cSrcweir void ScInterpreter::ScISPMT()
811cdf0e10cSrcweir {   // rate ; period ; total_periods ; invest
812cdf0e10cSrcweir     if( MustHaveParamCount( GetByte(), 4 ) )
813cdf0e10cSrcweir     {
814cdf0e10cSrcweir         double fInvest = GetDouble();
815cdf0e10cSrcweir         double fTotal = GetDouble();
816cdf0e10cSrcweir         double fPeriod = GetDouble();
817cdf0e10cSrcweir         double fRate = GetDouble();
818cdf0e10cSrcweir 
819cdf0e10cSrcweir         if( nGlobalError )
820cdf0e10cSrcweir             PushError( nGlobalError);
821cdf0e10cSrcweir         else
822cdf0e10cSrcweir             PushDouble( fInvest * fRate * (fPeriod / fTotal - 1.0) );
823cdf0e10cSrcweir     }
824cdf0e10cSrcweir }
825cdf0e10cSrcweir 
826cdf0e10cSrcweir 
827cdf0e10cSrcweir //----------------------- Finanzfunktionen ------------------------------------
828cdf0e10cSrcweir 
ScGetBw(double fZins,double fZzr,double fRmz,double fZw,double fF)829cdf0e10cSrcweir double ScInterpreter::ScGetBw(double fZins, double fZzr, double fRmz,
830cdf0e10cSrcweir                               double fZw, double fF)
831cdf0e10cSrcweir {
832cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMIRR" );
833cdf0e10cSrcweir     double fBw;
834cdf0e10cSrcweir     if (fZins == 0.0)
835cdf0e10cSrcweir         fBw = fZw + fRmz * fZzr;
836cdf0e10cSrcweir     else if (fF > 0.0)
837cdf0e10cSrcweir         fBw = (fZw * pow(1.0 + fZins, -fZzr))
838cdf0e10cSrcweir                 + (fRmz * (1.0 - pow(1.0 + fZins, -fZzr + 1.0)) / fZins)
839cdf0e10cSrcweir                 + fRmz;
840cdf0e10cSrcweir     else
841cdf0e10cSrcweir         fBw = (fZw * pow(1.0 + fZins, -fZzr))
842cdf0e10cSrcweir                 + (fRmz * (1.0 - pow(1.0 + fZins, -fZzr)) / fZins);
843cdf0e10cSrcweir     return -fBw;
844cdf0e10cSrcweir }
845cdf0e10cSrcweir 
ScBW()846cdf0e10cSrcweir void ScInterpreter::ScBW()
847cdf0e10cSrcweir {
848cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBW" );
849cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
850cdf0e10cSrcweir     double nRmz, nZzr, nZins, nZw = 0, nFlag = 0;
851cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
852cdf0e10cSrcweir     if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
853cdf0e10cSrcweir         return;
854cdf0e10cSrcweir     if (nParamCount == 5)
855cdf0e10cSrcweir         nFlag = GetDouble();
856cdf0e10cSrcweir     if (nParamCount >= 4)
857cdf0e10cSrcweir         nZw   = GetDouble();
858cdf0e10cSrcweir     nRmz  = GetDouble();
859cdf0e10cSrcweir     nZzr  = GetDouble();
860cdf0e10cSrcweir     nZins = GetDouble();
861cdf0e10cSrcweir     PushDouble(ScGetBw(nZins, nZzr, nRmz, nZw, nFlag));
862cdf0e10cSrcweir }
863cdf0e10cSrcweir 
ScDIA()864cdf0e10cSrcweir void ScInterpreter::ScDIA()
865cdf0e10cSrcweir {
866cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDIA" );
867cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
868cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 4 ) )
869cdf0e10cSrcweir     {
870cdf0e10cSrcweir         double nZr = GetDouble();
871cdf0e10cSrcweir         double nDauer = GetDouble();
872cdf0e10cSrcweir         double nRest = GetDouble();
873cdf0e10cSrcweir         double nWert = GetDouble();
874cdf0e10cSrcweir         double nDia = ((nWert - nRest) * (nDauer - nZr + 1.0)) /
875cdf0e10cSrcweir                       ((nDauer * (nDauer + 1.0)) / 2.0);
876cdf0e10cSrcweir         PushDouble(nDia);
877cdf0e10cSrcweir     }
878cdf0e10cSrcweir }
879cdf0e10cSrcweir 
ScGetGDA(double fWert,double fRest,double fDauer,double fPeriode,double fFaktor)880cdf0e10cSrcweir double ScInterpreter::ScGetGDA(double fWert, double fRest, double fDauer,
881cdf0e10cSrcweir                 double fPeriode, double fFaktor)
882cdf0e10cSrcweir {
883cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetGDA" );
884cdf0e10cSrcweir     double fGda, fZins, fAlterWert, fNeuerWert;
885cdf0e10cSrcweir     fZins = fFaktor / fDauer;
886cdf0e10cSrcweir     if (fZins >= 1.0)
887cdf0e10cSrcweir     {
888cdf0e10cSrcweir         fZins = 1.0;
889cdf0e10cSrcweir         if (fPeriode == 1.0)
890cdf0e10cSrcweir             fAlterWert = fWert;
891cdf0e10cSrcweir         else
892cdf0e10cSrcweir             fAlterWert = 0.0;
893cdf0e10cSrcweir     }
894cdf0e10cSrcweir     else
895cdf0e10cSrcweir         fAlterWert = fWert * pow(1.0 - fZins, fPeriode - 1.0);
896cdf0e10cSrcweir     fNeuerWert = fWert * pow(1.0 - fZins, fPeriode);
897cdf0e10cSrcweir 
898cdf0e10cSrcweir     if (fNeuerWert < fRest)
899cdf0e10cSrcweir         fGda = fAlterWert - fRest;
900cdf0e10cSrcweir     else
901cdf0e10cSrcweir         fGda = fAlterWert - fNeuerWert;
902cdf0e10cSrcweir     if (fGda < 0.0)
903cdf0e10cSrcweir         fGda = 0.0;
904cdf0e10cSrcweir     return fGda;
905cdf0e10cSrcweir }
906cdf0e10cSrcweir 
ScGDA()907cdf0e10cSrcweir void ScInterpreter::ScGDA()
908cdf0e10cSrcweir {
909cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGDA" );
910cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
911cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
912cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 4, 5 ) )
913cdf0e10cSrcweir     {
914cdf0e10cSrcweir         double nFaktor;
915cdf0e10cSrcweir         if (nParamCount == 5)
916cdf0e10cSrcweir             nFaktor = GetDouble();
917cdf0e10cSrcweir         else
918cdf0e10cSrcweir             nFaktor = 2.0;
919cdf0e10cSrcweir         double nPeriode = GetDouble();
920cdf0e10cSrcweir         double nDauer   = GetDouble();
921cdf0e10cSrcweir         double nRest    = GetDouble();
922cdf0e10cSrcweir         double nWert    = GetDouble();
923cdf0e10cSrcweir         if (nWert < 0.0 || nRest < 0.0 || nFaktor <= 0.0 || nRest > nWert
924cdf0e10cSrcweir                         || nPeriode < 1.0 || nPeriode > nDauer)
925cdf0e10cSrcweir             PushIllegalArgument();
926cdf0e10cSrcweir         else
927cdf0e10cSrcweir             PushDouble(ScGetGDA(nWert, nRest, nDauer, nPeriode, nFaktor));
928cdf0e10cSrcweir     }
929cdf0e10cSrcweir }
930cdf0e10cSrcweir 
ScGDA2()931cdf0e10cSrcweir void ScInterpreter::ScGDA2()
932cdf0e10cSrcweir {
933cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGDA2" );
934cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
935cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
936cdf0e10cSrcweir     if ( !MustHaveParamCount( nParamCount, 4, 5 ) )
937cdf0e10cSrcweir         return ;
938cdf0e10cSrcweir     double nMonate;
939cdf0e10cSrcweir     if (nParamCount == 4)
940cdf0e10cSrcweir         nMonate = 12.0;
941cdf0e10cSrcweir     else
942cdf0e10cSrcweir         nMonate = ::rtl::math::approxFloor(GetDouble());
943cdf0e10cSrcweir     double nPeriode = GetDouble();
944cdf0e10cSrcweir     double nDauer = GetDouble();
945cdf0e10cSrcweir     double nRest = GetDouble();
946cdf0e10cSrcweir     double nWert = GetDouble();
947cdf0e10cSrcweir     if (nMonate < 1.0 || nMonate > 12.0 || nDauer > 1200.0 || nRest < 0.0 ||
948cdf0e10cSrcweir         nPeriode > (nDauer + 1.0) || nRest > nWert || nWert < 0.0)
949cdf0e10cSrcweir     {
950cdf0e10cSrcweir         PushIllegalArgument();
951cdf0e10cSrcweir         return;
952cdf0e10cSrcweir     }
953cdf0e10cSrcweir     double nAbRate = 1.0 - pow(nRest / nWert, 1.0 / nDauer);
954cdf0e10cSrcweir     nAbRate = ::rtl::math::approxFloor((nAbRate * 1000.0) + 0.5) / 1000.0;
955cdf0e10cSrcweir     double nErsteAbRate = nWert * nAbRate * nMonate / 12.0;
956cdf0e10cSrcweir     double nGda2 = 0.0;
957cdf0e10cSrcweir     if (::rtl::math::approxFloor(nPeriode) == 1)
958cdf0e10cSrcweir         nGda2 = nErsteAbRate;
959cdf0e10cSrcweir     else
960cdf0e10cSrcweir     {
961cdf0e10cSrcweir         double nSummAbRate = nErsteAbRate;
962cdf0e10cSrcweir         double nMin = nDauer;
963cdf0e10cSrcweir         if (nMin > nPeriode) nMin = nPeriode;
964cdf0e10cSrcweir         sal_uInt16 iMax = (sal_uInt16)::rtl::math::approxFloor(nMin);
965cdf0e10cSrcweir         for (sal_uInt16 i = 2; i <= iMax; i++)
966cdf0e10cSrcweir         {
967cdf0e10cSrcweir             nGda2 = (nWert - nSummAbRate) * nAbRate;
968cdf0e10cSrcweir             nSummAbRate += nGda2;
969cdf0e10cSrcweir         }
970cdf0e10cSrcweir         if (nPeriode > nDauer)
971cdf0e10cSrcweir             nGda2 = ((nWert - nSummAbRate) * nAbRate * (12.0 - nMonate)) / 12.0;
972cdf0e10cSrcweir     }
973cdf0e10cSrcweir     PushDouble(nGda2);
974cdf0e10cSrcweir }
975cdf0e10cSrcweir 
976cdf0e10cSrcweir 
ScInterVDB(double fWert,double fRest,double fDauer,double fDauer1,double fPeriode,double fFaktor)977cdf0e10cSrcweir double ScInterpreter::ScInterVDB(double fWert,double fRest,double fDauer,
978cdf0e10cSrcweir                              double fDauer1,double fPeriode,double fFaktor)
979cdf0e10cSrcweir {
980cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInterVDB" );
981cdf0e10cSrcweir     double fVdb=0;
982cdf0e10cSrcweir     double fIntEnd   = ::rtl::math::approxCeil(fPeriode);
983cdf0e10cSrcweir     sal_uLong nLoopEnd   = (sal_uLong) fIntEnd;
984cdf0e10cSrcweir 
985cdf0e10cSrcweir     double fTerm, fLia;
986cdf0e10cSrcweir     double fRestwert = fWert - fRest;
987cdf0e10cSrcweir     sal_Bool bNowLia = sal_False;
988cdf0e10cSrcweir 
989cdf0e10cSrcweir     double fGda;
990cdf0e10cSrcweir     sal_uLong i;
991cdf0e10cSrcweir     fLia=0;
992cdf0e10cSrcweir     for ( i = 1; i <= nLoopEnd; i++)
993cdf0e10cSrcweir     {
994cdf0e10cSrcweir         if(!bNowLia)
995cdf0e10cSrcweir         {
996cdf0e10cSrcweir             fGda = ScGetGDA(fWert, fRest, fDauer, (double) i, fFaktor);
997cdf0e10cSrcweir             fLia = fRestwert/ (fDauer1 - (double) (i-1));
998cdf0e10cSrcweir 
999cdf0e10cSrcweir             if (fLia > fGda)
1000cdf0e10cSrcweir             {
1001cdf0e10cSrcweir                 fTerm = fLia;
1002cdf0e10cSrcweir                 bNowLia = sal_True;
1003cdf0e10cSrcweir             }
1004cdf0e10cSrcweir             else
1005cdf0e10cSrcweir             {
1006cdf0e10cSrcweir                 fTerm = fGda;
1007cdf0e10cSrcweir                 fRestwert -= fGda;
1008cdf0e10cSrcweir             }
1009cdf0e10cSrcweir         }
1010cdf0e10cSrcweir         else
1011cdf0e10cSrcweir         {
1012cdf0e10cSrcweir             fTerm = fLia;
1013cdf0e10cSrcweir         }
1014cdf0e10cSrcweir 
1015cdf0e10cSrcweir         if ( i == nLoopEnd)
1016cdf0e10cSrcweir             fTerm *= ( fPeriode + 1.0 - fIntEnd );
1017cdf0e10cSrcweir 
1018cdf0e10cSrcweir         fVdb += fTerm;
1019cdf0e10cSrcweir     }
1020cdf0e10cSrcweir     return fVdb;
1021cdf0e10cSrcweir }
1022cdf0e10cSrcweir 
1023cdf0e10cSrcweir 
DblMin(double a,double b)1024cdf0e10cSrcweir inline double DblMin( double a, double b )
1025cdf0e10cSrcweir {
1026cdf0e10cSrcweir     return (a < b) ? a : b;
1027cdf0e10cSrcweir }
1028cdf0e10cSrcweir 
ScVDB()1029cdf0e10cSrcweir void ScInterpreter::ScVDB()
1030cdf0e10cSrcweir {
1031cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVDB" );
1032cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
1033cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
1034cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 5, 7 ) )
1035cdf0e10cSrcweir     {
1036cdf0e10cSrcweir         double fWert, fRest, fDauer, fAnfang, fEnde, fFaktor, fVdb = 0.0;
1037cdf0e10cSrcweir         sal_Bool bFlag;
1038cdf0e10cSrcweir         if (nParamCount == 7)
1039cdf0e10cSrcweir             bFlag = GetBool();
1040cdf0e10cSrcweir         else
1041cdf0e10cSrcweir             bFlag = sal_False;
1042cdf0e10cSrcweir         if (nParamCount >= 6)
1043cdf0e10cSrcweir             fFaktor = GetDouble();
1044cdf0e10cSrcweir         else
1045cdf0e10cSrcweir             fFaktor = 2.0;
1046cdf0e10cSrcweir         fEnde   = GetDouble();
1047cdf0e10cSrcweir         fAnfang = GetDouble();
1048cdf0e10cSrcweir         fDauer  = GetDouble();
1049cdf0e10cSrcweir         fRest   = GetDouble();
1050cdf0e10cSrcweir         fWert   = GetDouble();
1051cdf0e10cSrcweir         if (fAnfang < 0.0 || fEnde < fAnfang || fEnde > fDauer || fWert < 0.0
1052cdf0e10cSrcweir                           || fRest > fWert || fFaktor <= 0.0)
1053cdf0e10cSrcweir             PushIllegalArgument();
1054cdf0e10cSrcweir         else
1055cdf0e10cSrcweir         {
1056cdf0e10cSrcweir             double fIntStart = ::rtl::math::approxFloor(fAnfang);
1057cdf0e10cSrcweir             double fIntEnd   = ::rtl::math::approxCeil(fEnde);
1058cdf0e10cSrcweir             sal_uLong nLoopStart = (sal_uLong) fIntStart;
1059cdf0e10cSrcweir             sal_uLong nLoopEnd   = (sal_uLong) fIntEnd;
1060cdf0e10cSrcweir 
1061cdf0e10cSrcweir             fVdb = 0.0;
1062cdf0e10cSrcweir             if (bFlag)
1063cdf0e10cSrcweir             {
1064cdf0e10cSrcweir                 for (sal_uLong i = nLoopStart + 1; i <= nLoopEnd; i++)
1065cdf0e10cSrcweir                 {
1066cdf0e10cSrcweir                     double fTerm = ScGetGDA(fWert, fRest, fDauer, (double) i, fFaktor);
1067cdf0e10cSrcweir 
1068cdf0e10cSrcweir                     //  Teilperioden am Anfang / Ende beruecksichtigen:
1069cdf0e10cSrcweir                     if ( i == nLoopStart+1 )
1070cdf0e10cSrcweir                         fTerm *= ( DblMin( fEnde, fIntStart + 1.0 ) - fAnfang );
1071cdf0e10cSrcweir                     else if ( i == nLoopEnd )
1072cdf0e10cSrcweir                         fTerm *= ( fEnde + 1.0 - fIntEnd );
1073cdf0e10cSrcweir 
1074cdf0e10cSrcweir                     fVdb += fTerm;
1075cdf0e10cSrcweir                 }
1076cdf0e10cSrcweir             }
1077cdf0e10cSrcweir             else
1078cdf0e10cSrcweir             {
1079cdf0e10cSrcweir 
1080cdf0e10cSrcweir                 double fDauer1=fDauer;
1081cdf0e10cSrcweir                 double fPart;
1082cdf0e10cSrcweir 
1083cdf0e10cSrcweir                 //@Die Frage aller Fragen: "Ist das hier richtig"
1084cdf0e10cSrcweir                 if(!::rtl::math::approxEqual(fAnfang,::rtl::math::approxFloor(fAnfang)))
1085cdf0e10cSrcweir                 {
1086cdf0e10cSrcweir                     if(fFaktor>1)
1087cdf0e10cSrcweir                     {
1088cdf0e10cSrcweir                         if(fAnfang>fDauer/2 || ::rtl::math::approxEqual(fAnfang,fDauer/2))
1089cdf0e10cSrcweir                         {
1090cdf0e10cSrcweir                             fPart=fAnfang-fDauer/2;
1091cdf0e10cSrcweir                             fAnfang=fDauer/2;
1092cdf0e10cSrcweir                             fEnde-=fPart;
1093cdf0e10cSrcweir                             fDauer1+=1;
1094cdf0e10cSrcweir                         }
1095cdf0e10cSrcweir                     }
1096cdf0e10cSrcweir                 }
1097cdf0e10cSrcweir 
1098cdf0e10cSrcweir                 fWert-=ScInterVDB(fWert,fRest,fDauer,fDauer1,fAnfang,fFaktor);
1099cdf0e10cSrcweir                 fVdb=ScInterVDB(fWert,fRest,fDauer,fDauer-fAnfang,fEnde-fAnfang,fFaktor);
1100cdf0e10cSrcweir             }
1101cdf0e10cSrcweir         }
1102cdf0e10cSrcweir         PushDouble(fVdb);
1103cdf0e10cSrcweir     }
1104cdf0e10cSrcweir }
1105cdf0e10cSrcweir 
ScLaufz()1106cdf0e10cSrcweir void ScInterpreter::ScLaufz()
1107cdf0e10cSrcweir {
1108cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLaufz" );
1109cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 3 ) )
1110cdf0e10cSrcweir     {
1111cdf0e10cSrcweir         double nZukunft = GetDouble();
1112cdf0e10cSrcweir         double nGegenwart = GetDouble();
1113cdf0e10cSrcweir         double nZins = GetDouble();
1114cdf0e10cSrcweir         PushDouble(log(nZukunft / nGegenwart) / log(1.0 + nZins));
1115cdf0e10cSrcweir     }
1116cdf0e10cSrcweir }
1117cdf0e10cSrcweir 
ScLIA()1118cdf0e10cSrcweir void ScInterpreter::ScLIA()
1119cdf0e10cSrcweir {
1120cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLIA" );
1121cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
1122cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 3 ) )
1123cdf0e10cSrcweir     {
1124cdf0e10cSrcweir         double nDauer = GetDouble();
1125cdf0e10cSrcweir         double nRest = GetDouble();
1126cdf0e10cSrcweir         double nWert = GetDouble();
1127cdf0e10cSrcweir         PushDouble((nWert - nRest) / nDauer);
1128cdf0e10cSrcweir     }
1129cdf0e10cSrcweir }
1130cdf0e10cSrcweir 
ScGetRmz(double fRate,double fNper,double fPv,double fFv,double fPaytype)1131cdf0e10cSrcweir double ScInterpreter::ScGetRmz(double fRate, double fNper, double fPv,
1132cdf0e10cSrcweir                        double fFv, double fPaytype)
1133cdf0e10cSrcweir {
1134cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetRmz" );
1135cdf0e10cSrcweir     double fPayment;
1136cdf0e10cSrcweir     if (fRate == 0.0)
1137cdf0e10cSrcweir         fPayment = (fPv + fFv) / fNper;
1138cdf0e10cSrcweir     else
1139cdf0e10cSrcweir     {
1140cdf0e10cSrcweir         if (fPaytype > 0.0) // payment in advance
114176ea2deeSPedro Giffuni             fPayment = (fFv + fPv * exp( fNper * ::boost::math::log1p(fRate) ) ) * fRate /
114276ea2deeSPedro Giffuni                 (::boost::math::expm1( (fNper + 1) * ::boost::math::log1p(fRate) ) - fRate);
1143cdf0e10cSrcweir         else  // payment in arrear
114476ea2deeSPedro Giffuni             fPayment = (fFv + fPv * exp(fNper * ::boost::math::log1p(fRate) ) ) * fRate /
114576ea2deeSPedro Giffuni                 ::boost::math::expm1( fNper * ::boost::math::log1p(fRate) );
1146cdf0e10cSrcweir     }
1147cdf0e10cSrcweir     return -fPayment;
1148cdf0e10cSrcweir }
1149cdf0e10cSrcweir 
ScRMZ()1150cdf0e10cSrcweir void ScInterpreter::ScRMZ()
1151cdf0e10cSrcweir {
1152cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRMZ" );
1153cdf0e10cSrcweir     double nZins, nZzr, nBw, nZw = 0, nFlag = 0;
1154cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
1155cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
1156cdf0e10cSrcweir     if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1157cdf0e10cSrcweir         return;
1158cdf0e10cSrcweir     if (nParamCount == 5)
1159cdf0e10cSrcweir         nFlag = GetDouble();
1160cdf0e10cSrcweir     if (nParamCount >= 4)
1161cdf0e10cSrcweir         nZw   = GetDouble();
1162cdf0e10cSrcweir     nBw   = GetDouble();
1163cdf0e10cSrcweir     nZzr  = GetDouble();
1164cdf0e10cSrcweir     nZins = GetDouble();
1165cdf0e10cSrcweir     PushDouble(ScGetRmz(nZins, nZzr, nBw, nZw, nFlag));
1166cdf0e10cSrcweir }
1167cdf0e10cSrcweir 
ScZGZ()1168cdf0e10cSrcweir void ScInterpreter::ScZGZ()
1169cdf0e10cSrcweir {
1170cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZGZ" );
1171cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_PERCENT;
1172cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 3 ) )
1173cdf0e10cSrcweir     {
1174cdf0e10cSrcweir         double nZukunftswert = GetDouble();
1175cdf0e10cSrcweir         double nGegenwartswert = GetDouble();
1176cdf0e10cSrcweir         double nZeitraum = GetDouble();
1177cdf0e10cSrcweir         PushDouble(pow(nZukunftswert / nGegenwartswert, 1.0 / nZeitraum) - 1.0);
1178cdf0e10cSrcweir     }
1179cdf0e10cSrcweir }
1180cdf0e10cSrcweir 
ScGetZw(double fZins,double fZzr,double fRmz,double fBw,double fF)1181cdf0e10cSrcweir double ScInterpreter::ScGetZw(double fZins, double fZzr, double fRmz,
1182cdf0e10cSrcweir                               double fBw, double fF)
1183cdf0e10cSrcweir {
1184cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetZw" );
1185cdf0e10cSrcweir     double fZw;
1186cdf0e10cSrcweir     if (fZins == 0.0)
1187cdf0e10cSrcweir         fZw = fBw + fRmz * fZzr;
1188cdf0e10cSrcweir     else
1189cdf0e10cSrcweir     {
1190cdf0e10cSrcweir         double fTerm = pow(1.0 + fZins, fZzr);
1191cdf0e10cSrcweir         if (fF > 0.0)
1192cdf0e10cSrcweir             fZw = fBw * fTerm + fRmz*(1.0 + fZins)*(fTerm - 1.0)/fZins;
1193cdf0e10cSrcweir         else
1194cdf0e10cSrcweir             fZw = fBw * fTerm + fRmz*(fTerm - 1.0)/fZins;
1195cdf0e10cSrcweir     }
1196cdf0e10cSrcweir     return -fZw;
1197cdf0e10cSrcweir }
1198cdf0e10cSrcweir 
ScZW()1199cdf0e10cSrcweir void ScInterpreter::ScZW()
1200cdf0e10cSrcweir {
1201cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZW" );
1202cdf0e10cSrcweir     double nZins, nZzr, nRmz, nBw = 0, nFlag = 0;
1203cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
1204cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
1205cdf0e10cSrcweir     if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1206cdf0e10cSrcweir         return;
1207cdf0e10cSrcweir     if (nParamCount == 5)
1208cdf0e10cSrcweir         nFlag = GetDouble();
1209cdf0e10cSrcweir     if (nParamCount >= 4)
1210cdf0e10cSrcweir         nBw   = GetDouble();
1211cdf0e10cSrcweir     nRmz  = GetDouble();
1212cdf0e10cSrcweir     nZzr  = GetDouble();
1213cdf0e10cSrcweir     nZins = GetDouble();
1214cdf0e10cSrcweir     PushDouble(ScGetZw(nZins, nZzr, nRmz, nBw, nFlag));
1215cdf0e10cSrcweir }
1216cdf0e10cSrcweir 
ScZZR()1217cdf0e10cSrcweir void ScInterpreter::ScZZR()
1218cdf0e10cSrcweir {
1219cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZZR" );
1220cdf0e10cSrcweir     double nZins, nRmz, nBw, nZw = 0, nFlag = 0;
1221cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
1222cdf0e10cSrcweir     if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1223cdf0e10cSrcweir         return;
1224cdf0e10cSrcweir     if (nParamCount == 5)
1225cdf0e10cSrcweir         nFlag = GetDouble();
1226cdf0e10cSrcweir     if (nParamCount >= 4)
1227cdf0e10cSrcweir         nZw   = GetDouble();
1228cdf0e10cSrcweir     nBw   = GetDouble();
1229cdf0e10cSrcweir     nRmz  = GetDouble();
1230cdf0e10cSrcweir     nZins = GetDouble();
1231cdf0e10cSrcweir     if (nZins == 0.0)
1232cdf0e10cSrcweir         PushDouble(-(nBw + nZw)/nRmz);
1233cdf0e10cSrcweir     else if (nFlag > 0.0)
1234cdf0e10cSrcweir         PushDouble(log(-(nZins*nZw-nRmz*(1.0+nZins))/(nZins*nBw+nRmz*(1.0+nZins)))
1235cdf0e10cSrcweir                   /log(1.0+nZins));
1236cdf0e10cSrcweir     else
1237cdf0e10cSrcweir         PushDouble(log(-(nZins*nZw-nRmz)/(nZins*nBw+nRmz))/log(1.0+nZins));
1238cdf0e10cSrcweir }
1239cdf0e10cSrcweir 
RateIteration(double fNper,double fPayment,double fPv,double fFv,double fPayType,double & fGuess)1240cdf0e10cSrcweir bool ScInterpreter::RateIteration( double fNper, double fPayment, double fPv,
1241cdf0e10cSrcweir                                    double fFv, double fPayType, double & fGuess )
1242cdf0e10cSrcweir {
1243cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RateIteration" );
1244cdf0e10cSrcweir     // See also #i15090#
1245cdf0e10cSrcweir     // Newton-Raphson method: x(i+1) = x(i) - f(x(i)) / f'(x(i))
1246cdf0e10cSrcweir     // This solution handles integer and non-integer values of Nper different.
1247cdf0e10cSrcweir     // If ODFF will constraint Nper to integer, the distinction of cases can be
1248cdf0e10cSrcweir     // removed; only the integer-part is needed then.
1249cdf0e10cSrcweir     bool bValid = true, bFound = false;
1250cdf0e10cSrcweir     double fX, fXnew, fTerm, fTermDerivation;
1251cdf0e10cSrcweir     double fGeoSeries, fGeoSeriesDerivation;
1252cdf0e10cSrcweir     const sal_uInt16 nIterationsMax = 150;
1253cdf0e10cSrcweir     sal_uInt16 nCount = 0;
1254cdf0e10cSrcweir     const double fEpsilonSmall = 1.0E-14;
1255cdf0e10cSrcweir     // convert any fPayType situation to fPayType == zero situation
1256cdf0e10cSrcweir     fFv = fFv - fPayment * fPayType;
1257cdf0e10cSrcweir     fPv = fPv + fPayment * fPayType;
1258cdf0e10cSrcweir     if (fNper == ::rtl::math::round( fNper, 0, rtl_math_RoundingMode_Corrected ))
1259cdf0e10cSrcweir     { // Nper is an integer value
1260cdf0e10cSrcweir         fX = fGuess;
1261cdf0e10cSrcweir         double fPowN, fPowNminus1;  // for (1.0+fX)^Nper and (1.0+fX)^(Nper-1)
1262cdf0e10cSrcweir         while (!bFound && nCount < nIterationsMax)
1263cdf0e10cSrcweir         {
1264cdf0e10cSrcweir             fPowNminus1 = pow( 1.0+fX, fNper-1.0);
1265cdf0e10cSrcweir             fPowN = fPowNminus1 * (1.0+fX);
1266cdf0e10cSrcweir             if (rtl::math::approxEqual( fabs(fX), 0.0))
1267cdf0e10cSrcweir             {
1268cdf0e10cSrcweir                 fGeoSeries = fNper;
1269cdf0e10cSrcweir                 fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
1270cdf0e10cSrcweir             }
1271cdf0e10cSrcweir             else
1272cdf0e10cSrcweir             {
1273cdf0e10cSrcweir                 fGeoSeries = (fPowN-1.0)/fX;
1274cdf0e10cSrcweir                 fGeoSeriesDerivation = fNper * fPowNminus1 / fX - fGeoSeries / fX;
1275cdf0e10cSrcweir             }
1276cdf0e10cSrcweir             fTerm = fFv + fPv *fPowN+ fPayment * fGeoSeries;
1277cdf0e10cSrcweir             fTermDerivation = fPv * fNper * fPowNminus1 + fPayment * fGeoSeriesDerivation;
1278cdf0e10cSrcweir             if (fabs(fTerm) < fEpsilonSmall)
1279cdf0e10cSrcweir                 bFound = true;  // will catch root which is at an extreme
1280cdf0e10cSrcweir             else
1281cdf0e10cSrcweir             {
1282cdf0e10cSrcweir                 if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0))
1283cdf0e10cSrcweir                     fXnew = fX + 1.1 * SCdEpsilon;  // move away from zero slope
1284cdf0e10cSrcweir                 else
1285cdf0e10cSrcweir                     fXnew = fX - fTerm / fTermDerivation;
1286cdf0e10cSrcweir             nCount++;
1287cdf0e10cSrcweir             // more accuracy not possible in oscillating cases
1288cdf0e10cSrcweir             bFound = (fabs(fXnew - fX) < SCdEpsilon);
1289cdf0e10cSrcweir             fX = fXnew;
1290cdf0e10cSrcweir             }
1291cdf0e10cSrcweir         }
1292cdf0e10cSrcweir         // Gnumeric returns roots < -1, Excel gives an error in that cases,
1293cdf0e10cSrcweir         // ODFF says nothing about it. Enable the statement, if you want Excel's
1294cdf0e10cSrcweir         // behavior
1295cdf0e10cSrcweir         //bValid =(fX >=-1.0);
1296cdf0e10cSrcweir     }
1297cdf0e10cSrcweir     else
1298cdf0e10cSrcweir     { // Nper is not an integer value.
1299cdf0e10cSrcweir         fX = (fGuess < -1.0) ? -1.0 : fGuess;   // start with a valid fX
1300cdf0e10cSrcweir         while (bValid && !bFound && nCount < nIterationsMax)
1301cdf0e10cSrcweir         {
1302cdf0e10cSrcweir             if (rtl::math::approxEqual( fabs(fX), 0.0))
1303cdf0e10cSrcweir             {
1304cdf0e10cSrcweir                 fGeoSeries = fNper;
1305cdf0e10cSrcweir                 fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
1306cdf0e10cSrcweir             }
1307cdf0e10cSrcweir             else
1308cdf0e10cSrcweir             {
1309cdf0e10cSrcweir                 fGeoSeries = (pow( 1.0+fX, fNper) - 1.0) / fX;
1310cdf0e10cSrcweir                 fGeoSeriesDerivation = fNper * pow( 1.0+fX, fNper-1.0) / fX - fGeoSeries / fX;
1311cdf0e10cSrcweir             }
1312cdf0e10cSrcweir             fTerm = fFv + fPv *pow(1.0 + fX,fNper)+ fPayment * fGeoSeries;
1313cdf0e10cSrcweir             fTermDerivation = fPv * fNper * pow( 1.0+fX, fNper-1.0) + fPayment * fGeoSeriesDerivation;
1314cdf0e10cSrcweir             if (fabs(fTerm) < fEpsilonSmall)
1315cdf0e10cSrcweir                 bFound = true;  // will catch root which is at an extreme
1316cdf0e10cSrcweir             else
1317cdf0e10cSrcweir             {
1318cdf0e10cSrcweir                 if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0))
1319cdf0e10cSrcweir                     fXnew = fX + 1.1 * SCdEpsilon;  // move away from zero slope
1320cdf0e10cSrcweir                 else
1321cdf0e10cSrcweir                     fXnew = fX - fTerm / fTermDerivation;
1322cdf0e10cSrcweir             nCount++;
1323cdf0e10cSrcweir              // more accuracy not possible in oscillating cases
1324cdf0e10cSrcweir             bFound = (fabs(fXnew - fX) < SCdEpsilon);
1325cdf0e10cSrcweir             fX = fXnew;
1326cdf0e10cSrcweir             bValid = (fX >= -1.0);  // otherwise pow(1.0+fX,fNper) will fail
1327cdf0e10cSrcweir             }
1328cdf0e10cSrcweir         }
1329cdf0e10cSrcweir     }
1330cdf0e10cSrcweir     fGuess = fX;    // return approximate root
1331cdf0e10cSrcweir     return bValid && bFound;
1332cdf0e10cSrcweir }
1333cdf0e10cSrcweir 
1334cdf0e10cSrcweir // In Calc UI it is the function RATE(Nper;Pmt;Pv;Fv;Type;Guess)
ScZins()1335cdf0e10cSrcweir void ScInterpreter::ScZins()
1336cdf0e10cSrcweir {
1337cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZins" );
1338cdf0e10cSrcweir     double fPv, fPayment, fNper;
1339cdf0e10cSrcweir     // defaults for missing arguments, see ODFF spec
1340cdf0e10cSrcweir     double fFv = 0, fPayType = 0, fGuess = 0.1;
1341cdf0e10cSrcweir     bool bValid = true;
1342cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_PERCENT;
1343cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
1344cdf0e10cSrcweir     if ( !MustHaveParamCount( nParamCount, 3, 6 ) )
1345cdf0e10cSrcweir         return;
1346cdf0e10cSrcweir     if (nParamCount == 6)
1347cdf0e10cSrcweir         fGuess = GetDouble();
1348cdf0e10cSrcweir     if (nParamCount >= 5)
1349cdf0e10cSrcweir         fPayType = GetDouble();
1350cdf0e10cSrcweir     if (nParamCount >= 4)
1351cdf0e10cSrcweir         fFv = GetDouble();
1352cdf0e10cSrcweir     fPv = GetDouble();
1353cdf0e10cSrcweir     fPayment = GetDouble();
1354cdf0e10cSrcweir     fNper = GetDouble();
1355cdf0e10cSrcweir     if (fNper <= 0.0) // constraint from ODFF spec
1356cdf0e10cSrcweir     {
1357cdf0e10cSrcweir         PushIllegalArgument();
1358cdf0e10cSrcweir         return;
1359cdf0e10cSrcweir     }
1360cdf0e10cSrcweir     // other values for fPayType might be meaningful,
1361cdf0e10cSrcweir     // ODFF spec is not clear yet, enable statement if you want only 0 and 1
1362cdf0e10cSrcweir     //if (fPayType != 0.0) fPayType = 1.0;
1363cdf0e10cSrcweir     bValid = RateIteration(fNper, fPayment, fPv, fFv, fPayType, fGuess);
1364cdf0e10cSrcweir     if (!bValid)
1365cdf0e10cSrcweir         SetError(errNoConvergence);
1366cdf0e10cSrcweir     PushDouble(fGuess);
1367cdf0e10cSrcweir }
1368cdf0e10cSrcweir 
ScGetZinsZ(double fZins,double fZr,double fZzr,double fBw,double fZw,double fF,double & fRmz)1369cdf0e10cSrcweir double ScInterpreter::ScGetZinsZ(double fZins, double fZr, double fZzr, double fBw,
1370cdf0e10cSrcweir                                  double fZw, double fF, double& fRmz)
1371cdf0e10cSrcweir {
1372cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetZinsZ" );
1373cdf0e10cSrcweir     fRmz = ScGetRmz(fZins, fZzr, fBw, fZw, fF);     // fuer kapz auch bei fZr == 1
1374cdf0e10cSrcweir     double fZinsZ;
1375cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
1376cdf0e10cSrcweir     if (fZr == 1.0)
1377cdf0e10cSrcweir     {
1378cdf0e10cSrcweir         if (fF > 0.0)
1379cdf0e10cSrcweir             fZinsZ = 0.0;
1380cdf0e10cSrcweir         else
1381cdf0e10cSrcweir             fZinsZ = -fBw;
1382cdf0e10cSrcweir     }
1383cdf0e10cSrcweir     else
1384cdf0e10cSrcweir     {
1385cdf0e10cSrcweir         if (fF > 0.0)
1386cdf0e10cSrcweir             fZinsZ = ScGetZw(fZins, fZr-2.0, fRmz, fBw, 1.0) - fRmz;
1387cdf0e10cSrcweir         else
1388cdf0e10cSrcweir             fZinsZ = ScGetZw(fZins, fZr-1.0, fRmz, fBw, 0.0);
1389cdf0e10cSrcweir     }
1390cdf0e10cSrcweir     return fZinsZ * fZins;
1391cdf0e10cSrcweir }
1392cdf0e10cSrcweir 
ScZinsZ()1393cdf0e10cSrcweir void ScInterpreter::ScZinsZ()
1394cdf0e10cSrcweir {
1395cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZinsZ" );
1396cdf0e10cSrcweir     double nZins, nZr, nRmz, nZzr, nBw, nZw = 0, nFlag = 0;
1397cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
1398cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
1399cdf0e10cSrcweir     if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
1400cdf0e10cSrcweir         return;
1401cdf0e10cSrcweir     if (nParamCount == 6)
1402cdf0e10cSrcweir         nFlag = GetDouble();
1403cdf0e10cSrcweir     if (nParamCount >= 5)
1404cdf0e10cSrcweir         nZw   = GetDouble();
1405cdf0e10cSrcweir     nBw   = GetDouble();
1406cdf0e10cSrcweir     nZzr  = GetDouble();
1407cdf0e10cSrcweir     nZr   = GetDouble();
1408cdf0e10cSrcweir     nZins = GetDouble();
1409cdf0e10cSrcweir     if (nZr < 1.0 || nZr > nZzr)
1410cdf0e10cSrcweir         PushIllegalArgument();
1411cdf0e10cSrcweir     else
1412cdf0e10cSrcweir         PushDouble(ScGetZinsZ(nZins, nZr, nZzr, nBw, nZw, nFlag, nRmz));
1413cdf0e10cSrcweir }
1414cdf0e10cSrcweir 
ScKapz()1415cdf0e10cSrcweir void ScInterpreter::ScKapz()
1416cdf0e10cSrcweir {
1417cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKapz" );
1418cdf0e10cSrcweir     double nZins, nZr, nZzr, nBw, nZw = 0, nFlag = 0, nRmz, nZinsz;
1419cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
1420cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
1421cdf0e10cSrcweir     if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
1422cdf0e10cSrcweir         return;
1423cdf0e10cSrcweir     if (nParamCount == 6)
1424cdf0e10cSrcweir         nFlag = GetDouble();
1425cdf0e10cSrcweir     if (nParamCount >= 5)
1426cdf0e10cSrcweir         nZw   = GetDouble();
1427cdf0e10cSrcweir     nBw   = GetDouble();
1428cdf0e10cSrcweir     nZzr  = GetDouble();
1429cdf0e10cSrcweir     nZr   = GetDouble();
1430cdf0e10cSrcweir     nZins = GetDouble();
1431cdf0e10cSrcweir     if (nZr < 1.0 || nZr > nZzr)
1432cdf0e10cSrcweir         PushIllegalArgument();
1433cdf0e10cSrcweir     else
1434cdf0e10cSrcweir     {
1435cdf0e10cSrcweir         nZinsz = ScGetZinsZ(nZins, nZr, nZzr, nBw, nZw, nFlag, nRmz);
1436cdf0e10cSrcweir         PushDouble(nRmz - nZinsz);
1437cdf0e10cSrcweir     }
1438cdf0e10cSrcweir }
1439cdf0e10cSrcweir 
ScKumZinsZ()1440cdf0e10cSrcweir void ScInterpreter::ScKumZinsZ()
1441cdf0e10cSrcweir {
1442cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKumZinsZ" );
1443cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
1444cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 6 ) )
1445cdf0e10cSrcweir     {
1446cdf0e10cSrcweir         double fZins, fZzr, fBw, fAnfang, fEnde, fF, fRmz, fZinsZ;
1447cdf0e10cSrcweir         fF      = GetDouble();
1448cdf0e10cSrcweir         fEnde   = ::rtl::math::approxFloor(GetDouble());
1449cdf0e10cSrcweir         fAnfang = ::rtl::math::approxFloor(GetDouble());
1450cdf0e10cSrcweir         fBw     = GetDouble();
1451cdf0e10cSrcweir         fZzr    = GetDouble();
1452cdf0e10cSrcweir         fZins   = GetDouble();
1453cdf0e10cSrcweir         if (fAnfang < 1.0 || fEnde < fAnfang || fZins <= 0.0 ||
1454cdf0e10cSrcweir             fEnde > fZzr  || fZzr <= 0.0 || fBw <= 0.0)
1455cdf0e10cSrcweir             PushIllegalArgument();
1456cdf0e10cSrcweir         else
1457cdf0e10cSrcweir         {
1458cdf0e10cSrcweir             sal_uLong nAnfang = (sal_uLong) fAnfang;
1459cdf0e10cSrcweir             sal_uLong nEnde = (sal_uLong) fEnde ;
1460cdf0e10cSrcweir             fRmz = ScGetRmz(fZins, fZzr, fBw, 0.0, fF);
1461cdf0e10cSrcweir             fZinsZ = 0.0;
1462cdf0e10cSrcweir             if (nAnfang == 1)
1463cdf0e10cSrcweir             {
1464cdf0e10cSrcweir                 if (fF <= 0.0)
1465cdf0e10cSrcweir                     fZinsZ = -fBw;
1466cdf0e10cSrcweir                 nAnfang++;
1467cdf0e10cSrcweir             }
1468cdf0e10cSrcweir             for (sal_uLong i = nAnfang; i <= nEnde; i++)
1469cdf0e10cSrcweir             {
1470cdf0e10cSrcweir                 if (fF > 0.0)
1471cdf0e10cSrcweir                     fZinsZ += ScGetZw(fZins, (double)(i-2), fRmz, fBw, 1.0) - fRmz;
1472cdf0e10cSrcweir                 else
1473cdf0e10cSrcweir                     fZinsZ += ScGetZw(fZins, (double)(i-1), fRmz, fBw, 0.0);
1474cdf0e10cSrcweir             }
1475cdf0e10cSrcweir             fZinsZ *= fZins;
1476cdf0e10cSrcweir             PushDouble(fZinsZ);
1477cdf0e10cSrcweir         }
1478cdf0e10cSrcweir     }
1479cdf0e10cSrcweir }
1480cdf0e10cSrcweir 
ScKumKapZ()1481cdf0e10cSrcweir void ScInterpreter::ScKumKapZ()
1482cdf0e10cSrcweir {
1483cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKumKapZ" );
1484cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_CURRENCY;
1485cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 6 ) )
1486cdf0e10cSrcweir     {
1487cdf0e10cSrcweir         double fZins, fZzr, fBw, fAnfang, fEnde, fF, fRmz, fKapZ;
1488cdf0e10cSrcweir         fF      = GetDouble();
1489cdf0e10cSrcweir         fEnde   = ::rtl::math::approxFloor(GetDouble());
1490cdf0e10cSrcweir         fAnfang = ::rtl::math::approxFloor(GetDouble());
1491cdf0e10cSrcweir         fBw     = GetDouble();
1492cdf0e10cSrcweir         fZzr    = GetDouble();
1493cdf0e10cSrcweir         fZins   = GetDouble();
1494cdf0e10cSrcweir         if (fAnfang < 1.0 || fEnde < fAnfang || fZins <= 0.0 ||
1495cdf0e10cSrcweir             fEnde > fZzr  || fZzr <= 0.0 || fBw <= 0.0)
1496cdf0e10cSrcweir             PushIllegalArgument();
1497cdf0e10cSrcweir         else
1498cdf0e10cSrcweir         {
1499cdf0e10cSrcweir             fRmz = ScGetRmz(fZins, fZzr, fBw, 0.0, fF);
1500cdf0e10cSrcweir             fKapZ = 0.0;
1501cdf0e10cSrcweir             sal_uLong nAnfang = (sal_uLong) fAnfang;
1502cdf0e10cSrcweir             sal_uLong nEnde = (sal_uLong) fEnde;
1503cdf0e10cSrcweir             if (nAnfang == 1)
1504cdf0e10cSrcweir             {
1505cdf0e10cSrcweir                 if (fF <= 0.0)
1506cdf0e10cSrcweir                     fKapZ = fRmz + fBw * fZins;
1507cdf0e10cSrcweir                 else
1508cdf0e10cSrcweir                     fKapZ = fRmz;
1509cdf0e10cSrcweir                 nAnfang++;
1510cdf0e10cSrcweir             }
1511cdf0e10cSrcweir             for (sal_uLong i = nAnfang; i <= nEnde; i++)
1512cdf0e10cSrcweir             {
1513cdf0e10cSrcweir                 if (fF > 0.0)
1514cdf0e10cSrcweir                     fKapZ += fRmz - (ScGetZw(fZins, (double)(i-2), fRmz, fBw, 1.0) - fRmz) * fZins;
1515cdf0e10cSrcweir                 else
1516cdf0e10cSrcweir                     fKapZ += fRmz - ScGetZw(fZins, (double)(i-1), fRmz, fBw, 0.0) * fZins;
1517cdf0e10cSrcweir             }
1518cdf0e10cSrcweir             PushDouble(fKapZ);
1519cdf0e10cSrcweir         }
1520cdf0e10cSrcweir     }
1521cdf0e10cSrcweir }
1522cdf0e10cSrcweir 
ScEffektiv()1523cdf0e10cSrcweir void ScInterpreter::ScEffektiv()
1524cdf0e10cSrcweir {
1525cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEffektiv" );
1526cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_PERCENT;
1527cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 2 ) )
1528cdf0e10cSrcweir     {
1529cdf0e10cSrcweir         double fPerioden = GetDouble();
1530cdf0e10cSrcweir         double fNominal = GetDouble();
1531cdf0e10cSrcweir         if (fPerioden < 1.0 || fNominal <= 0.0)
1532cdf0e10cSrcweir             PushIllegalArgument();
1533cdf0e10cSrcweir         else
1534cdf0e10cSrcweir         {
1535cdf0e10cSrcweir             fPerioden = ::rtl::math::approxFloor(fPerioden);
1536cdf0e10cSrcweir             PushDouble(pow(1.0 + fNominal/fPerioden, fPerioden) - 1.0);
1537cdf0e10cSrcweir         }
1538cdf0e10cSrcweir     }
1539cdf0e10cSrcweir }
1540cdf0e10cSrcweir 
ScNominal()1541cdf0e10cSrcweir void ScInterpreter::ScNominal()
1542cdf0e10cSrcweir {
1543cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNominal" );
1544cdf0e10cSrcweir     nFuncFmtType = NUMBERFORMAT_PERCENT;
1545cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 2 ) )
1546cdf0e10cSrcweir     {
1547cdf0e10cSrcweir         double fPerioden = GetDouble();
1548cdf0e10cSrcweir         double fEffektiv = GetDouble();
1549cdf0e10cSrcweir         if (fPerioden < 1.0 || fEffektiv <= 0.0)
1550cdf0e10cSrcweir             PushIllegalArgument();
1551cdf0e10cSrcweir         else
1552cdf0e10cSrcweir         {
1553cdf0e10cSrcweir             fPerioden = ::rtl::math::approxFloor(fPerioden);
1554cdf0e10cSrcweir             PushDouble( (pow(fEffektiv + 1.0, 1.0 / fPerioden) - 1.0) * fPerioden );
1555cdf0e10cSrcweir         }
1556cdf0e10cSrcweir     }
1557cdf0e10cSrcweir }
1558cdf0e10cSrcweir 
ScMod()1559cdf0e10cSrcweir void ScInterpreter::ScMod()
1560cdf0e10cSrcweir {
1561cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMod" );
1562cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 2 ) )
1563cdf0e10cSrcweir     {
1564cdf0e10cSrcweir         double fVal2 = GetDouble(); // Denominator
1565cdf0e10cSrcweir         double fVal1 = GetDouble(); // Numerator
1566cdf0e10cSrcweir         if (fVal2 == floor(fVal2))  // a pure integral number stored in double
1567cdf0e10cSrcweir         {
1568cdf0e10cSrcweir             double fResult = fmod(fVal1,fVal2);
1569cdf0e10cSrcweir             if ( (fResult != 0.0) &&
1570cdf0e10cSrcweir                 ((fVal1 > 0.0 && fVal2 < 0.0) || (fVal1 < 0.0 && fVal2 > 0.0)))
1571cdf0e10cSrcweir                 fResult += fVal2 ;
1572cdf0e10cSrcweir             PushDouble( fResult );
1573cdf0e10cSrcweir         }
1574cdf0e10cSrcweir         else
1575cdf0e10cSrcweir         {
1576cdf0e10cSrcweir             PushDouble( ::rtl::math::approxSub( fVal1,
1577cdf0e10cSrcweir                     ::rtl::math::approxFloor(fVal1 / fVal2) * fVal2));
1578cdf0e10cSrcweir         }
1579cdf0e10cSrcweir     }
1580cdf0e10cSrcweir }
1581cdf0e10cSrcweir 
1582cdf0e10cSrcweir /** (Goal Seek) Find a value of x that is a root of f(x)
1583cdf0e10cSrcweir 
1584cdf0e10cSrcweir     This function is used internally for the goal seek operation.  It uses the
1585cdf0e10cSrcweir     Regula Falsi (aka false position) algorithm to find a root of f(x).  The
1586cdf0e10cSrcweir     start value and the target value are to be given by the user in the
1587cdf0e10cSrcweir     goal seek dialog.  The f(x) in this case is defined as the formula in the
1588cdf0e10cSrcweir     formula cell minus target value.  This function may also perform additional
1589cdf0e10cSrcweir     search in the horizontal directions when the f(x) is discrete in order to
1590cdf0e10cSrcweir     ensure a non-zero slope necessary for deriving a subsequent x that is
1591cdf0e10cSrcweir     reasonably close to the root of interest.
1592cdf0e10cSrcweir 
1593cdf0e10cSrcweir     @change 24.10.2004 by Kohei Yoshida (kohei@openoffice.org)
1594cdf0e10cSrcweir 
1595cdf0e10cSrcweir     @see #i28955#
1596cdf0e10cSrcweir */
ScBackSolver()1597cdf0e10cSrcweir void ScInterpreter::ScBackSolver()
1598cdf0e10cSrcweir {
1599cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBackSolver" );
1600cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 3 ) )
1601cdf0e10cSrcweir     {
1602cdf0e10cSrcweir         sal_Bool bDoneIteration = sal_False;
1603cdf0e10cSrcweir         ScAddress aValueAdr, aFormulaAdr;
1604cdf0e10cSrcweir         double fTargetVal = GetDouble();
1605cdf0e10cSrcweir         PopSingleRef( aFormulaAdr );
1606cdf0e10cSrcweir         PopSingleRef( aValueAdr );
1607cdf0e10cSrcweir 
1608cdf0e10cSrcweir         if (nGlobalError == 0)
1609cdf0e10cSrcweir         {
1610cdf0e10cSrcweir             ScBaseCell* pVCell = GetCell( aValueAdr );
1611cdf0e10cSrcweir             // CELLTYPE_NOTE: kein Value aber von Formel referiert
1612cdf0e10cSrcweir             sal_Bool bTempCell = (!pVCell || pVCell->GetCellType() == CELLTYPE_NOTE);
1613cdf0e10cSrcweir             ScBaseCell* pFCell = GetCell( aFormulaAdr );
1614cdf0e10cSrcweir 
1615cdf0e10cSrcweir             if ( ((pVCell && pVCell->GetCellType() == CELLTYPE_VALUE) || bTempCell)
1616cdf0e10cSrcweir                 && pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA )
1617cdf0e10cSrcweir             {
1618cdf0e10cSrcweir                 ScRange aVRange( aValueAdr, aValueAdr );    // fuer SetDirty
1619cdf0e10cSrcweir                 double fSaveVal; // Original value to be restored later if necessary
1620cdf0e10cSrcweir                 ScPostIt* pNote = 0;
1621cdf0e10cSrcweir 
1622cdf0e10cSrcweir                 if ( bTempCell )
1623cdf0e10cSrcweir                 {
1624cdf0e10cSrcweir                     pNote = pVCell ? pVCell->ReleaseNote() : 0;
1625cdf0e10cSrcweir                     fSaveVal = 0.0;
1626cdf0e10cSrcweir                     pVCell = new ScValueCell( fSaveVal );
1627cdf0e10cSrcweir                     pDok->PutCell( aValueAdr, pVCell );
1628cdf0e10cSrcweir                 }
1629cdf0e10cSrcweir                 else
1630cdf0e10cSrcweir                     fSaveVal = GetCellValue( aValueAdr, pVCell );
1631cdf0e10cSrcweir 
1632cdf0e10cSrcweir                 const sal_uInt16 nMaxIter = 100;
1633cdf0e10cSrcweir                 const double fEps = 1E-10;
1634cdf0e10cSrcweir                 const double fDelta = 1E-6;
1635cdf0e10cSrcweir 
1636cdf0e10cSrcweir                 double fBestX, fXPrev;
1637cdf0e10cSrcweir                 double fBestF, fFPrev;
1638cdf0e10cSrcweir                 fBestX = fXPrev = fSaveVal;
1639cdf0e10cSrcweir 
1640cdf0e10cSrcweir                 ScFormulaCell* pFormula = (ScFormulaCell*) pFCell;
1641cdf0e10cSrcweir                 ScValueCell* pValue = (ScValueCell*) pVCell;
1642cdf0e10cSrcweir 
1643cdf0e10cSrcweir                 pFormula->Interpret();
1644cdf0e10cSrcweir                 sal_Bool bError = ( pFormula->GetErrCode() != 0 );
1645cdf0e10cSrcweir                 // bError always corresponds with fF
1646cdf0e10cSrcweir 
1647cdf0e10cSrcweir                 fFPrev = pFormula->GetValue() - fTargetVal;
1648cdf0e10cSrcweir 
1649cdf0e10cSrcweir                 fBestF = fabs( fFPrev );
1650cdf0e10cSrcweir                 if ( fBestF < fDelta )
1651cdf0e10cSrcweir                     bDoneIteration = sal_True;
1652cdf0e10cSrcweir 
1653cdf0e10cSrcweir                 double fX = fXPrev + fEps;
1654cdf0e10cSrcweir                 double fF = fFPrev;
1655cdf0e10cSrcweir                 double fSlope;
1656cdf0e10cSrcweir 
1657cdf0e10cSrcweir                 sal_uInt16 nIter = 0;
1658cdf0e10cSrcweir 
1659cdf0e10cSrcweir                 sal_Bool bHorMoveError = sal_False;
1660cdf0e10cSrcweir                                                 // Nach der Regula Falsi Methode
1661cdf0e10cSrcweir                 while ( !bDoneIteration && ( nIter++ < nMaxIter ) )
1662cdf0e10cSrcweir                 {
1663cdf0e10cSrcweir                     pValue->SetValue( fX );
1664cdf0e10cSrcweir                     pDok->SetDirty( aVRange );
1665cdf0e10cSrcweir                     pFormula->Interpret();
1666cdf0e10cSrcweir                     bError = ( pFormula->GetErrCode() != 0 );
1667cdf0e10cSrcweir                     fF = pFormula->GetValue() - fTargetVal;
1668cdf0e10cSrcweir 
1669cdf0e10cSrcweir                     if ( fF == fFPrev && !bError )
1670cdf0e10cSrcweir                     {
1671cdf0e10cSrcweir                         // HORIZONTAL SEARCH: Keep moving x in both directions until the f(x)
1672cdf0e10cSrcweir                         // becomes different from the previous f(x).  This routine is needed
1673cdf0e10cSrcweir                         // when a given function is discrete, in which case the resulting slope
1674cdf0e10cSrcweir                         // may become zero which ultimately causes the goal seek operation
1675cdf0e10cSrcweir                         // to fail. #i28955#
1676cdf0e10cSrcweir 
1677cdf0e10cSrcweir                         sal_uInt16 nHorIter = 0;
1678cdf0e10cSrcweir                         const double fHorStepAngle = 5.0;
1679cdf0e10cSrcweir                         const double fHorMaxAngle = 80.0;
1680cdf0e10cSrcweir                         int nHorMaxIter = static_cast<int>( fHorMaxAngle / fHorStepAngle );
1681cdf0e10cSrcweir                         sal_Bool bDoneHorMove = sal_False;
1682cdf0e10cSrcweir 
1683cdf0e10cSrcweir                         while ( !bDoneHorMove && !bHorMoveError && nHorIter++ < nHorMaxIter )
1684cdf0e10cSrcweir                         {
1685cdf0e10cSrcweir                             double fHorAngle = fHorStepAngle * static_cast<double>( nHorIter );
1686cdf0e10cSrcweir                             double fHorTangent = ::rtl::math::tan( fHorAngle * F_PI / 180 );
1687cdf0e10cSrcweir 
1688cdf0e10cSrcweir                             sal_uInt16 nIdx = 0;
1689cdf0e10cSrcweir                             while( nIdx++ < 2 && !bDoneHorMove )
1690cdf0e10cSrcweir                             {
1691cdf0e10cSrcweir                                 double fHorX;
1692cdf0e10cSrcweir                                 if ( nIdx == 1 )
1693cdf0e10cSrcweir                                     fHorX = fX + fabs(fF)*fHorTangent;
1694cdf0e10cSrcweir                                 else
1695cdf0e10cSrcweir                                     fHorX = fX - fabs(fF)*fHorTangent;
1696cdf0e10cSrcweir 
1697cdf0e10cSrcweir                                 pValue->SetValue( fHorX );
1698cdf0e10cSrcweir                                 pDok->SetDirty( aVRange );
1699cdf0e10cSrcweir                                 pFormula->Interpret();
1700cdf0e10cSrcweir                                 bHorMoveError = ( pFormula->GetErrCode() != 0 );
1701cdf0e10cSrcweir                                 if ( bHorMoveError )
1702cdf0e10cSrcweir                                     break;
1703cdf0e10cSrcweir 
1704cdf0e10cSrcweir                                 fF = pFormula->GetValue() - fTargetVal;
1705cdf0e10cSrcweir                                 if ( fF != fFPrev )
1706cdf0e10cSrcweir                                 {
1707cdf0e10cSrcweir                                     fX = fHorX;
1708cdf0e10cSrcweir                                     bDoneHorMove = sal_True;
1709cdf0e10cSrcweir                                 }
1710cdf0e10cSrcweir                             }
1711cdf0e10cSrcweir                         }
1712cdf0e10cSrcweir                         if ( !bDoneHorMove )
1713cdf0e10cSrcweir                             bHorMoveError = sal_True;
1714cdf0e10cSrcweir                     }
1715cdf0e10cSrcweir 
1716cdf0e10cSrcweir                     if ( bError )
1717cdf0e10cSrcweir                     {
1718cdf0e10cSrcweir                         // move closer to last valid value (fXPrev), keep fXPrev & fFPrev
1719cdf0e10cSrcweir                         double fDiff = ( fXPrev - fX ) / 2;
1720cdf0e10cSrcweir                         if (fabs(fDiff) < fEps)
1721cdf0e10cSrcweir                             fDiff = (fDiff < 0.0) ? - fEps : fEps;
1722cdf0e10cSrcweir                         fX += fDiff;
1723cdf0e10cSrcweir                     }
1724cdf0e10cSrcweir                     else if ( bHorMoveError )
1725cdf0e10cSrcweir                         break;
1726cdf0e10cSrcweir                     else if ( fabs(fF) < fDelta )
1727cdf0e10cSrcweir                     {
1728cdf0e10cSrcweir                         // converged to root
1729cdf0e10cSrcweir                         fBestX = fX;
1730cdf0e10cSrcweir                         bDoneIteration = sal_True;
1731cdf0e10cSrcweir                     }
1732cdf0e10cSrcweir                     else
1733cdf0e10cSrcweir                     {
1734cdf0e10cSrcweir                         if ( fabs(fF) + fDelta < fBestF )
1735cdf0e10cSrcweir                         {
1736cdf0e10cSrcweir                             fBestX = fX;
1737cdf0e10cSrcweir                             fBestF = fabs(fF);
1738cdf0e10cSrcweir                         }
1739cdf0e10cSrcweir 
1740cdf0e10cSrcweir                         if ( ( fXPrev - fX ) != 0 )
1741cdf0e10cSrcweir                         {
1742cdf0e10cSrcweir                             fSlope = ( fFPrev - fF ) / ( fXPrev - fX );
1743cdf0e10cSrcweir                             if ( fabs( fSlope ) < fEps )
1744cdf0e10cSrcweir                                 fSlope = fSlope < 0.0 ? -fEps : fEps;
1745cdf0e10cSrcweir                         }
1746cdf0e10cSrcweir                         else
1747cdf0e10cSrcweir                             fSlope = fEps;
1748cdf0e10cSrcweir 
1749cdf0e10cSrcweir                         fXPrev = fX;
1750cdf0e10cSrcweir                         fFPrev = fF;
1751cdf0e10cSrcweir                         fX = fX - ( fF / fSlope );
1752cdf0e10cSrcweir                     }
1753cdf0e10cSrcweir                 }
1754cdf0e10cSrcweir 
1755cdf0e10cSrcweir                 // Try a nice rounded input value if possible.
1756cdf0e10cSrcweir                 const double fNiceDelta = (bDoneIteration && fabs(fBestX) >= 1e-3 ? 1e-3 : fDelta);
1757cdf0e10cSrcweir                 double nX = ::rtl::math::approxFloor((fBestX / fNiceDelta) + 0.5) * fNiceDelta;
1758cdf0e10cSrcweir //                double nX = ::rtl::math::approxFloor((fBestX / fDelta) + 0.5) * fDelta;
1759cdf0e10cSrcweir 
1760cdf0e10cSrcweir                 if ( bDoneIteration )
1761cdf0e10cSrcweir                 {
1762cdf0e10cSrcweir                     pValue->SetValue( nX );
1763cdf0e10cSrcweir                     pDok->SetDirty( aVRange );
1764cdf0e10cSrcweir                     pFormula->Interpret();
1765cdf0e10cSrcweir                     if ( fabs( pFormula->GetValue() - fTargetVal ) > fabs( fF ) )
1766cdf0e10cSrcweir                         nX = fBestX;
1767cdf0e10cSrcweir                 }
1768cdf0e10cSrcweir                 else if ( bError || bHorMoveError )
1769cdf0e10cSrcweir                 {
1770cdf0e10cSrcweir                     nX = fBestX;
1771cdf0e10cSrcweir                 }
1772cdf0e10cSrcweir                 if ( bTempCell )
1773cdf0e10cSrcweir                 {
1774cdf0e10cSrcweir                     pVCell = pNote ? new ScNoteCell( pNote ) : 0;
1775cdf0e10cSrcweir                     pDok->PutCell( aValueAdr, pVCell );
1776cdf0e10cSrcweir                 }
1777cdf0e10cSrcweir                 else
1778cdf0e10cSrcweir                     pValue->SetValue( fSaveVal );
1779cdf0e10cSrcweir                 pDok->SetDirty( aVRange );
1780cdf0e10cSrcweir                 pFormula->Interpret();
1781cdf0e10cSrcweir                 if ( !bDoneIteration )
1782cdf0e10cSrcweir                     SetError(NOTAVAILABLE);
1783cdf0e10cSrcweir                 PushDouble(nX);
1784cdf0e10cSrcweir             }
1785cdf0e10cSrcweir             else
1786cdf0e10cSrcweir             {
1787cdf0e10cSrcweir                 if ( !bDoneIteration )
1788cdf0e10cSrcweir                     SetError(NOTAVAILABLE);
1789cdf0e10cSrcweir                 PushInt(0);         // falsche Zelltypen
1790cdf0e10cSrcweir             }
1791cdf0e10cSrcweir         }
1792cdf0e10cSrcweir         else
1793cdf0e10cSrcweir         {
1794cdf0e10cSrcweir             if ( !bDoneIteration )
1795cdf0e10cSrcweir                 SetError(NOTAVAILABLE);
1796cdf0e10cSrcweir             PushInt(0);             // nGlobalError
1797cdf0e10cSrcweir         }
1798cdf0e10cSrcweir     }
1799cdf0e10cSrcweir }
1800cdf0e10cSrcweir 
ScIntersect()1801cdf0e10cSrcweir void ScInterpreter::ScIntersect()
1802cdf0e10cSrcweir {
1803cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIntersect" );
1804cdf0e10cSrcweir     formula::FormulaTokenRef p2nd = PopToken();
1805cdf0e10cSrcweir     formula::FormulaTokenRef p1st = PopToken();
1806cdf0e10cSrcweir 
1807cdf0e10cSrcweir     if (nGlobalError || !p2nd || !p1st)
1808cdf0e10cSrcweir     {
1809cdf0e10cSrcweir         PushIllegalArgument();
1810cdf0e10cSrcweir         return;
1811cdf0e10cSrcweir     } // if (nGlobalError || !xT2 || !xT1)
1812cdf0e10cSrcweir 
1813cdf0e10cSrcweir     StackVar sv1 = p1st->GetType();
1814cdf0e10cSrcweir     StackVar sv2 = p2nd->GetType();
1815cdf0e10cSrcweir     if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
1816cdf0e10cSrcweir         (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
1817cdf0e10cSrcweir     {
1818cdf0e10cSrcweir         PushIllegalArgument();
1819cdf0e10cSrcweir         return;
1820cdf0e10cSrcweir     }
1821cdf0e10cSrcweir 
1822cdf0e10cSrcweir     ScToken* x1 = static_cast<ScToken*>(p1st.get());
1823cdf0e10cSrcweir     ScToken* x2 = static_cast<ScToken*>(p2nd.get());
1824cdf0e10cSrcweir     if (sv1 == svRefList || sv2 == svRefList)
1825cdf0e10cSrcweir     {
1826cdf0e10cSrcweir         // Now this is a bit nasty but it simplifies things, and having
1827cdf0e10cSrcweir         // intersections with lists isn't too common, if at all..
1828cdf0e10cSrcweir         // Convert a reference to list.
1829cdf0e10cSrcweir         ScToken* xt[2] = { x1, x2 };
1830cdf0e10cSrcweir         StackVar sv[2] = { sv1, sv2 };
1831cdf0e10cSrcweir         for (size_t i=0; i<2; ++i)
1832cdf0e10cSrcweir         {
1833cdf0e10cSrcweir             if (sv[i] == svSingleRef)
1834cdf0e10cSrcweir             {
1835cdf0e10cSrcweir                 ScComplexRefData aRef;
1836cdf0e10cSrcweir                 aRef.Ref1 = aRef.Ref2 = xt[i]->GetSingleRef();
1837cdf0e10cSrcweir                 xt[i] = new ScRefListToken;
1838cdf0e10cSrcweir                 xt[i]->GetRefList()->push_back( aRef);
1839cdf0e10cSrcweir             }
1840cdf0e10cSrcweir             else if (sv[i] == svDoubleRef)
1841cdf0e10cSrcweir             {
1842cdf0e10cSrcweir                 ScComplexRefData aRef = xt[i]->GetDoubleRef();
1843cdf0e10cSrcweir                 xt[i] = new ScRefListToken;
1844cdf0e10cSrcweir                 xt[i]->GetRefList()->push_back( aRef);
1845cdf0e10cSrcweir             }
1846cdf0e10cSrcweir         }
1847cdf0e10cSrcweir         x1 = xt[0], x2 = xt[1];
1848cdf0e10cSrcweir 
1849cdf0e10cSrcweir         x1->CalcAbsIfRel( aPos);
1850cdf0e10cSrcweir         x2->CalcAbsIfRel( aPos);
1851cdf0e10cSrcweir         ScTokenRef xRes = new ScRefListToken;
1852cdf0e10cSrcweir         ScRefList* pRefList = xRes->GetRefList();
1853cdf0e10cSrcweir         ScRefList::const_iterator end1( x1->GetRefList()->end());
1854cdf0e10cSrcweir         ScRefList::const_iterator end2( x2->GetRefList()->end());
1855cdf0e10cSrcweir         for (ScRefList::const_iterator it1( x1->GetRefList()->begin());
1856cdf0e10cSrcweir                 it1 != end1; ++it1)
1857cdf0e10cSrcweir         {
1858cdf0e10cSrcweir             const ScSingleRefData& r11 = (*it1).Ref1;
1859cdf0e10cSrcweir             const ScSingleRefData& r12 = (*it1).Ref2;
1860cdf0e10cSrcweir             for (ScRefList::const_iterator it2( x2->GetRefList()->begin());
1861cdf0e10cSrcweir                     it2 != end2; ++it2)
1862cdf0e10cSrcweir             {
1863cdf0e10cSrcweir                 const ScSingleRefData& r21 = (*it2).Ref1;
1864cdf0e10cSrcweir                 const ScSingleRefData& r22 = (*it2).Ref2;
1865cdf0e10cSrcweir                 SCCOL nCol1 = ::std::max( r11.nCol, r21.nCol);
1866cdf0e10cSrcweir                 SCROW nRow1 = ::std::max( r11.nRow, r21.nRow);
1867cdf0e10cSrcweir                 SCTAB nTab1 = ::std::max( r11.nTab, r21.nTab);
1868cdf0e10cSrcweir                 SCCOL nCol2 = ::std::min( r12.nCol, r22.nCol);
1869cdf0e10cSrcweir                 SCROW nRow2 = ::std::min( r12.nRow, r22.nRow);
1870cdf0e10cSrcweir                 SCTAB nTab2 = ::std::min( r12.nTab, r22.nTab);
1871cdf0e10cSrcweir                 if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
1872cdf0e10cSrcweir                     ;   // nothing
1873cdf0e10cSrcweir                 else
1874cdf0e10cSrcweir                 {
1875cdf0e10cSrcweir                     ScComplexRefData aRef;
1876cdf0e10cSrcweir                     aRef.InitRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
1877cdf0e10cSrcweir                     pRefList->push_back( aRef);
1878cdf0e10cSrcweir                 }
1879cdf0e10cSrcweir             }
1880cdf0e10cSrcweir         }
1881cdf0e10cSrcweir         size_t n = pRefList->size();
1882cdf0e10cSrcweir         if (!n)
1883cdf0e10cSrcweir             PushError( errNoRef);
1884cdf0e10cSrcweir         else if (n == 1)
1885cdf0e10cSrcweir         {
1886cdf0e10cSrcweir             const ScComplexRefData& rRef = (*pRefList)[0];
1887cdf0e10cSrcweir             if (rRef.Ref1 == rRef.Ref2)
1888cdf0e10cSrcweir                 PushTempToken( new ScSingleRefToken( rRef.Ref1));
1889cdf0e10cSrcweir             else
1890cdf0e10cSrcweir                 PushTempToken( new ScDoubleRefToken( rRef));
1891cdf0e10cSrcweir         }
1892cdf0e10cSrcweir         else
1893cdf0e10cSrcweir             PushTempToken( xRes);
1894cdf0e10cSrcweir     }
1895cdf0e10cSrcweir     else
1896cdf0e10cSrcweir     {
1897cdf0e10cSrcweir         ScToken* pt[2] = { x1, x2 };
1898cdf0e10cSrcweir         StackVar sv[2] = { sv1, sv2 };
1899cdf0e10cSrcweir         SCCOL nC1[2], nC2[2];
1900cdf0e10cSrcweir         SCROW nR1[2], nR2[2];
1901cdf0e10cSrcweir         SCTAB nT1[2], nT2[2];
1902cdf0e10cSrcweir         for (size_t i=0; i<2; ++i)
1903cdf0e10cSrcweir         {
1904cdf0e10cSrcweir             switch (sv[i])
1905cdf0e10cSrcweir             {
1906cdf0e10cSrcweir                 case svSingleRef:
1907cdf0e10cSrcweir                 case svDoubleRef:
1908cdf0e10cSrcweir                     pt[i]->CalcAbsIfRel( aPos);
1909cdf0e10cSrcweir                     {
1910cdf0e10cSrcweir                         const ScSingleRefData& r = pt[i]->GetSingleRef();
1911cdf0e10cSrcweir                         nC1[i] = r.nCol;
1912cdf0e10cSrcweir                         nR1[i] = r.nRow;
1913cdf0e10cSrcweir                         nT1[i] = r.nTab;
1914cdf0e10cSrcweir                     }
1915cdf0e10cSrcweir                     if (sv[i] == svDoubleRef)
1916cdf0e10cSrcweir                     {
1917cdf0e10cSrcweir                         const ScSingleRefData& r = pt[i]->GetSingleRef2();
1918cdf0e10cSrcweir                         nC2[i] = r.nCol;
1919cdf0e10cSrcweir                         nR2[i] = r.nRow;
1920cdf0e10cSrcweir                         nT2[i] = r.nTab;
1921cdf0e10cSrcweir                     }
1922cdf0e10cSrcweir                     else
1923cdf0e10cSrcweir                     {
1924cdf0e10cSrcweir                         nC2[i] = nC1[i];
1925cdf0e10cSrcweir                         nR2[i] = nR1[i];
1926cdf0e10cSrcweir                         nT2[i] = nT1[i];
1927cdf0e10cSrcweir                     }
1928cdf0e10cSrcweir                     break;
1929cdf0e10cSrcweir                 default:
1930cdf0e10cSrcweir                     ;   // nothing, prevent compiler warning
1931cdf0e10cSrcweir             }
1932cdf0e10cSrcweir         }
1933cdf0e10cSrcweir         SCCOL nCol1 = ::std::max( nC1[0], nC1[1]);
1934cdf0e10cSrcweir         SCROW nRow1 = ::std::max( nR1[0], nR1[1]);
1935cdf0e10cSrcweir         SCTAB nTab1 = ::std::max( nT1[0], nT1[1]);
1936cdf0e10cSrcweir         SCCOL nCol2 = ::std::min( nC2[0], nC2[1]);
1937cdf0e10cSrcweir         SCROW nRow2 = ::std::min( nR2[0], nR2[1]);
1938cdf0e10cSrcweir         SCTAB nTab2 = ::std::min( nT2[0], nT2[1]);
1939cdf0e10cSrcweir         if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
1940cdf0e10cSrcweir             PushError( errNoRef);
1941cdf0e10cSrcweir         else if (nCol2 == nCol1 && nRow2 == nRow1 && nTab2 == nTab1)
1942cdf0e10cSrcweir             PushSingleRef( nCol1, nRow1, nTab1);
1943cdf0e10cSrcweir         else
1944cdf0e10cSrcweir             PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
1945cdf0e10cSrcweir     }
1946cdf0e10cSrcweir }
1947cdf0e10cSrcweir 
1948cdf0e10cSrcweir 
ScRangeFunc()1949cdf0e10cSrcweir void ScInterpreter::ScRangeFunc()
1950cdf0e10cSrcweir {
1951cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRangeFunc" );
1952cdf0e10cSrcweir     formula::FormulaTokenRef x2 = PopToken();
1953cdf0e10cSrcweir     formula::FormulaTokenRef x1 = PopToken();
1954cdf0e10cSrcweir 
1955cdf0e10cSrcweir     if (nGlobalError || !x2 || !x1)
1956cdf0e10cSrcweir     {
1957cdf0e10cSrcweir         PushIllegalArgument();
1958cdf0e10cSrcweir         return;
1959cdf0e10cSrcweir     } // if (nGlobalError || !xT2 || !xT1)
1960cdf0e10cSrcweir     FormulaTokenRef xRes = ScToken::ExtendRangeReference( *x1, *x2, aPos, false);
1961cdf0e10cSrcweir     if (!xRes)
1962cdf0e10cSrcweir         PushIllegalArgument();
1963cdf0e10cSrcweir     else
1964cdf0e10cSrcweir         PushTempToken( xRes);
1965cdf0e10cSrcweir }
1966cdf0e10cSrcweir 
1967cdf0e10cSrcweir 
ScUnionFunc()1968cdf0e10cSrcweir void ScInterpreter::ScUnionFunc()
1969cdf0e10cSrcweir {
1970cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScUnionFunc" );
1971cdf0e10cSrcweir     formula::FormulaTokenRef p2nd = PopToken();
1972cdf0e10cSrcweir     formula::FormulaTokenRef p1st = PopToken();
1973cdf0e10cSrcweir 
1974cdf0e10cSrcweir     if (nGlobalError || !p2nd || !p1st)
1975cdf0e10cSrcweir     {
1976cdf0e10cSrcweir         PushIllegalArgument();
1977cdf0e10cSrcweir         return;
1978cdf0e10cSrcweir     } // if (nGlobalError || !xT2 || !xT1)
1979cdf0e10cSrcweir 
1980cdf0e10cSrcweir     StackVar sv1 = p1st->GetType();
1981cdf0e10cSrcweir     StackVar sv2 = p2nd->GetType();
1982cdf0e10cSrcweir     if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
1983cdf0e10cSrcweir         (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
1984cdf0e10cSrcweir     {
1985cdf0e10cSrcweir         PushIllegalArgument();
1986cdf0e10cSrcweir         return;
1987cdf0e10cSrcweir     }
1988cdf0e10cSrcweir 
1989cdf0e10cSrcweir     ScToken* x1 = static_cast<ScToken*>(p1st.get());
1990cdf0e10cSrcweir     ScToken* x2 = static_cast<ScToken*>(p2nd.get());
1991cdf0e10cSrcweir 
1992cdf0e10cSrcweir 
1993cdf0e10cSrcweir     ScTokenRef xRes;
1994cdf0e10cSrcweir     // Append to an existing RefList if there is one.
1995cdf0e10cSrcweir     if (sv1 == svRefList)
1996cdf0e10cSrcweir     {
1997cdf0e10cSrcweir         xRes = x1;
1998cdf0e10cSrcweir         sv1 = svUnknown;    // mark as handled
1999cdf0e10cSrcweir     }
2000cdf0e10cSrcweir     else if (sv2 == svRefList)
2001cdf0e10cSrcweir     {
2002cdf0e10cSrcweir         xRes = x2;
2003cdf0e10cSrcweir         sv2 = svUnknown;    // mark as handled
2004cdf0e10cSrcweir     }
2005cdf0e10cSrcweir     else
2006cdf0e10cSrcweir         xRes = new ScRefListToken;
2007cdf0e10cSrcweir     ScRefList* pRes = xRes->GetRefList();
2008cdf0e10cSrcweir     ScToken* pt[2] = { x1, x2 };
2009cdf0e10cSrcweir     StackVar sv[2] = { sv1, sv2 };
2010cdf0e10cSrcweir     for (size_t i=0; i<2; ++i)
2011cdf0e10cSrcweir     {
2012cdf0e10cSrcweir         if (pt[i] == xRes)
2013cdf0e10cSrcweir             continue;
2014cdf0e10cSrcweir         switch (sv[i])
2015cdf0e10cSrcweir         {
2016cdf0e10cSrcweir             case svSingleRef:
2017cdf0e10cSrcweir                 {
2018cdf0e10cSrcweir                     ScComplexRefData aRef;
2019cdf0e10cSrcweir                     aRef.Ref1 = aRef.Ref2 = pt[i]->GetSingleRef();
2020cdf0e10cSrcweir                     pRes->push_back( aRef);
2021cdf0e10cSrcweir                 }
2022cdf0e10cSrcweir                 break;
2023cdf0e10cSrcweir             case svDoubleRef:
2024cdf0e10cSrcweir                 pRes->push_back( pt[i]->GetDoubleRef());
2025cdf0e10cSrcweir                 break;
2026cdf0e10cSrcweir             case svRefList:
2027cdf0e10cSrcweir                 {
2028cdf0e10cSrcweir                     const ScRefList* p = pt[i]->GetRefList();
2029cdf0e10cSrcweir                     ScRefList::const_iterator it( p->begin());
2030cdf0e10cSrcweir                     ScRefList::const_iterator end( p->end());
2031cdf0e10cSrcweir                     for ( ; it != end; ++it)
2032cdf0e10cSrcweir                     {
2033cdf0e10cSrcweir                         pRes->push_back( *it);
2034cdf0e10cSrcweir                     }
2035cdf0e10cSrcweir                 }
2036cdf0e10cSrcweir                 break;
2037cdf0e10cSrcweir             default:
2038cdf0e10cSrcweir                 ;   // nothing, prevent compiler warning
2039cdf0e10cSrcweir         }
2040cdf0e10cSrcweir     }
2041cdf0e10cSrcweir     ValidateRef( *pRes);    // set #REF! if needed
2042cdf0e10cSrcweir     PushTempToken( xRes);
2043cdf0e10cSrcweir }
2044cdf0e10cSrcweir 
2045cdf0e10cSrcweir 
ScCurrent()2046cdf0e10cSrcweir void ScInterpreter::ScCurrent()
2047cdf0e10cSrcweir {
2048cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCurrent" );
2049cdf0e10cSrcweir     FormulaTokenRef xTok( PopToken());
2050cdf0e10cSrcweir     if (xTok)
2051cdf0e10cSrcweir     {
2052cdf0e10cSrcweir         PushTempToken( xTok);
2053cdf0e10cSrcweir         PushTempToken( xTok);
2054cdf0e10cSrcweir     }
2055cdf0e10cSrcweir     else
2056cdf0e10cSrcweir         PushError( errUnknownStackVariable);
2057cdf0e10cSrcweir }
2058cdf0e10cSrcweir 
ScStyle()2059cdf0e10cSrcweir void ScInterpreter::ScStyle()
2060cdf0e10cSrcweir {
2061cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStyle" );
2062cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
2063cdf0e10cSrcweir     if (nParamCount >= 1 && nParamCount <= 3)
2064cdf0e10cSrcweir     {
2065cdf0e10cSrcweir         String aStyle2;                             // Vorlage nach Timer
2066cdf0e10cSrcweir         if (nParamCount >= 3)
2067cdf0e10cSrcweir             aStyle2 = GetString();
2068cdf0e10cSrcweir         long nTimeOut = 0;                          // Timeout
2069cdf0e10cSrcweir         if (nParamCount >= 2)
2070cdf0e10cSrcweir             nTimeOut = (long)(GetDouble()*1000.0);
2071cdf0e10cSrcweir         String aStyle1 = GetString();               // Vorlage fuer sofort
2072cdf0e10cSrcweir 
2073cdf0e10cSrcweir         if (nTimeOut < 0)
2074cdf0e10cSrcweir             nTimeOut = 0;
2075cdf0e10cSrcweir 
2076cdf0e10cSrcweir         //
2077cdf0e10cSrcweir         //  Request ausfuehren, um Vorlage anzuwenden
2078cdf0e10cSrcweir         //
2079cdf0e10cSrcweir 
2080cdf0e10cSrcweir         if ( !pDok->IsClipOrUndo() )
2081cdf0e10cSrcweir         {
2082cdf0e10cSrcweir             SfxObjectShell* pShell = pDok->GetDocumentShell();
2083cdf0e10cSrcweir             if (pShell)
2084cdf0e10cSrcweir             {
2085cdf0e10cSrcweir                 //! notify object shell directly
2086cdf0e10cSrcweir 
2087cdf0e10cSrcweir                 ScRange aRange(aPos);
2088cdf0e10cSrcweir                 ScAutoStyleHint aHint( aRange, aStyle1, nTimeOut, aStyle2 );
2089cdf0e10cSrcweir                 pShell->Broadcast( aHint );
2090cdf0e10cSrcweir             }
2091cdf0e10cSrcweir         }
2092cdf0e10cSrcweir 
2093cdf0e10cSrcweir         PushDouble(0.0);
2094cdf0e10cSrcweir     }
2095cdf0e10cSrcweir     else
2096cdf0e10cSrcweir         PushIllegalParameter();
2097cdf0e10cSrcweir }
2098cdf0e10cSrcweir 
lcl_GetDdeLink(sfx2::LinkManager * pLinkMgr,const String & rA,const String & rT,const String & rI,sal_uInt8 nM)2099cdf0e10cSrcweir ScDdeLink* lcl_GetDdeLink( sfx2::LinkManager* pLinkMgr,
2100cdf0e10cSrcweir                                 const String& rA, const String& rT, const String& rI, sal_uInt8 nM )
2101cdf0e10cSrcweir {
2102cdf0e10cSrcweir     sal_uInt16 nCount = pLinkMgr->GetLinks().Count();
2103cdf0e10cSrcweir     for (sal_uInt16 i=0; i<nCount; i++ )
2104cdf0e10cSrcweir     {
2105cdf0e10cSrcweir         ::sfx2::SvBaseLink* pBase = *pLinkMgr->GetLinks()[i];
2106cdf0e10cSrcweir         if (pBase->ISA(ScDdeLink))
2107cdf0e10cSrcweir         {
2108cdf0e10cSrcweir             ScDdeLink* pLink = (ScDdeLink*)pBase;
2109cdf0e10cSrcweir             if ( pLink->GetAppl() == rA &&
2110cdf0e10cSrcweir                  pLink->GetTopic() == rT &&
2111cdf0e10cSrcweir                  pLink->GetItem() == rI &&
2112cdf0e10cSrcweir                  pLink->GetMode() == nM )
2113cdf0e10cSrcweir                 return pLink;
2114cdf0e10cSrcweir         }
2115cdf0e10cSrcweir     }
2116cdf0e10cSrcweir 
2117cdf0e10cSrcweir     return NULL;
2118cdf0e10cSrcweir }
2119cdf0e10cSrcweir 
ScDde()2120cdf0e10cSrcweir void ScInterpreter::ScDde()
2121cdf0e10cSrcweir {
2122cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDde" );
2123cdf0e10cSrcweir     //  Applikation, Datei, Bereich
2124cdf0e10cSrcweir     //  Application, Topic, Item
2125cdf0e10cSrcweir 
2126cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
2127cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 3, 4 ) )
2128cdf0e10cSrcweir     {
2129cdf0e10cSrcweir         sal_uInt8 nMode = SC_DDE_DEFAULT;
2130cdf0e10cSrcweir         if (nParamCount == 4)
2131cdf0e10cSrcweir             nMode = (sal_uInt8) ::rtl::math::approxFloor(GetDouble());
2132cdf0e10cSrcweir         String aItem  = GetString();
2133cdf0e10cSrcweir         String aTopic = GetString();
2134cdf0e10cSrcweir         String aAppl  = GetString();
2135cdf0e10cSrcweir 
2136cdf0e10cSrcweir         if (nMode > SC_DDE_TEXT)
2137cdf0e10cSrcweir             nMode = SC_DDE_DEFAULT;
2138cdf0e10cSrcweir 
2139cdf0e10cSrcweir         //  temporary documents (ScFunctionAccess) have no DocShell
2140cdf0e10cSrcweir         //  and no LinkManager -> abort
2141cdf0e10cSrcweir 
2142cdf0e10cSrcweir         sfx2::LinkManager* pLinkMgr = pDok->GetLinkManager();
2143cdf0e10cSrcweir         if (!pLinkMgr)
2144cdf0e10cSrcweir         {
2145cdf0e10cSrcweir             PushNoValue();
2146cdf0e10cSrcweir             return;
2147cdf0e10cSrcweir         }
2148cdf0e10cSrcweir 
2149cdf0e10cSrcweir             //  Nach dem Laden muss neu interpretiert werden (Verknuepfungen aufbauen)
2150cdf0e10cSrcweir 
2151cdf0e10cSrcweir         if ( pMyFormulaCell->GetCode()->IsRecalcModeNormal() )
2152cdf0e10cSrcweir             pMyFormulaCell->GetCode()->SetRecalcModeOnLoad();
2153cdf0e10cSrcweir 
2154cdf0e10cSrcweir             //  solange der Link nicht ausgewertet ist, Idle abklemmen
2155cdf0e10cSrcweir             //  (um zirkulaere Referenzen zu vermeiden)
2156cdf0e10cSrcweir 
2157cdf0e10cSrcweir         sal_Bool bOldDis = pDok->IsIdleDisabled();
2158cdf0e10cSrcweir         pDok->DisableIdle( sal_True );
2159cdf0e10cSrcweir 
2160cdf0e10cSrcweir             //  Link-Objekt holen / anlegen
2161cdf0e10cSrcweir 
2162cdf0e10cSrcweir         ScDdeLink* pLink = lcl_GetDdeLink( pLinkMgr, aAppl, aTopic, aItem, nMode );
2163cdf0e10cSrcweir 
2164cdf0e10cSrcweir         //! Dde-Links (zusaetzlich) effizienter am Dokument speichern !!!!!
2165cdf0e10cSrcweir         //      ScDdeLink* pLink = pDok->GetDdeLink( aAppl, aTopic, aItem );
2166cdf0e10cSrcweir 
2167cdf0e10cSrcweir         sal_Bool bWasError = ( pMyFormulaCell->GetRawError() != 0 );
2168cdf0e10cSrcweir 
2169cdf0e10cSrcweir         if (!pLink)
2170cdf0e10cSrcweir         {
2171cdf0e10cSrcweir             pLink = new ScDdeLink( pDok, aAppl, aTopic, aItem, nMode );
2172cdf0e10cSrcweir             pLinkMgr->InsertDDELink( pLink, aAppl, aTopic, aItem );
2173cdf0e10cSrcweir             if ( pLinkMgr->GetLinks().Count() == 1 )                    // erster ?
2174cdf0e10cSrcweir             {
2175cdf0e10cSrcweir                 SfxBindings* pBindings = pDok->GetViewBindings();
2176cdf0e10cSrcweir                 if (pBindings)
2177cdf0e10cSrcweir                     pBindings->Invalidate( SID_LINKS );             // Link-Manager enablen
2178cdf0e10cSrcweir             }
2179cdf0e10cSrcweir 
2180cdf0e10cSrcweir                                     //! asynchron auswerten ???
2181cdf0e10cSrcweir             pLink->TryUpdate();     //  TryUpdate ruft Update nicht mehrfach auf
2182cdf0e10cSrcweir 
2183cdf0e10cSrcweir             // StartListening erst nach dem Update, sonst circular reference
2184cdf0e10cSrcweir             pMyFormulaCell->StartListening( *pLink );
2185cdf0e10cSrcweir         }
2186cdf0e10cSrcweir         else
2187cdf0e10cSrcweir         {
2188cdf0e10cSrcweir             pMyFormulaCell->StartListening( *pLink );
2189cdf0e10cSrcweir         }
2190cdf0e10cSrcweir 
2191cdf0e10cSrcweir         //  Wenn aus dem Reschedule beim Ausfuehren des Links ein Fehler
2192cdf0e10cSrcweir         //  (z.B. zirkulaere Referenz) entstanden ist, der vorher nicht da war,
2193cdf0e10cSrcweir         //  das Fehler-Flag zuruecksetzen:
2194cdf0e10cSrcweir 
2195cdf0e10cSrcweir         if ( pMyFormulaCell->GetRawError() && !bWasError )
2196cdf0e10cSrcweir             pMyFormulaCell->SetErrCode(0);
2197cdf0e10cSrcweir 
2198cdf0e10cSrcweir             //  Wert abfragen
2199cdf0e10cSrcweir 
2200cdf0e10cSrcweir         const ScMatrix* pLinkMat = pLink->GetResult();
2201cdf0e10cSrcweir         if (pLinkMat)
2202cdf0e10cSrcweir         {
2203cdf0e10cSrcweir             SCSIZE nC, nR;
2204cdf0e10cSrcweir             pLinkMat->GetDimensions(nC, nR);
2205cdf0e10cSrcweir             ScMatrixRef pNewMat = GetNewMat( nC, nR);
2206cdf0e10cSrcweir             if (pNewMat)
2207cdf0e10cSrcweir             {
2208cdf0e10cSrcweir                 pLinkMat->MatCopy(*pNewMat);        // kopieren
2209cdf0e10cSrcweir                 PushMatrix( pNewMat );
2210cdf0e10cSrcweir             }
2211cdf0e10cSrcweir             else
2212cdf0e10cSrcweir                 PushIllegalArgument();
2213cdf0e10cSrcweir         }
2214cdf0e10cSrcweir         else
2215cdf0e10cSrcweir             PushNA();
2216cdf0e10cSrcweir 
2217cdf0e10cSrcweir         pDok->DisableIdle( bOldDis );
2218cdf0e10cSrcweir     }
2219cdf0e10cSrcweir }
2220cdf0e10cSrcweir 
ScBase()2221cdf0e10cSrcweir void ScInterpreter::ScBase()
2222cdf0e10cSrcweir {   // Value, Base [, MinLen]
2223cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
2224cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 2, 3 ) )
2225cdf0e10cSrcweir     {
2226cdf0e10cSrcweir         static const sal_Unicode __FAR_DATA pDigits[] = {
2227cdf0e10cSrcweir             '0','1','2','3','4','5','6','7','8','9',
2228cdf0e10cSrcweir             'A','B','C','D','E','F','G','H','I','J','K','L','M',
2229cdf0e10cSrcweir             'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
2230cdf0e10cSrcweir             0
2231cdf0e10cSrcweir         };
2232cdf0e10cSrcweir         static const int nDigits = (sizeof(pDigits)/sizeof(sal_Unicode))-1;
2233cdf0e10cSrcweir         xub_StrLen nMinLen;
2234cdf0e10cSrcweir         if ( nParamCount == 3 )
2235cdf0e10cSrcweir         {
2236cdf0e10cSrcweir             double fLen = ::rtl::math::approxFloor( GetDouble() );
2237cdf0e10cSrcweir             if ( 1.0 <= fLen && fLen < STRING_MAXLEN )
2238cdf0e10cSrcweir                 nMinLen = (xub_StrLen) fLen;
2239cdf0e10cSrcweir             else if ( fLen == 0.0 )
2240cdf0e10cSrcweir                 nMinLen = 1;
2241cdf0e10cSrcweir             else
2242cdf0e10cSrcweir                 nMinLen = 0;    // Error
2243cdf0e10cSrcweir         }
2244cdf0e10cSrcweir         else
2245cdf0e10cSrcweir             nMinLen = 1;
2246cdf0e10cSrcweir         double fBase = ::rtl::math::approxFloor( GetDouble() );
2247cdf0e10cSrcweir         double fVal = ::rtl::math::approxFloor( GetDouble() );
2248cdf0e10cSrcweir         double fChars = ((fVal > 0.0 && fBase > 0.0) ?
2249cdf0e10cSrcweir             (ceil( log( fVal ) / log( fBase ) ) + 2.0) :
2250cdf0e10cSrcweir             2.0);
2251cdf0e10cSrcweir         if ( fChars >= STRING_MAXLEN )
2252cdf0e10cSrcweir             nMinLen = 0;    // Error
2253cdf0e10cSrcweir 
2254cdf0e10cSrcweir         if ( !nGlobalError && nMinLen && 2 <= fBase && fBase <= nDigits && 0 <= fVal )
2255cdf0e10cSrcweir         {
2256cdf0e10cSrcweir             const xub_StrLen nConstBuf = 128;
2257cdf0e10cSrcweir             sal_Unicode aBuf[nConstBuf];
2258cdf0e10cSrcweir             xub_StrLen nBuf = Max( (xub_StrLen) fChars, (xub_StrLen) (nMinLen+1) );
2259cdf0e10cSrcweir             sal_Unicode* pBuf = (nBuf <= nConstBuf ? aBuf : new sal_Unicode[nBuf]);
2260cdf0e10cSrcweir             for ( xub_StrLen j = 0; j < nBuf; ++j )
2261cdf0e10cSrcweir             {
2262cdf0e10cSrcweir                 pBuf[j] = '0';
2263cdf0e10cSrcweir             }
2264cdf0e10cSrcweir             sal_Unicode* p = pBuf + nBuf - 1;
2265cdf0e10cSrcweir             *p = 0;
2266cdf0e10cSrcweir             if ( fVal <= (sal_uLong)(~0) )
2267cdf0e10cSrcweir             {
2268cdf0e10cSrcweir                 sal_uLong nVal = (sal_uLong) fVal;
2269cdf0e10cSrcweir                 sal_uLong nBase = (sal_uLong) fBase;
2270cdf0e10cSrcweir                 while ( nVal && p > pBuf )
2271cdf0e10cSrcweir                 {
2272cdf0e10cSrcweir                     *--p = pDigits[ nVal % nBase ];
2273cdf0e10cSrcweir                     nVal /= nBase;
2274cdf0e10cSrcweir                 }
2275cdf0e10cSrcweir                 fVal = (double) nVal;
2276cdf0e10cSrcweir             }
2277cdf0e10cSrcweir             else
2278cdf0e10cSrcweir             {
2279cdf0e10cSrcweir                 sal_Bool bDirt = sal_False;
2280cdf0e10cSrcweir                 while ( fVal && p > pBuf )
2281cdf0e10cSrcweir                 {
2282cdf0e10cSrcweir //! mit fmod Rundungsfehler ab 2**48
2283cdf0e10cSrcweir //                  double fDig = ::rtl::math::approxFloor( fmod( fVal, fBase ) );
2284cdf0e10cSrcweir // so ist es etwas besser
2285cdf0e10cSrcweir                     double fInt = ::rtl::math::approxFloor( fVal / fBase );
2286cdf0e10cSrcweir                     double fMult = fInt * fBase;
2287cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
2288cdf0e10cSrcweir                     // #53943# =BASIS(1e308;36) => GPF mit
2289cdf0e10cSrcweir                     // nDig = (size_t) ::rtl::math::approxFloor( fVal - fMult );
2290cdf0e10cSrcweir                     // trotz vorheriger Pruefung ob fVal >= fMult
2291cdf0e10cSrcweir                     double fDebug1 = fVal - fMult;
2292cdf0e10cSrcweir                     // fVal    := 7,5975311883090e+290
2293cdf0e10cSrcweir                     // fMult   := 7,5975311883090e+290
2294cdf0e10cSrcweir                     // fDebug1 := 1,3848924157003e+275  <- RoundOff-Error
2295cdf0e10cSrcweir                     // fVal != fMult, aber: ::rtl::math::approxEqual( fVal, fMult ) == TRUE
2296cdf0e10cSrcweir                     double fDebug2 = ::rtl::math::approxSub( fVal, fMult );
2297cdf0e10cSrcweir                     // und ::rtl::math::approxSub( fVal, fMult ) == 0
2298cdf0e10cSrcweir                     double fDebug3 = ( fInt ? fVal / fInt : 0.0 );
2299cdf0e10cSrcweir                     // Nach dem strange fDebug1 und fVal < fMult  ist eigentlich
2300cdf0e10cSrcweir                     // fDebug2 == fBase, trotzdem wird das mit einem Vergleich
2301cdf0e10cSrcweir                     // nicht erkannt, dann schlaegt bDirt zu und alles wird wieder gut..
2302cdf0e10cSrcweir 
2303cdf0e10cSrcweir                     // prevent compiler warnings
2304cdf0e10cSrcweir                     (void)fDebug1; (void)fDebug2; (void)fDebug3;
2305cdf0e10cSrcweir #endif
2306cdf0e10cSrcweir                     size_t nDig;
2307cdf0e10cSrcweir                     if ( fVal < fMult )
2308cdf0e10cSrcweir                     {   // da ist was gekippt
2309cdf0e10cSrcweir                         bDirt = sal_True;
2310cdf0e10cSrcweir                         nDig = 0;
2311cdf0e10cSrcweir                     }
2312cdf0e10cSrcweir                     else
2313cdf0e10cSrcweir                     {
2314cdf0e10cSrcweir                         double fDig = ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal, fMult ) );
2315cdf0e10cSrcweir                         if ( bDirt )
2316cdf0e10cSrcweir                         {
2317cdf0e10cSrcweir                             bDirt = sal_False;
2318cdf0e10cSrcweir                             --fDig;
2319cdf0e10cSrcweir                         }
2320cdf0e10cSrcweir                         if ( fDig <= 0.0 )
2321cdf0e10cSrcweir                             nDig = 0;
2322cdf0e10cSrcweir                         else if ( fDig >= fBase )
2323cdf0e10cSrcweir                             nDig = ((size_t) fBase) - 1;
2324cdf0e10cSrcweir                         else
2325cdf0e10cSrcweir                             nDig = (size_t) fDig;
2326cdf0e10cSrcweir                     }
2327cdf0e10cSrcweir                     *--p = pDigits[ nDig ];
2328cdf0e10cSrcweir                     fVal = fInt;
2329cdf0e10cSrcweir                 }
2330cdf0e10cSrcweir             }
2331cdf0e10cSrcweir             if ( fVal )
2332cdf0e10cSrcweir                 PushError( errStringOverflow );
2333cdf0e10cSrcweir             else
2334cdf0e10cSrcweir             {
2335cdf0e10cSrcweir                 if ( nBuf - (p - pBuf) <= nMinLen )
2336cdf0e10cSrcweir                     p = pBuf + nBuf - 1 - nMinLen;
2337cdf0e10cSrcweir                 PushStringBuffer( p );
2338cdf0e10cSrcweir             }
2339cdf0e10cSrcweir             if ( pBuf != aBuf )
2340cdf0e10cSrcweir                 delete [] pBuf;
2341cdf0e10cSrcweir         }
2342cdf0e10cSrcweir         else
2343cdf0e10cSrcweir             PushIllegalArgument();
2344cdf0e10cSrcweir     }
2345cdf0e10cSrcweir }
2346cdf0e10cSrcweir 
2347cdf0e10cSrcweir 
ScDecimal()2348cdf0e10cSrcweir void ScInterpreter::ScDecimal()
2349cdf0e10cSrcweir {   // Text, Base
2350cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 2 ) )
2351cdf0e10cSrcweir     {
2352cdf0e10cSrcweir         double fBase = ::rtl::math::approxFloor( GetDouble() );
2353cdf0e10cSrcweir         String aStr( GetString() );
2354cdf0e10cSrcweir         if ( !nGlobalError && 2 <= fBase && fBase <= 36 )
2355cdf0e10cSrcweir         {
2356cdf0e10cSrcweir             double fVal = 0.0;
2357cdf0e10cSrcweir             int nBase = (int) fBase;
2358cdf0e10cSrcweir             register const sal_Unicode* p = aStr.GetBuffer();
2359cdf0e10cSrcweir             while ( *p == ' ' || *p == '\t' )
2360cdf0e10cSrcweir                 p++;        // strip leading white space
2361cdf0e10cSrcweir             if ( nBase == 16 )
2362cdf0e10cSrcweir             {   // evtl. hex-prefix strippen
2363cdf0e10cSrcweir                 if ( *p == 'x' || *p == 'X' )
2364cdf0e10cSrcweir                     p++;
2365cdf0e10cSrcweir                 else if ( *p == '0' && (*(p+1) == 'x' || *(p+1) == 'X') )
2366cdf0e10cSrcweir                     p += 2;
2367cdf0e10cSrcweir             }
2368cdf0e10cSrcweir             while ( *p )
2369cdf0e10cSrcweir             {
2370cdf0e10cSrcweir                 int n;
2371cdf0e10cSrcweir                 if ( '0' <= *p && *p <= '9' )
2372cdf0e10cSrcweir                     n = *p - '0';
2373cdf0e10cSrcweir                 else if ( 'A' <= *p && *p <= 'Z' )
2374cdf0e10cSrcweir                     n = 10 + (*p - 'A');
2375cdf0e10cSrcweir                 else if ( 'a' <= *p && *p <= 'z' )
2376cdf0e10cSrcweir                     n = 10 + (*p - 'a');
2377cdf0e10cSrcweir                 else
2378cdf0e10cSrcweir                     n = nBase;
2379cdf0e10cSrcweir                 if ( nBase <= n )
2380cdf0e10cSrcweir                 {
2381cdf0e10cSrcweir                     if ( *(p+1) == 0 &&
2382cdf0e10cSrcweir                             ( (nBase ==  2 && (*p == 'b' || *p == 'B'))
2383cdf0e10cSrcweir                             ||(nBase == 16 && (*p == 'h' || *p == 'H')) )
2384cdf0e10cSrcweir                         )
2385cdf0e10cSrcweir                         ;       // 101b und F00Dh sind ok
2386cdf0e10cSrcweir                     else
2387cdf0e10cSrcweir                     {
2388cdf0e10cSrcweir                         PushIllegalArgument();
2389cdf0e10cSrcweir                         return ;
2390cdf0e10cSrcweir                     }
2391cdf0e10cSrcweir                 }
2392cdf0e10cSrcweir                 else
2393cdf0e10cSrcweir                     fVal = fVal * fBase + n;
2394cdf0e10cSrcweir                 p++;
2395cdf0e10cSrcweir 
2396cdf0e10cSrcweir             }
2397cdf0e10cSrcweir             PushDouble( fVal );
2398cdf0e10cSrcweir         }
2399cdf0e10cSrcweir         else
2400cdf0e10cSrcweir             PushIllegalArgument();
2401cdf0e10cSrcweir     }
2402cdf0e10cSrcweir }
2403cdf0e10cSrcweir 
2404cdf0e10cSrcweir 
ScConvert()2405cdf0e10cSrcweir void ScInterpreter::ScConvert()
2406cdf0e10cSrcweir {   // Value, FromUnit, ToUnit
2407cdf0e10cSrcweir     if ( MustHaveParamCount( GetByte(), 3 ) )
2408cdf0e10cSrcweir     {
2409cdf0e10cSrcweir         String aToUnit( GetString() );
2410cdf0e10cSrcweir         String aFromUnit( GetString() );
2411cdf0e10cSrcweir         double fVal = GetDouble();
2412cdf0e10cSrcweir         if ( nGlobalError )
2413cdf0e10cSrcweir             PushError( nGlobalError);
2414cdf0e10cSrcweir         else
2415cdf0e10cSrcweir         {   // erst die angegebene Reihenfolge suchen, wenn nicht gefunden den Kehrwert
2416cdf0e10cSrcweir             double fConv;
2417cdf0e10cSrcweir             if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aFromUnit, aToUnit ) )
2418cdf0e10cSrcweir                 PushDouble( fVal * fConv );
2419cdf0e10cSrcweir             else if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aToUnit, aFromUnit ) )
2420cdf0e10cSrcweir                 PushDouble( fVal / fConv );
2421cdf0e10cSrcweir             else
2422cdf0e10cSrcweir                 PushNA();
2423cdf0e10cSrcweir         }
2424cdf0e10cSrcweir     }
2425cdf0e10cSrcweir }
2426cdf0e10cSrcweir 
2427cdf0e10cSrcweir 
ScRoman()2428cdf0e10cSrcweir void ScInterpreter::ScRoman()
2429cdf0e10cSrcweir {   // Value [Mode]
2430cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
2431cdf0e10cSrcweir     if( MustHaveParamCount( nParamCount, 1, 2 ) )
2432cdf0e10cSrcweir     {
2433cdf0e10cSrcweir         double fMode = (nParamCount == 2) ? ::rtl::math::approxFloor( GetDouble() ) : 0.0;
2434cdf0e10cSrcweir         double fVal = ::rtl::math::approxFloor( GetDouble() );
2435cdf0e10cSrcweir         if( nGlobalError )
2436cdf0e10cSrcweir             PushError( nGlobalError);
2437cdf0e10cSrcweir         else if( (fMode >= 0.0) && (fMode < 5.0) && (fVal >= 0.0) && (fVal < 4000.0) )
2438cdf0e10cSrcweir         {
2439cdf0e10cSrcweir             static const sal_Unicode pChars[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
2440cdf0e10cSrcweir             static const sal_uInt16 pValues[] = { 1000, 500, 100, 50, 10, 5, 1 };
2441cdf0e10cSrcweir             static const sal_uInt16 nMaxIndex = (sal_uInt16)(sizeof(pValues) / sizeof(pValues[0]) - 1);
2442cdf0e10cSrcweir 
2443cdf0e10cSrcweir             String aRoman;
2444cdf0e10cSrcweir             sal_uInt16 nVal = (sal_uInt16) fVal;
2445cdf0e10cSrcweir             sal_uInt16 nMode = (sal_uInt16) fMode;
2446cdf0e10cSrcweir 
2447cdf0e10cSrcweir             for( sal_uInt16 i = 0; i <= nMaxIndex / 2; i++ )
2448cdf0e10cSrcweir             {
2449cdf0e10cSrcweir                 sal_uInt16 nIndex = 2 * i;
2450cdf0e10cSrcweir                 sal_uInt16 nDigit = nVal / pValues[ nIndex ];
2451cdf0e10cSrcweir 
2452cdf0e10cSrcweir                 if( (nDigit % 5) == 4 )
2453cdf0e10cSrcweir                 {
2454cdf0e10cSrcweir                     sal_uInt16 nIndex2 = (nDigit == 4) ? nIndex - 1 : nIndex - 2;
2455cdf0e10cSrcweir                     sal_uInt16 nSteps = 0;
2456cdf0e10cSrcweir                     while( (nSteps < nMode) && (nIndex < nMaxIndex) )
2457cdf0e10cSrcweir                     {
2458cdf0e10cSrcweir                         nSteps++;
2459cdf0e10cSrcweir                         if( pValues[ nIndex2 ] - pValues[ nIndex + 1 ] <= nVal )
2460cdf0e10cSrcweir                             nIndex++;
2461cdf0e10cSrcweir                         else
2462cdf0e10cSrcweir                             nSteps = nMode;
2463cdf0e10cSrcweir                     }
2464cdf0e10cSrcweir                     aRoman += pChars[ nIndex ];
2465cdf0e10cSrcweir                     aRoman += pChars[ nIndex2 ];
2466cdf0e10cSrcweir                     nVal = sal::static_int_cast<sal_uInt16>( nVal + pValues[ nIndex ] );
2467cdf0e10cSrcweir                     nVal = sal::static_int_cast<sal_uInt16>( nVal - pValues[ nIndex2 ] );
2468cdf0e10cSrcweir                 }
2469cdf0e10cSrcweir                 else
2470cdf0e10cSrcweir                 {
2471cdf0e10cSrcweir                     if( nDigit > 4 )
2472cdf0e10cSrcweir                         aRoman += pChars[ nIndex - 1 ];
2473cdf0e10cSrcweir                     aRoman.Expand( aRoman.Len() + (nDigit % 5), pChars[ nIndex ] );
2474cdf0e10cSrcweir                     nVal %= pValues[ nIndex ];
2475cdf0e10cSrcweir                 }
2476cdf0e10cSrcweir             }
2477cdf0e10cSrcweir 
2478cdf0e10cSrcweir             PushString( aRoman );
2479cdf0e10cSrcweir         }
2480cdf0e10cSrcweir         else
2481cdf0e10cSrcweir             PushIllegalArgument();
2482cdf0e10cSrcweir     }
2483cdf0e10cSrcweir }
2484cdf0e10cSrcweir 
2485cdf0e10cSrcweir 
lcl_GetArabicValue(sal_Unicode cChar,sal_uInt16 & rnValue,sal_Bool & rbIsDec)2486cdf0e10cSrcweir sal_Bool lcl_GetArabicValue( sal_Unicode cChar, sal_uInt16& rnValue, sal_Bool& rbIsDec )
2487cdf0e10cSrcweir {
2488cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBase" );
2489cdf0e10cSrcweir     switch( cChar )
2490cdf0e10cSrcweir     {
2491cdf0e10cSrcweir         case 'M':   rnValue = 1000; rbIsDec = sal_True;     break;
2492cdf0e10cSrcweir         case 'D':   rnValue = 500;  rbIsDec = sal_False;    break;
2493cdf0e10cSrcweir         case 'C':   rnValue = 100;  rbIsDec = sal_True;     break;
2494cdf0e10cSrcweir         case 'L':   rnValue = 50;   rbIsDec = sal_False;    break;
2495cdf0e10cSrcweir         case 'X':   rnValue = 10;   rbIsDec = sal_True;     break;
2496cdf0e10cSrcweir         case 'V':   rnValue = 5;    rbIsDec = sal_False;    break;
2497cdf0e10cSrcweir         case 'I':   rnValue = 1;    rbIsDec = sal_True;     break;
2498cdf0e10cSrcweir         default:    return sal_False;
2499cdf0e10cSrcweir     }
2500cdf0e10cSrcweir     return sal_True;
2501cdf0e10cSrcweir }
2502cdf0e10cSrcweir 
2503cdf0e10cSrcweir 
ScArabic()2504cdf0e10cSrcweir void ScInterpreter::ScArabic()
2505cdf0e10cSrcweir {
2506cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArabic" );
2507cdf0e10cSrcweir     String aRoman( GetString() );
2508cdf0e10cSrcweir     if( nGlobalError )
2509cdf0e10cSrcweir         PushError( nGlobalError);
2510cdf0e10cSrcweir     else
2511cdf0e10cSrcweir     {
2512cdf0e10cSrcweir         aRoman.ToUpperAscii();
2513cdf0e10cSrcweir 
2514cdf0e10cSrcweir         sal_uInt16 nValue = 0;
2515cdf0e10cSrcweir         sal_uInt16 nValidRest = 3999;
2516cdf0e10cSrcweir         sal_uInt16 nCharIndex = 0;
2517cdf0e10cSrcweir         sal_uInt16 nCharCount = aRoman.Len();
2518cdf0e10cSrcweir         sal_Bool bValid = sal_True;
2519cdf0e10cSrcweir 
2520cdf0e10cSrcweir         while( bValid && (nCharIndex < nCharCount) )
2521cdf0e10cSrcweir         {
2522cdf0e10cSrcweir             sal_uInt16 nDigit1 = 0;
2523cdf0e10cSrcweir             sal_uInt16 nDigit2 = 0;
2524cdf0e10cSrcweir             sal_Bool bIsDec1 = sal_False;
2525cdf0e10cSrcweir             sal_Bool bIsDec2 = sal_False;
2526cdf0e10cSrcweir             bValid = lcl_GetArabicValue( aRoman.GetChar( nCharIndex ), nDigit1, bIsDec1 );
2527cdf0e10cSrcweir             if( bValid && (nCharIndex + 1 < nCharCount) )
2528cdf0e10cSrcweir                 bValid = lcl_GetArabicValue( aRoman.GetChar( nCharIndex + 1 ), nDigit2, bIsDec2 );
2529cdf0e10cSrcweir             if( bValid )
2530cdf0e10cSrcweir             {
2531cdf0e10cSrcweir                 if( nDigit1 >= nDigit2 )
2532cdf0e10cSrcweir                 {
2533cdf0e10cSrcweir                     nValue = sal::static_int_cast<sal_uInt16>( nValue + nDigit1 );
2534cdf0e10cSrcweir                     nValidRest %= (nDigit1 * (bIsDec1 ? 5 : 2));
2535cdf0e10cSrcweir                     bValid = (nValidRest >= nDigit1);
2536cdf0e10cSrcweir                     if( bValid )
2537cdf0e10cSrcweir                         nValidRest = sal::static_int_cast<sal_uInt16>( nValidRest - nDigit1 );
2538cdf0e10cSrcweir                     nCharIndex++;
2539cdf0e10cSrcweir                 }
2540cdf0e10cSrcweir                 else if( nDigit1 * 2 != nDigit2 )
2541cdf0e10cSrcweir                 {
2542cdf0e10cSrcweir                     sal_uInt16 nDiff = nDigit2 - nDigit1;
2543cdf0e10cSrcweir                     nValue = sal::static_int_cast<sal_uInt16>( nValue + nDiff );
2544cdf0e10cSrcweir                     bValid = (nValidRest >= nDiff);
2545cdf0e10cSrcweir                     if( bValid )
2546cdf0e10cSrcweir                         nValidRest = nDigit1 - 1;
2547cdf0e10cSrcweir                     nCharIndex += 2;
2548cdf0e10cSrcweir                 }
2549cdf0e10cSrcweir                 else
2550cdf0e10cSrcweir                     bValid = sal_False;
2551cdf0e10cSrcweir             }
2552cdf0e10cSrcweir         }
2553cdf0e10cSrcweir         if( bValid )
2554cdf0e10cSrcweir             PushInt( nValue );
2555cdf0e10cSrcweir         else
2556cdf0e10cSrcweir             PushIllegalArgument();
2557cdf0e10cSrcweir     }
2558cdf0e10cSrcweir }
2559cdf0e10cSrcweir 
2560cdf0e10cSrcweir 
ScHyperLink()2561cdf0e10cSrcweir void ScInterpreter::ScHyperLink()
2562cdf0e10cSrcweir {
2563cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHyperLink" );
2564cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
2565cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
2566cdf0e10cSrcweir     {
2567cdf0e10cSrcweir         double fVal = 0.0;
2568cdf0e10cSrcweir         String aStr;
2569cdf0e10cSrcweir         ScMatValType nResultType = SC_MATVAL_STRING;
2570cdf0e10cSrcweir 
2571cdf0e10cSrcweir         if ( nParamCount == 2 )
2572cdf0e10cSrcweir         {
2573cdf0e10cSrcweir             switch ( GetStackType() )
2574cdf0e10cSrcweir             {
2575cdf0e10cSrcweir                 case svDouble:
2576cdf0e10cSrcweir                     fVal = GetDouble();
2577cdf0e10cSrcweir                     nResultType = SC_MATVAL_VALUE;
2578cdf0e10cSrcweir                 break;
2579cdf0e10cSrcweir                 case svString:
2580cdf0e10cSrcweir                     aStr = GetString();
2581cdf0e10cSrcweir                 break;
2582cdf0e10cSrcweir                 case svSingleRef:
2583cdf0e10cSrcweir                 case svDoubleRef:
2584cdf0e10cSrcweir                 {
2585cdf0e10cSrcweir                     ScAddress aAdr;
2586cdf0e10cSrcweir                     if ( !PopDoubleRefOrSingleRef( aAdr ) )
2587cdf0e10cSrcweir                         break;
2588cdf0e10cSrcweir                     ScBaseCell* pCell = GetCell( aAdr );
2589cdf0e10cSrcweir                     if (HasCellEmptyData( pCell))
2590cdf0e10cSrcweir                         nResultType = SC_MATVAL_EMPTY;
2591cdf0e10cSrcweir                     else
2592cdf0e10cSrcweir                     {
2593cdf0e10cSrcweir                         sal_uInt16 nErr = GetCellErrCode( pCell );
2594cdf0e10cSrcweir                         if (nErr)
2595cdf0e10cSrcweir                             SetError( nErr);
2596cdf0e10cSrcweir                         else if (HasCellValueData( pCell))
2597cdf0e10cSrcweir                         {
2598cdf0e10cSrcweir                             fVal = GetCellValue( aAdr, pCell );
2599cdf0e10cSrcweir                             nResultType = SC_MATVAL_VALUE;
2600cdf0e10cSrcweir                         }
2601cdf0e10cSrcweir                         else
2602cdf0e10cSrcweir                             GetCellString( aStr, pCell );
2603cdf0e10cSrcweir                     }
2604cdf0e10cSrcweir                 }
2605cdf0e10cSrcweir                 break;
2606cdf0e10cSrcweir                 case svMatrix:
2607cdf0e10cSrcweir                     nResultType = GetDoubleOrStringFromMatrix( fVal, aStr);
2608cdf0e10cSrcweir                 break;
2609cdf0e10cSrcweir                 case svMissing:
2610cdf0e10cSrcweir                 case svEmptyCell:
2611cdf0e10cSrcweir                     Pop();
2612cdf0e10cSrcweir                     // mimic xcl
2613cdf0e10cSrcweir                     fVal = 0.0;
2614cdf0e10cSrcweir                     nResultType = SC_MATVAL_VALUE;
2615cdf0e10cSrcweir                 break;
2616cdf0e10cSrcweir                 default:
2617cdf0e10cSrcweir                     PopError();
2618cdf0e10cSrcweir                     SetError( errIllegalArgument);
2619cdf0e10cSrcweir             }
2620cdf0e10cSrcweir         }
2621cdf0e10cSrcweir         String aUrl = GetString();
2622cdf0e10cSrcweir         ScMatrixRef pResMat = GetNewMat( 1, 2);
2623cdf0e10cSrcweir         if (nGlobalError)
2624cdf0e10cSrcweir         {
2625cdf0e10cSrcweir             fVal = CreateDoubleError( nGlobalError);
2626cdf0e10cSrcweir             nResultType = SC_MATVAL_VALUE;
2627cdf0e10cSrcweir         }
2628cdf0e10cSrcweir         if (nParamCount == 2 || nGlobalError)
2629cdf0e10cSrcweir         {
2630cdf0e10cSrcweir             if (ScMatrix::IsValueType( nResultType))
2631cdf0e10cSrcweir                 pResMat->PutDouble( fVal, 0);
2632cdf0e10cSrcweir             else if (ScMatrix::IsRealStringType( nResultType))
2633cdf0e10cSrcweir                 pResMat->PutString( aStr, 0);
2634cdf0e10cSrcweir             else    // EmptyType, EmptyPathType, mimic xcl
2635cdf0e10cSrcweir                 pResMat->PutDouble( 0.0, 0 );
2636cdf0e10cSrcweir         }
2637cdf0e10cSrcweir         else
2638cdf0e10cSrcweir             pResMat->PutString( aUrl, 0 );
2639cdf0e10cSrcweir         pResMat->PutString( aUrl, 1 );
2640cdf0e10cSrcweir         bMatrixFormula = true;
2641cdf0e10cSrcweir         PushMatrix(pResMat);
2642cdf0e10cSrcweir     }
2643cdf0e10cSrcweir }
2644cdf0e10cSrcweir 
2645cdf0e10cSrcweir 
lclConvertMoney(const String & aSearchUnit,double & rfRate,int & rnDec)2646cdf0e10cSrcweir sal_Bool lclConvertMoney( const String& aSearchUnit, double& rfRate, int& rnDec )
2647cdf0e10cSrcweir {
2648cdf0e10cSrcweir     struct ConvertInfo
2649cdf0e10cSrcweir     {
2650cdf0e10cSrcweir         const sal_Char* pCurrText;
2651cdf0e10cSrcweir         double          fRate;
2652cdf0e10cSrcweir         int             nDec;
2653cdf0e10cSrcweir     };
2654cdf0e10cSrcweir     ConvertInfo aConvertTable[] = {
2655cdf0e10cSrcweir         { "EUR", 1.0,      2 },
2656cdf0e10cSrcweir         { "ATS", 13.7603,  2 },
2657cdf0e10cSrcweir         { "BEF", 40.3399,  0 },
2658cdf0e10cSrcweir         { "DEM", 1.95583,  2 },
2659cdf0e10cSrcweir         { "ESP", 166.386,  0 },
2660cdf0e10cSrcweir         { "FIM", 5.94573,  2 },
2661cdf0e10cSrcweir         { "FRF", 6.55957,  2 },
2662cdf0e10cSrcweir         { "IEP", 0.787564, 2 },
2663cdf0e10cSrcweir         { "ITL", 1936.27,  0 },
2664cdf0e10cSrcweir         { "LUF", 40.3399,  0 },
2665cdf0e10cSrcweir         { "NLG", 2.20371,  2 },
2666cdf0e10cSrcweir         { "PTE", 200.482,  2 },
2667cdf0e10cSrcweir         { "GRD", 340.750,  2 },
2668cdf0e10cSrcweir         { "SIT", 239.640,  2 },
2669cdf0e10cSrcweir         { "MTL", 0.429300, 2 },
2670cdf0e10cSrcweir         { "CYP", 0.585274, 2 },
26715ab069a0SMatthias Seidel         { "SKK", 30.1260,  2 },
26725ab069a0SMatthias Seidel         { "EEK", 15.6466,  2 },
26735ab069a0SMatthias Seidel         { "LVL", 0.702804, 2 },
2674*535b2a06Smseidel         { "LTL", 3.45280,  2 },
2675*535b2a06Smseidel         { "HRK", 7.53450,  2 }
2676cdf0e10cSrcweir     };
2677cdf0e10cSrcweir 
2678cdf0e10cSrcweir     const size_t nConversionCount = sizeof( aConvertTable ) / sizeof( aConvertTable[0] );
2679cdf0e10cSrcweir     for ( size_t i = 0; i < nConversionCount; i++ )
2680cdf0e10cSrcweir         if ( aSearchUnit.EqualsIgnoreCaseAscii( aConvertTable[i].pCurrText ) )
2681cdf0e10cSrcweir         {
2682cdf0e10cSrcweir             rfRate = aConvertTable[i].fRate;
2683cdf0e10cSrcweir             rnDec  = aConvertTable[i].nDec;
2684cdf0e10cSrcweir             return sal_True;
2685cdf0e10cSrcweir         }
2686cdf0e10cSrcweir     return sal_False;
2687cdf0e10cSrcweir }
2688cdf0e10cSrcweir 
ScEuroConvert()2689cdf0e10cSrcweir void ScInterpreter::ScEuroConvert()
2690cdf0e10cSrcweir {   //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]]
2691cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
2692cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 3, 5 ) )
2693cdf0e10cSrcweir     {
2694cdf0e10cSrcweir         double nPrecision = 0.0;
2695cdf0e10cSrcweir         if ( nParamCount == 5 )
2696cdf0e10cSrcweir         {
2697cdf0e10cSrcweir             nPrecision = ::rtl::math::approxFloor(GetDouble());
2698cdf0e10cSrcweir             if ( nPrecision < 3 )
2699cdf0e10cSrcweir             {
2700cdf0e10cSrcweir                 PushIllegalArgument();
2701cdf0e10cSrcweir                 return;
2702cdf0e10cSrcweir             }
2703cdf0e10cSrcweir         }
2704cdf0e10cSrcweir         sal_Bool bFullPrecision = sal_False;
2705cdf0e10cSrcweir         if ( nParamCount >= 4 )
2706cdf0e10cSrcweir             bFullPrecision = GetBool();
2707cdf0e10cSrcweir         String aToUnit( GetString() );
2708cdf0e10cSrcweir         String aFromUnit( GetString() );
2709cdf0e10cSrcweir         double fVal = GetDouble();
2710cdf0e10cSrcweir         if ( nGlobalError )
2711cdf0e10cSrcweir             PushError( nGlobalError);
2712cdf0e10cSrcweir         else
2713cdf0e10cSrcweir         {
2714cdf0e10cSrcweir             double fRes;
2715cdf0e10cSrcweir             double fFromRate;
2716cdf0e10cSrcweir             double fToRate;
2717cdf0e10cSrcweir             int    nFromDec;
2718cdf0e10cSrcweir             int    nToDec;
2719cdf0e10cSrcweir             String aEur( RTL_CONSTASCII_USTRINGPARAM("EUR"));
2720cdf0e10cSrcweir             if ( lclConvertMoney( aFromUnit, fFromRate, nFromDec )
2721cdf0e10cSrcweir                 && lclConvertMoney( aToUnit, fToRate, nToDec ) )
2722cdf0e10cSrcweir             {
2723cdf0e10cSrcweir                 if ( aFromUnit.EqualsIgnoreCaseAscii( aToUnit ) )
2724cdf0e10cSrcweir                     fRes = fVal;
2725cdf0e10cSrcweir                 else
2726cdf0e10cSrcweir                 {
2727cdf0e10cSrcweir                     if ( aFromUnit.EqualsIgnoreCaseAscii( aEur ) )
2728cdf0e10cSrcweir                        fRes = fVal * fToRate;
2729cdf0e10cSrcweir                     else
2730cdf0e10cSrcweir                     {
2731cdf0e10cSrcweir                         double fIntermediate = fVal / fFromRate;
2732cdf0e10cSrcweir                         if ( nPrecision )
2733cdf0e10cSrcweir                             fIntermediate = ::rtl::math::round( fIntermediate,
2734cdf0e10cSrcweir                                                             (int) nPrecision );
2735cdf0e10cSrcweir                         fRes = fIntermediate * fToRate;
2736cdf0e10cSrcweir                     }
2737cdf0e10cSrcweir                     if ( !bFullPrecision )
2738cdf0e10cSrcweir                         fRes = ::rtl::math::round( fRes, nToDec );
2739cdf0e10cSrcweir                 }
2740cdf0e10cSrcweir                 PushDouble( fRes );
2741cdf0e10cSrcweir             }
2742cdf0e10cSrcweir             else
2743cdf0e10cSrcweir                 PushIllegalArgument();
2744cdf0e10cSrcweir         }
2745cdf0e10cSrcweir     }
2746cdf0e10cSrcweir }
2747cdf0e10cSrcweir 
2748cdf0e10cSrcweir 
2749cdf0e10cSrcweir // BAHTTEXT ===================================================================
2750cdf0e10cSrcweir 
2751cdf0e10cSrcweir #define UTF8_TH_0       "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214"
2752cdf0e10cSrcweir #define UTF8_TH_1       "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207"
2753cdf0e10cSrcweir #define UTF8_TH_2       "\340\270\252\340\270\255\340\270\207"
2754cdf0e10cSrcweir #define UTF8_TH_3       "\340\270\252\340\270\262\340\270\241"
2755cdf0e10cSrcweir #define UTF8_TH_4       "\340\270\252\340\270\265\340\271\210"
2756cdf0e10cSrcweir #define UTF8_TH_5       "\340\270\253\340\271\211\340\270\262"
2757cdf0e10cSrcweir #define UTF8_TH_6       "\340\270\253\340\270\201"
2758cdf0e10cSrcweir #define UTF8_TH_7       "\340\271\200\340\270\210\340\271\207\340\270\224"
2759cdf0e10cSrcweir #define UTF8_TH_8       "\340\271\201\340\270\233\340\270\224"
2760cdf0e10cSrcweir #define UTF8_TH_9       "\340\271\200\340\270\201\340\271\211\340\270\262"
2761cdf0e10cSrcweir #define UTF8_TH_10      "\340\270\252\340\270\264\340\270\232"
2762cdf0e10cSrcweir #define UTF8_TH_11      "\340\271\200\340\270\255\340\271\207\340\270\224"
2763cdf0e10cSrcweir #define UTF8_TH_20      "\340\270\242\340\270\265\340\271\210"
2764cdf0e10cSrcweir #define UTF8_TH_1E2     "\340\270\243\340\271\211\340\270\255\340\270\242"
2765cdf0e10cSrcweir #define UTF8_TH_1E3     "\340\270\236\340\270\261\340\270\231"
2766cdf0e10cSrcweir #define UTF8_TH_1E4     "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231"
2767cdf0e10cSrcweir #define UTF8_TH_1E5     "\340\271\201\340\270\252\340\270\231"
2768cdf0e10cSrcweir #define UTF8_TH_1E6     "\340\270\245\340\271\211\340\270\262\340\270\231"
2769cdf0e10cSrcweir #define UTF8_TH_DOT0    "\340\270\226\340\271\211\340\270\247\340\270\231"
2770cdf0e10cSrcweir #define UTF8_TH_BAHT    "\340\270\232\340\270\262\340\270\227"
2771cdf0e10cSrcweir #define UTF8_TH_SATANG  "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214"
2772cdf0e10cSrcweir #define UTF8_TH_MINUS   "\340\270\245\340\270\232"
2773cdf0e10cSrcweir 
2774cdf0e10cSrcweir #define UTF8_STRINGPARAM( ascii )   ascii, static_cast< xub_StrLen >( sizeof( ascii ) - 1 )
2775cdf0e10cSrcweir #define UTF8_CREATE( ascii )        ByteString( UTF8_STRINGPARAM( ascii ) )
2776cdf0e10cSrcweir #define UTF8_APPEND( ascii )        Append( UTF8_STRINGPARAM( ascii ) )
2777cdf0e10cSrcweir #define UTF8_PREPEND( ascii )       Insert( UTF8_CREATE( ascii ), 0 )
2778cdf0e10cSrcweir 
2779cdf0e10cSrcweir // local functions ------------------------------------------------------------
2780cdf0e10cSrcweir 
2781cdf0e10cSrcweir namespace {
2782cdf0e10cSrcweir 
lclSplitBlock(double & rfInt,sal_Int32 & rnBlock,double fValue,double fSize)2783cdf0e10cSrcweir inline void lclSplitBlock( double& rfInt, sal_Int32& rnBlock, double fValue, double fSize )
2784cdf0e10cSrcweir {
2785cdf0e10cSrcweir     rnBlock = static_cast< sal_Int32 >( modf( (fValue + 0.1) / fSize, &rfInt ) * fSize + 0.1 );
2786cdf0e10cSrcweir }
2787cdf0e10cSrcweir 
2788cdf0e10cSrcweir /** Appends a digit (0 to 9) to the passed string. */
lclAppendDigit(ByteString & rText,sal_Int32 nDigit)2789cdf0e10cSrcweir void lclAppendDigit( ByteString& rText, sal_Int32 nDigit )
2790cdf0e10cSrcweir {
2791cdf0e10cSrcweir     switch( nDigit )
2792cdf0e10cSrcweir     {
2793cdf0e10cSrcweir         case 0: rText.UTF8_APPEND( UTF8_TH_0 ); break;
2794cdf0e10cSrcweir         case 1: rText.UTF8_APPEND( UTF8_TH_1 ); break;
2795cdf0e10cSrcweir         case 2: rText.UTF8_APPEND( UTF8_TH_2 ); break;
2796cdf0e10cSrcweir         case 3: rText.UTF8_APPEND( UTF8_TH_3 ); break;
2797cdf0e10cSrcweir         case 4: rText.UTF8_APPEND( UTF8_TH_4 ); break;
2798cdf0e10cSrcweir         case 5: rText.UTF8_APPEND( UTF8_TH_5 ); break;
2799cdf0e10cSrcweir         case 6: rText.UTF8_APPEND( UTF8_TH_6 ); break;
2800cdf0e10cSrcweir         case 7: rText.UTF8_APPEND( UTF8_TH_7 ); break;
2801cdf0e10cSrcweir         case 8: rText.UTF8_APPEND( UTF8_TH_8 ); break;
2802cdf0e10cSrcweir         case 9: rText.UTF8_APPEND( UTF8_TH_9 ); break;
2803cdf0e10cSrcweir         default:    DBG_ERRORFILE( "lclAppendDigit - illegal digit" );
2804cdf0e10cSrcweir     }
2805cdf0e10cSrcweir }
2806cdf0e10cSrcweir 
2807cdf0e10cSrcweir /** Appends a value raised to a power of 10: nDigit*10^nPow10.
2808cdf0e10cSrcweir     @param nDigit  A digit in the range from 1 to 9.
2809cdf0e10cSrcweir     @param nPow10  A value in the range from 2 to 5.
2810cdf0e10cSrcweir  */
lclAppendPow10(ByteString & rText,sal_Int32 nDigit,sal_Int32 nPow10)2811cdf0e10cSrcweir void lclAppendPow10( ByteString& rText, sal_Int32 nDigit, sal_Int32 nPow10 )
2812cdf0e10cSrcweir {
2813cdf0e10cSrcweir     DBG_ASSERT( (1 <= nDigit) && (nDigit <= 9), "lclAppendPow10 - illegal digit" );
2814cdf0e10cSrcweir     lclAppendDigit( rText, nDigit );
2815cdf0e10cSrcweir     switch( nPow10 )
2816cdf0e10cSrcweir     {
2817cdf0e10cSrcweir         case 2: rText.UTF8_APPEND( UTF8_TH_1E2 );   break;
2818cdf0e10cSrcweir         case 3: rText.UTF8_APPEND( UTF8_TH_1E3 );   break;
2819cdf0e10cSrcweir         case 4: rText.UTF8_APPEND( UTF8_TH_1E4 );   break;
2820cdf0e10cSrcweir         case 5: rText.UTF8_APPEND( UTF8_TH_1E5 );   break;
2821cdf0e10cSrcweir         default:    DBG_ERRORFILE( "lclAppendPow10 - illegal power" );
2822cdf0e10cSrcweir     }
2823cdf0e10cSrcweir }
2824cdf0e10cSrcweir 
2825cdf0e10cSrcweir /** Appends a block of 6 digits (value from 1 to 999,999) to the passed string. */
lclAppendBlock(ByteString & rText,sal_Int32 nValue)2826cdf0e10cSrcweir void lclAppendBlock( ByteString& rText, sal_Int32 nValue )
2827cdf0e10cSrcweir {
2828cdf0e10cSrcweir     DBG_ASSERT( (1 <= nValue) && (nValue <= 999999), "lclAppendBlock - illegal value" );
2829cdf0e10cSrcweir     if( nValue >= 100000 )
2830cdf0e10cSrcweir     {
2831cdf0e10cSrcweir         lclAppendPow10( rText, nValue / 100000, 5 );
2832cdf0e10cSrcweir         nValue %= 100000;
2833cdf0e10cSrcweir     }
2834cdf0e10cSrcweir     if( nValue >= 10000 )
2835cdf0e10cSrcweir     {
2836cdf0e10cSrcweir         lclAppendPow10( rText, nValue / 10000, 4 );
2837cdf0e10cSrcweir         nValue %= 10000;
2838cdf0e10cSrcweir     }
2839cdf0e10cSrcweir     if( nValue >= 1000 )
2840cdf0e10cSrcweir     {
2841cdf0e10cSrcweir         lclAppendPow10( rText, nValue / 1000, 3 );
2842cdf0e10cSrcweir         nValue %= 1000;
2843cdf0e10cSrcweir     }
2844cdf0e10cSrcweir     if( nValue >= 100 )
2845cdf0e10cSrcweir     {
2846cdf0e10cSrcweir         lclAppendPow10( rText, nValue / 100, 2 );
2847cdf0e10cSrcweir         nValue %= 100;
2848cdf0e10cSrcweir     }
2849cdf0e10cSrcweir     if( nValue > 0 )
2850cdf0e10cSrcweir     {
2851cdf0e10cSrcweir         sal_Int32 nTen = nValue / 10;
2852cdf0e10cSrcweir         sal_Int32 nOne = nValue % 10;
2853cdf0e10cSrcweir         if( nTen >= 1 )
2854cdf0e10cSrcweir         {
2855cdf0e10cSrcweir             if( nTen >= 3 )
2856cdf0e10cSrcweir                 lclAppendDigit( rText, nTen );
2857cdf0e10cSrcweir             else if( nTen == 2 )
2858cdf0e10cSrcweir                 rText.UTF8_APPEND( UTF8_TH_20 );
2859cdf0e10cSrcweir             rText.UTF8_APPEND( UTF8_TH_10 );
2860cdf0e10cSrcweir         }
2861cdf0e10cSrcweir         if( (nTen > 0) && (nOne == 1) )
2862cdf0e10cSrcweir             rText.UTF8_APPEND( UTF8_TH_11 );
2863cdf0e10cSrcweir         else if( nOne > 0 )
2864cdf0e10cSrcweir             lclAppendDigit( rText, nOne );
2865cdf0e10cSrcweir     }
2866cdf0e10cSrcweir }
2867cdf0e10cSrcweir 
2868cdf0e10cSrcweir } // namespace
2869cdf0e10cSrcweir 
2870cdf0e10cSrcweir // ----------------------------------------------------------------------------
2871cdf0e10cSrcweir 
ScBahtText()2872cdf0e10cSrcweir void ScInterpreter::ScBahtText()
2873cdf0e10cSrcweir {
2874cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBahtText" );
2875cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
2876cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 1 ) )
2877cdf0e10cSrcweir     {
2878cdf0e10cSrcweir         double fValue = GetDouble();
2879cdf0e10cSrcweir         if( nGlobalError )
2880cdf0e10cSrcweir         {
2881cdf0e10cSrcweir             PushError( nGlobalError);
2882cdf0e10cSrcweir             return;
2883cdf0e10cSrcweir         }
2884cdf0e10cSrcweir 
2885cdf0e10cSrcweir         // sign
2886cdf0e10cSrcweir         bool bMinus = fValue < 0.0;
2887cdf0e10cSrcweir         fValue = fabs( fValue );
2888cdf0e10cSrcweir 
2889cdf0e10cSrcweir         // round to 2 digits after decimal point, fValue contains Satang as integer
2890cdf0e10cSrcweir         fValue = ::rtl::math::approxFloor( fValue * 100.0 + 0.5 );
2891cdf0e10cSrcweir 
2892cdf0e10cSrcweir         // split Baht and Satang
2893cdf0e10cSrcweir         double fBaht = 0.0;
2894cdf0e10cSrcweir         sal_Int32 nSatang = 0;
2895cdf0e10cSrcweir         lclSplitBlock( fBaht, nSatang, fValue, 100.0 );
2896cdf0e10cSrcweir 
2897cdf0e10cSrcweir         ByteString aText;
2898cdf0e10cSrcweir 
2899cdf0e10cSrcweir         // generate text for Baht value
2900cdf0e10cSrcweir         if( fBaht == 0.0 )
2901cdf0e10cSrcweir         {
2902cdf0e10cSrcweir             if( nSatang == 0 )
2903cdf0e10cSrcweir                 aText.UTF8_APPEND( UTF8_TH_0 );
2904cdf0e10cSrcweir         }
2905cdf0e10cSrcweir         else while( fBaht > 0.0 )
2906cdf0e10cSrcweir         {
2907cdf0e10cSrcweir             ByteString aBlock;
2908cdf0e10cSrcweir             sal_Int32 nBlock = 0;
2909cdf0e10cSrcweir             lclSplitBlock( fBaht, nBlock, fBaht, 1.0e6 );
2910cdf0e10cSrcweir             if( nBlock > 0 )
2911cdf0e10cSrcweir                 lclAppendBlock( aBlock, nBlock );
2912cdf0e10cSrcweir             // add leading "million", if there will come more blocks
2913cdf0e10cSrcweir             if( fBaht > 0.0 )
2914cdf0e10cSrcweir                 aBlock.UTF8_PREPEND( UTF8_TH_1E6 );
2915cdf0e10cSrcweir             aText.Insert( aBlock, 0 );
2916cdf0e10cSrcweir         }
2917cdf0e10cSrcweir         if( aText.Len() > 0 )
2918cdf0e10cSrcweir             aText.UTF8_APPEND( UTF8_TH_BAHT );
2919cdf0e10cSrcweir 
2920cdf0e10cSrcweir         // generate text for Satang value
2921cdf0e10cSrcweir         if( nSatang == 0 )
2922cdf0e10cSrcweir         {
2923cdf0e10cSrcweir             aText.UTF8_APPEND( UTF8_TH_DOT0 );
2924cdf0e10cSrcweir         }
2925cdf0e10cSrcweir         else
2926cdf0e10cSrcweir         {
2927cdf0e10cSrcweir             lclAppendBlock( aText, nSatang );
2928cdf0e10cSrcweir             aText.UTF8_APPEND( UTF8_TH_SATANG );
2929cdf0e10cSrcweir         }
2930cdf0e10cSrcweir 
2931cdf0e10cSrcweir         // add the minus sign
2932cdf0e10cSrcweir         if( bMinus )
2933cdf0e10cSrcweir             aText.UTF8_PREPEND( UTF8_TH_MINUS );
2934cdf0e10cSrcweir 
2935cdf0e10cSrcweir         PushString( String( aText, RTL_TEXTENCODING_UTF8 ) );
2936cdf0e10cSrcweir     }
2937cdf0e10cSrcweir }
2938cdf0e10cSrcweir 
2939cdf0e10cSrcweir // ============================================================================
2940cdf0e10cSrcweir 
ScGetPivotData()2941cdf0e10cSrcweir void ScInterpreter::ScGetPivotData()
2942cdf0e10cSrcweir {
2943cdf0e10cSrcweir     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetPivotData" );
2944cdf0e10cSrcweir     sal_uInt8 nParamCount = GetByte();
2945cdf0e10cSrcweir 
2946cdf0e10cSrcweir     if ( MustHaveParamCount( nParamCount, 2, 30 ) )
2947cdf0e10cSrcweir     {
2948cdf0e10cSrcweir         // there must be an even number of args
2949cdf0e10cSrcweir         //      target, ref, then field/item pairs
2950cdf0e10cSrcweir         if( (nParamCount % 2) == 1)
2951cdf0e10cSrcweir             goto failed;
2952cdf0e10cSrcweir 
2953cdf0e10cSrcweir         bool bOldSyntax = false;
2954cdf0e10cSrcweir         if ( nParamCount == 2 )
2955cdf0e10cSrcweir         {
2956cdf0e10cSrcweir             // if the first parameter is a ref, assume old syntax
2957cdf0e10cSrcweir             StackVar eFirstType = GetStackType( 2 );
2958cdf0e10cSrcweir             if ( eFirstType == svSingleRef || eFirstType == svDoubleRef )
2959cdf0e10cSrcweir                 bOldSyntax = true;
2960cdf0e10cSrcweir         }
2961cdf0e10cSrcweir 
2962cdf0e10cSrcweir         ScDPGetPivotDataField aTarget;                  // target field, and returns result
2963cdf0e10cSrcweir         std::vector< ScDPGetPivotDataField > aFilters;
2964cdf0e10cSrcweir         String aFilterList;
2965cdf0e10cSrcweir         if ( bOldSyntax )
2966cdf0e10cSrcweir             aFilterList = GetString();      // old syntax: second parameter is list of constraints
2967cdf0e10cSrcweir         else
2968cdf0e10cSrcweir         {
2969cdf0e10cSrcweir             // new syntax: separate name/value pairs
2970cdf0e10cSrcweir 
2971cdf0e10cSrcweir             sal_uInt16 nFilterCount = nParamCount / 2 - 1;
2972cdf0e10cSrcweir             aFilters.resize( nFilterCount );
2973cdf0e10cSrcweir 
2974cdf0e10cSrcweir             sal_uInt16 i = nFilterCount;
2975cdf0e10cSrcweir             while( i-- > 0 )
2976cdf0e10cSrcweir             {
2977cdf0e10cSrcweir                 //! should allow numeric constraint values
2978cdf0e10cSrcweir                 aFilters[i].mbValIsStr = sal_True;
2979cdf0e10cSrcweir                 aFilters[i].maValStr = GetString();
2980cdf0e10cSrcweir 
2981cdf0e10cSrcweir                 aFilters[i].maFieldName = GetString();
2982cdf0e10cSrcweir             }
2983cdf0e10cSrcweir         }
2984cdf0e10cSrcweir 
2985cdf0e10cSrcweir         // common to both syntaxes: a reference to the data pilot table
2986cdf0e10cSrcweir 
2987cdf0e10cSrcweir         ScRange aBlock;
2988cdf0e10cSrcweir         switch ( GetStackType() )
2989cdf0e10cSrcweir         {
2990cdf0e10cSrcweir             case svDoubleRef :
2991cdf0e10cSrcweir                 PopDoubleRef( aBlock );
2992cdf0e10cSrcweir                 break;
2993cdf0e10cSrcweir 
2994cdf0e10cSrcweir             case svSingleRef :
2995cdf0e10cSrcweir                 {
2996cdf0e10cSrcweir                     ScAddress aAddr;
2997cdf0e10cSrcweir                     PopSingleRef( aAddr );
2998cdf0e10cSrcweir                     aBlock = aAddr;
2999cdf0e10cSrcweir                     break;
3000cdf0e10cSrcweir                 }
3001cdf0e10cSrcweir             default:
3002cdf0e10cSrcweir                 goto failed;
3003cdf0e10cSrcweir         }
3004cdf0e10cSrcweir         // NOTE : MS Excel docs claim to use the 'most recent' which is not
3005cdf0e10cSrcweir         // exactly the same as what we do in ScDocument::GetDPAtBlock
3006cdf0e10cSrcweir         // However we do need to use GetDPABlock
3007cdf0e10cSrcweir         ScDPObject* pDPObj = pDok->GetDPAtBlock ( aBlock );
3008cdf0e10cSrcweir         if( NULL == pDPObj)
3009cdf0e10cSrcweir             goto failed;
3010cdf0e10cSrcweir 
3011cdf0e10cSrcweir         if ( bOldSyntax )
3012cdf0e10cSrcweir         {
3013cdf0e10cSrcweir             // fill aFilters / aTarget from aFilterList string
3014cdf0e10cSrcweir             if ( !pDPObj->ParseFilters( aTarget, aFilters, aFilterList ) )
3015cdf0e10cSrcweir                 goto failed;
3016cdf0e10cSrcweir         }
3017cdf0e10cSrcweir         else
3018cdf0e10cSrcweir             aTarget.maFieldName = GetString(); // new syntax: first parameter is data field name
3019cdf0e10cSrcweir 
3020cdf0e10cSrcweir         if( pDPObj->GetPivotData( aTarget, aFilters ) )
3021cdf0e10cSrcweir         {
3022cdf0e10cSrcweir             if( aTarget.mbValIsStr )
3023cdf0e10cSrcweir                 PushString( aTarget.maValStr );
3024cdf0e10cSrcweir             else
3025cdf0e10cSrcweir                 PushDouble( aTarget.mnValNum );
3026cdf0e10cSrcweir             return;
3027cdf0e10cSrcweir         }
3028cdf0e10cSrcweir     }
3029cdf0e10cSrcweir 
3030cdf0e10cSrcweir failed :
3031cdf0e10cSrcweir     PushError( errNoRef );
3032cdf0e10cSrcweir }
3033