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