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