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