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