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