1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "interpre.hxx"
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>
33 #include "ddelink.hxx"
34 #include "scmatrix.hxx"
35 #include "compiler.hxx"
36 #include "formulacell.hxx"
37 #include "document.hxx"
38 #include "dociter.hxx"
39 #include "docoptio.hxx"
40 #include "unitconv.hxx"
41 #include "globstr.hrc"
43 #include "dpobject.hxx"
45 #include "tokenarray.hxx"
46 #include "globalnames.hxx"
48 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
53 using namespace com::sun::star
;
54 using namespace formula
;
56 #define SCdEpsilon 1.0E-7
60 double ScInterpreter::GetDateSerial( sal_Int16 nYear
, sal_Int16 nMonth
, sal_Int16 nDay
,
61 bool bStrict
, bool bCheckGregorian
)
63 if ( nYear
< 100 && !bStrict
)
64 nYear
= pFormatter
->ExpandTwoDigitYear( nYear
);
65 // Do not use a default Date ctor here because it asks system time with a
66 // performance penalty.
69 nY
= nYear
, nM
= nMonth
, nD
= nDay
;
74 nY
= nYear
+ (nMonth
-1) / 12;
75 nM
= ((nMonth
-1) % 12) + 1;
79 nY
= nYear
+ (nMonth
-12) / 12;
80 nM
= 12 - (-nMonth
) % 12;
84 Date
aDate( nD
, nM
, nY
);
87 if ((!bCheckGregorian
&& aDate
.IsValidDate()) || (bCheckGregorian
&& aDate
.IsValidAndGregorian()))
88 return (double) (aDate
- *(pFormatter
->GetNullDate()));
98 void ScInterpreter::ScGetActDate()
100 nFuncFmtType
= NUMBERFORMAT_DATE
;
101 Date
aActDate( Date::SYSTEM
);
102 long nDiff
= aActDate
- *(pFormatter
->GetNullDate());
103 PushDouble((double) nDiff
);
106 void ScInterpreter::ScGetActTime()
108 nFuncFmtType
= NUMBERFORMAT_DATETIME
;
109 Date
aActDate( Date::SYSTEM
);
110 long nDiff
= aActDate
- *(pFormatter
->GetNullDate());
111 Time
aActTime( Time::SYSTEM
);
112 double nTime
= aActTime
.GetHour() / static_cast<double>(::Time::hourPerDay
) +
113 aActTime
.GetMin() / static_cast<double>(::Time::minutePerDay
) +
114 aActTime
.GetSec() / static_cast<double>(::Time::secondPerDay
) +
115 aActTime
.GetNanoSec() / static_cast<double>(::Time::nanoSecPerDay
);
116 PushDouble( (double) nDiff
+ nTime
);
119 void ScInterpreter::ScGetYear()
121 Date aDate
= *(pFormatter
->GetNullDate());
122 aDate
+= (long) ::rtl::math::approxFloor(GetDouble());
123 PushDouble( (double) aDate
.GetYear() );
126 void ScInterpreter::ScGetMonth()
128 Date aDate
= *(pFormatter
->GetNullDate());
129 aDate
+= (long) ::rtl::math::approxFloor(GetDouble());
130 PushDouble( (double) aDate
.GetMonth() );
133 void ScInterpreter::ScGetDay()
135 Date aDate
= *(pFormatter
->GetNullDate());
136 aDate
+= (long)::rtl::math::approxFloor(GetDouble());
137 PushDouble((double) aDate
.GetDay());
140 void ScInterpreter::ScGetMin()
142 double fTime
= GetDouble();
143 fTime
-= ::rtl::math::approxFloor(fTime
); // Datumsanteil weg
144 long nVal
= (long)::rtl::math::approxFloor(fTime
*DATE_TIME_FACTOR
+0.5) % ::Time::secondPerHour
;
145 PushDouble( (double) (nVal
/ ::Time::secondPerMinute
) );
148 void ScInterpreter::ScGetSec()
150 double fTime
= GetDouble();
151 fTime
-= ::rtl::math::approxFloor(fTime
); // Datumsanteil weg
152 long nVal
= (long)::rtl::math::approxFloor(fTime
*DATE_TIME_FACTOR
+0.5) % ::Time::secondPerMinute
;
153 PushDouble( (double) nVal
);
156 void ScInterpreter::ScGetHour()
158 double fTime
= GetDouble();
159 fTime
-= ::rtl::math::approxFloor(fTime
); // Datumsanteil weg
160 long nVal
= (long)::rtl::math::approxFloor(fTime
*DATE_TIME_FACTOR
+0.5) / ::Time::secondPerHour
;
161 PushDouble((double) nVal
);
164 void ScInterpreter::ScGetDateValue()
166 OUString aInputString
= GetString().getString();
167 sal_uInt32 nFIndex
= 0; // damit default Land/Spr.
169 if (pFormatter
->IsNumberFormat(aInputString
, nFIndex
, fVal
))
171 short eType
= pFormatter
->GetType(nFIndex
);
172 if (eType
== NUMBERFORMAT_DATE
|| eType
== NUMBERFORMAT_DATETIME
)
173 PushDouble(::rtl::math::approxFloor(fVal
));
175 PushIllegalArgument();
178 PushIllegalArgument();
181 void ScInterpreter::ScGetDayOfWeek()
183 sal_uInt8 nParamCount
= GetByte();
184 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
187 if (nParamCount
== 2)
188 nFlag
= (short) ::rtl::math::approxFloor(GetDouble());
192 Date aDate
= *(pFormatter
->GetNullDate());
193 aDate
+= (long)::rtl::math::approxFloor(GetDouble());
194 int nVal
= (int) aDate
.GetDayOfWeek();
208 void ScInterpreter::ScGetWeekOfYear()
210 if ( MustHaveParamCount( GetByte(), 2 ) )
212 short nFlag
= (short) ::rtl::math::approxFloor(GetDouble());
214 Date aDate
= *(pFormatter
->GetNullDate());
215 aDate
+= (long)::rtl::math::approxFloor(GetDouble());
216 PushInt( (int) aDate
.GetWeekOfYear( nFlag
== 1 ? SUNDAY
: MONDAY
));
220 void ScInterpreter::ScEasterSunday()
222 nFuncFmtType
= NUMBERFORMAT_DATE
;
223 if ( MustHaveParamCount( GetByte(), 1 ) )
225 sal_Int16 nDay
, nMonth
, nYear
;
226 nYear
= (sal_Int16
) ::rtl::math::approxFloor( GetDouble() );
228 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
;
232 B
= int(nYear
/ 100);
236 F
= int((B
+ 8) / 25);
237 G
= int((B
- F
+ 1) / 3);
238 H
= (19 * N
+ B
- D
- G
+ 15) % 30;
241 L
= (32 + 2 * E
+ 2 * I
- H
- K
) % 7;
242 M
= int((N
+ 11 * H
+ 22 * L
) / 451);
243 O
= H
+ L
- 7 * M
+ 114;
244 nDay
= sal::static_int_cast
<sal_Int16
>( O
% 31 + 1 );
245 nMonth
= sal::static_int_cast
<sal_Int16
>( int(O
/ 31) );
246 PushDouble( GetDateSerial( nYear
, nMonth
, nDay
, true, true ) );
250 void ScInterpreter::ScGetDate()
252 nFuncFmtType
= NUMBERFORMAT_DATE
;
253 if ( MustHaveParamCount( GetByte(), 3 ) )
255 sal_Int16 nDay
= (sal_Int16
) ::rtl::math::approxFloor(GetDouble());
256 sal_Int16 nMonth
= (sal_Int16
) ::rtl::math::approxFloor(GetDouble());
257 sal_Int16 nYear
= (sal_Int16
) ::rtl::math::approxFloor(GetDouble());
259 PushIllegalArgument();
262 PushDouble(GetDateSerial(nYear
, nMonth
, nDay
, false, true));
267 void ScInterpreter::ScGetTime()
269 nFuncFmtType
= NUMBERFORMAT_TIME
;
270 if ( MustHaveParamCount( GetByte(), 3 ) )
272 double nSec
= GetDouble();
273 double nMin
= GetDouble();
274 double nHour
= GetDouble();
275 double fTime
= fmod( (nHour
* ::Time::secondPerHour
) + (nMin
* ::Time::secondPerMinute
) + nSec
, DATE_TIME_FACTOR
) / DATE_TIME_FACTOR
;
277 PushIllegalArgument();
283 void ScInterpreter::ScGetDiffDate()
285 if ( MustHaveParamCount( GetByte(), 2 ) )
287 double nDate2
= GetDouble();
288 double nDate1
= GetDouble();
289 PushDouble(nDate1
- nDate2
);
293 void ScInterpreter::ScGetDiffDate360()
295 /* Implementation follows
296 * http://www.bondmarkets.com/eCommerce/SMD_Fields_030802.pdf
297 * Appendix B: Day-Count Bases, there are 7 different ways to calculate the
298 * 30-days count. That document also claims that Excel implements the "PSA
299 * 30" or "NASD 30" method (funny enough they also state that Excel is the
300 * only tool that does so).
302 * Note that the definiton given in
303 * http://msdn.microsoft.com/library/en-us/office97/html/SEB7C.asp
304 * is _not_ the way how it is actually calculated by Excel (that would not
305 * even match any of the 7 methods mentioned above) and would result in the
306 * following test cases producing wrong results according to that appendix B:
308 * 28-Feb-95 31-Aug-95 181 instead of 180
309 * 29-Feb-96 31-Aug-96 181 instead of 180
310 * 30-Jan-96 31-Mar-96 61 instead of 60
311 * 31-Jan-96 31-Mar-96 61 instead of 60
313 * Still, there is a difference between OOoCalc and Excel:
315 * 02-Feb-99 31-Mar-00 results in 419
316 * 31-Mar-00 02-Feb-99 results in -418
317 * In Calc the result is 419 respectively -419. I consider the -418 a bug in Excel.
320 sal_uInt8 nParamCount
= GetByte();
321 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
324 if (nParamCount
== 3)
328 double nDate2
= GetDouble();
329 double nDate1
= GetDouble();
331 PushError( nGlobalError
);
335 // #i84934# only for non-US European algorithm swap dates. Else
336 // follow Excel's meaningless extrapolation for "interoperability".
337 if (bFlag
&& (nDate2
< nDate1
))
346 Date aDate1
= *(pFormatter
->GetNullDate());
347 aDate1
+= (long) ::rtl::math::approxFloor(nDate1
);
348 Date aDate2
= *(pFormatter
->GetNullDate());
349 aDate2
+= (long) ::rtl::math::approxFloor(nDate2
);
350 if (aDate1
.GetDay() == 31)
351 aDate1
-= (sal_uLong
) 1;
354 if (aDate1
.GetMonth() == 2)
356 switch ( aDate1
.GetDay() )
359 if ( !aDate1
.IsLeapYear() )
368 if (aDate2
.GetDay() == 31)
372 if (aDate1
.GetDay() == 30)
373 aDate2
-= (sal_uLong
) 1;
378 PushDouble( fSign
* (double)
379 ( (double) aDate2
.GetDay() + (double) aDate2
.GetMonth() * 30.0 +
380 (double) aDate2
.GetYear() * 360.0
381 - (double) aDate1
.GetDay() - (double) aDate1
.GetMonth() * 30.0
382 - (double)aDate1
.GetYear() * 360.0) );
387 // fdo#44456 function DATEDIF as defined in ODF1.2 (Par. 6.10.3)
388 void ScInterpreter::ScGetDateDif()
390 if ( MustHaveParamCount( GetByte(), 3 ) )
392 OUString aInterval
= GetString().getString();
393 double nDate2
= GetDouble();
394 double nDate1
= GetDouble();
398 PushError( nGlobalError
);
402 // Excel doesn't swap dates or return negative numbers, so don't we.
405 PushIllegalArgument();
409 long dd
= nDate2
- nDate1
;
410 // Zero difference or number of days can be returned immediately.
411 if (dd
== 0 || aInterval
.equalsIgnoreAsciiCase( "d" ))
417 // split dates in day, month, year for use with formats other than "d"
418 sal_uInt16 d1
, m1
, y1
, d2
, m2
, y2
;
419 Date
aDate1( *( pFormatter
->GetNullDate()));
420 aDate1
+= (long) ::rtl::math::approxFloor( nDate1
);
421 y1
= aDate1
.GetYear();
422 m1
= aDate1
.GetMonth();
423 d1
= aDate1
.GetDay();
424 Date
aDate2( *( pFormatter
->GetNullDate()));
425 aDate2
+= (long) ::rtl::math::approxFloor( nDate2
);
426 y2
= aDate2
.GetYear();
427 m2
= aDate2
.GetMonth();
428 d2
= aDate2
.GetDay();
430 if ( aInterval
.equalsIgnoreAsciiCase( "m" ) )
432 // Return number of months.
433 int md
= m2
- m1
+ 12 * (y2
- y1
);
438 else if ( aInterval
.equalsIgnoreAsciiCase( "y" ) )
440 // Return number of years.
444 if (m2
> m1
|| (m2
== m1
&& d2
>= d1
))
445 yd
= y2
- y1
; // complete years between dates
447 yd
= y2
- y1
- 1; // one incomplete year
451 // Year is equal as we don't allow reversed arguments, no
452 // complete year between dates.
457 else if ( aInterval
.equalsIgnoreAsciiCase( "md" ) )
459 // Return number of days, excluding months and years.
460 // This is actually the remainder of days when subtracting years
461 // and months from the difference of dates. Birthday-like 23 years
462 // and 10 months and 19 days.
464 // Algorithm's roll-over behavior extracted from Excel by try and
466 // If day1 <= day2 then simply day2 - day1.
467 // If day1 > day2 then set month1 to month2-1 and year1 to
468 // year2(-1) and subtract dates, e.g. for 2012-01-28,2012-03-01 set
469 // 2012-02-28 and then (2012-03-01)-(2012-02-28) => 2 days (leap
471 // For 2011-01-29,2011-03-01 the non-existent 2011-02-29 rolls over
472 // to 2011-03-01 so the result is 0. Same for day 31 in months with
482 aDate1
.SetYear( y2
- 1 );
483 aDate1
.SetMonth( 12 );
487 aDate1
.SetYear( y2
);
488 aDate1
.SetMonth( m2
- 1 );
491 nd
= aDate2
- aDate1
;
495 else if ( aInterval
.equalsIgnoreAsciiCase( "ym" ) )
497 // Return number of months, excluding years.
498 int md
= m2
- m1
+ 12 * (y2
- y1
);
504 else if ( aInterval
.equalsIgnoreAsciiCase( "yd" ) )
506 // Return number of days, excluding years.
508 /* TODO: check what Excel really does, though this seems to be
511 // Condition corresponds with "y".
512 if (m2
> m1
|| (m2
== m1
&& d2
>= d1
))
513 aDate1
.SetYear( y2
);
515 aDate1
.SetYear( y2
- 1 );
516 // XXX NOTE: Excel for the case 1988-06-22,2012-05-11 returns
517 // 323, whereas the result here is 324. Don't they use the leap
519 // http://www.cpearson.com/excel/datedif.aspx "DATEDIF And Leap
520 // Years" is not correct and Excel 2010 correctly returns 0 in
521 // both cases mentioned there. Also using year1 as mentioned
522 // produces incorrect results in other cases and different from
523 // Excel 2010. Apparently they fixed some calculations.
525 double nd
= aDate2
- aDate1
;
529 PushIllegalArgument(); // unsupported format
533 void ScInterpreter::ScGetTimeValue()
535 OUString aInputString
= GetString().getString();
536 sal_uInt32 nFIndex
= 0; // damit default Land/Spr.
538 if (pFormatter
->IsNumberFormat(aInputString
, nFIndex
, fVal
))
540 short eType
= pFormatter
->GetType(nFIndex
);
541 if (eType
== NUMBERFORMAT_TIME
|| eType
== NUMBERFORMAT_DATETIME
)
543 double fDateVal
= rtl::math::approxFloor(fVal
);
544 double fTimeVal
= fVal
- fDateVal
;
545 PushDouble(fTimeVal
);
548 PushIllegalArgument();
551 PushIllegalArgument();
554 void ScInterpreter::ScPlusMinus()
556 double nVal
= GetDouble();
565 void ScInterpreter::ScAbs()
567 PushDouble(fabs(GetDouble()));
570 void ScInterpreter::ScInt()
572 PushDouble(::rtl::math::approxFloor(GetDouble()));
575 void ScInterpreter::RoundNumber( rtl_math_RoundingMode eMode
)
577 sal_uInt8 nParamCount
= GetByte();
578 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
581 if (nParamCount
== 1)
582 fVal
= ::rtl::math::round( GetDouble(), 0, eMode
);
585 sal_Int32 nDec
= (sal_Int32
) ::rtl::math::approxFloor(GetDouble());
586 if( nDec
< -20 || nDec
> 20 )
587 PushIllegalArgument();
589 fVal
= ::rtl::math::round( GetDouble(), (short)nDec
, eMode
);
595 void ScInterpreter::ScRound()
597 RoundNumber( rtl_math_RoundingMode_Corrected
);
600 void ScInterpreter::ScRoundDown()
602 RoundNumber( rtl_math_RoundingMode_Down
);
605 void ScInterpreter::ScRoundUp()
607 RoundNumber( rtl_math_RoundingMode_Up
);
610 void ScInterpreter::ScCeil()
612 sal_uInt8 nParamCount
= GetByte();
613 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
615 bool bAbs
= ( nParamCount
== 3 ? GetBool() : false );
616 double fDec
= GetDouble();
617 double fVal
= GetDouble();
620 else if (fVal
*fDec
< 0.0)
621 PushIllegalArgument();
624 if ( !bAbs
&& fVal
< 0.0 )
625 PushDouble(::rtl::math::approxFloor(fVal
/fDec
) * fDec
);
627 PushDouble(::rtl::math::approxCeil(fVal
/fDec
) * fDec
);
632 void ScInterpreter::ScFloor()
634 sal_uInt8 nParamCount
= GetByte();
635 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
637 bool bAbs
= ( nParamCount
== 3 ? GetBool() : false );
638 double fDec
= GetDouble();
639 double fVal
= GetDouble();
642 else if (fVal
*fDec
< 0.0)
643 PushIllegalArgument();
646 if ( !bAbs
&& fVal
< 0.0 )
647 PushDouble(::rtl::math::approxCeil(fVal
/fDec
) * fDec
);
649 PushDouble(::rtl::math::approxFloor(fVal
/fDec
) * fDec
);
654 void ScInterpreter::ScEven()
656 double fVal
= GetDouble();
658 PushDouble(::rtl::math::approxFloor(fVal
/2.0) * 2.0);
660 PushDouble(::rtl::math::approxCeil(fVal
/2.0) * 2.0);
663 void ScInterpreter::ScOdd()
665 double fVal
= GetDouble();
668 fVal
= ::rtl::math::approxCeil(fVal
);
669 if (fmod(fVal
, 2.0) == 0.0)
674 fVal
= ::rtl::math::approxFloor(fVal
);
675 if (fmod(fVal
, 2.0) == 0.0)
681 void ScInterpreter::ScArcTan2()
683 if ( MustHaveParamCount( GetByte(), 2 ) )
685 double nVal2
= GetDouble();
686 double nVal1
= GetDouble();
687 PushDouble(atan2(nVal2
, nVal1
));
691 void ScInterpreter::ScLog()
693 sal_uInt8 nParamCount
= GetByte();
694 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
697 if (nParamCount
== 2)
701 double nVal
= GetDouble();
702 if (nVal
> 0.0 && nBase
> 0.0 && nBase
!= 1.0)
703 PushDouble(log(nVal
) / log(nBase
));
705 PushIllegalArgument();
709 void ScInterpreter::ScLn()
711 double fVal
= GetDouble();
713 PushDouble(log(fVal
));
715 PushIllegalArgument();
718 void ScInterpreter::ScLog10()
720 double fVal
= GetDouble();
722 PushDouble(log10(fVal
));
724 PushIllegalArgument();
727 void ScInterpreter::ScNPV()
729 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
730 short nParamCount
= GetByte();
731 if ( MustHaveParamCount( nParamCount
, 2, 31 ) )
734 // Wir drehen den Stack um!!
735 FormulaToken
* pTemp
[ 31 ];
736 for( short i
= 0; i
< nParamCount
; i
++ )
737 pTemp
[ i
] = pStack
[ sp
- i
- 1 ];
738 memcpy( &pStack
[ sp
- nParamCount
], pTemp
, nParamCount
* sizeof( FormulaToken
* ) );
739 if (nGlobalError
== 0)
742 double nZins
= GetDouble();
744 size_t nRefInList
= 0;
746 while (nParamCount
-- > 0)
748 switch (GetStackType())
752 nVal
+= (GetDouble() / pow(1.0 + nZins
, (double)nCount
));
759 PopSingleRef( aAdr
);
760 ScRefCellValue aCell
;
761 aCell
.assign(*pDok
, aAdr
);
762 if (!aCell
.hasEmptyValue() && aCell
.hasNumeric())
764 double nCellVal
= GetCellValue(aAdr
, aCell
);
765 nVal
+= (nCellVal
/ pow(1.0 + nZins
, (double)nCount
));
775 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
776 ScHorizontalValueIterator
aValIter( pDok
, aRange
, glSubTotal
);
777 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
779 nVal
+= (nCellVal
/ pow(1.0 + nZins
, (double)nCount
));
786 default : SetError(errIllegalParameter
); break;
794 void ScInterpreter::ScIRR()
797 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
798 sal_uInt8 nParamCount
= GetByte();
799 if ( !MustHaveParamCount( nParamCount
, 1, 2 ) )
801 if (nParamCount
== 2)
802 fSchaetzwert
= GetDouble();
805 sal_uInt16 sPos
= sp
; // Stack-Position merken
807 double x
, xNeu
, fWert
, fZaehler
, fNenner
, nCount
;
808 if (fSchaetzwert
== -1.0)
809 x
= 0.1; // default gegen Nulldivisionen
811 x
= fSchaetzwert
; // Startwert
812 switch (GetStackType())
818 PushIllegalParameter();
822 const sal_uInt16 nIterationsMax
= 20;
823 sal_uInt16 nItCount
= 0;
825 while (fEps
> SCdEpsilon
&& nItCount
< nIterationsMax
)
826 { // Newton-Verfahren:
827 sp
= sPos
; // Stack zuruecksetzen
832 PopDoubleRef( aRange
);
833 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
834 if (aValIter
.GetFirst(fWert
, nErr
))
836 fZaehler
+= fWert
/ pow(1.0+x
,(double)nCount
);
837 fNenner
+= -nCount
* fWert
/ pow(1.0+x
,nCount
+1.0);
839 while ((nErr
== 0) && aValIter
.GetNext(fWert
, nErr
))
841 fZaehler
+= fWert
/ pow(1.0+x
,(double)nCount
);
842 fNenner
+= -nCount
* fWert
/ pow(1.0+x
,nCount
+1.0);
847 xNeu
= x
- fZaehler
/ fNenner
; // x(i+1) = x(i)-f(x(i))/f'(x(i))
849 fEps
= fabs(xNeu
- x
);
852 if (fSchaetzwert
== 0.0 && fabs(x
) < SCdEpsilon
)
853 x
= 0.0; // auf Null normieren
854 if (fEps
< SCdEpsilon
)
857 PushError( errNoConvergence
);
860 void ScInterpreter::ScMIRR()
861 { // range_of_values ; rate_invest ; rate_reinvest
862 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
863 if( MustHaveParamCount( GetByte(), 3 ) )
865 double fRate1_reinvest
= GetDouble() + 1;
866 double fRate1_invest
= GetDouble() + 1;
869 PopDoubleRef( aRange
);
872 PushError( nGlobalError
);
875 double fNPV_reinvest
= 0.0;
876 double fPow_reinvest
= 1.0;
877 double fNPV_invest
= 0.0;
878 double fPow_invest
= 1.0;
879 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
);
881 sal_uLong nCount
= 0;
882 sal_uInt16 nIterError
= 0;
884 bool bLoop
= aValIter
.GetFirst( fCellValue
, nIterError
);
887 if( fCellValue
> 0.0 ) // reinvestments
888 fNPV_reinvest
+= fCellValue
* fPow_reinvest
;
889 else if( fCellValue
< 0.0 ) // investments
890 fNPV_invest
+= fCellValue
* fPow_invest
;
891 fPow_reinvest
/= fRate1_reinvest
;
892 fPow_invest
/= fRate1_invest
;
895 bLoop
= aValIter
.GetNext( fCellValue
, nIterError
);
898 PushError( nIterError
);
901 double fResult
= -fNPV_reinvest
/ fNPV_invest
;
902 fResult
*= pow( fRate1_reinvest
, (double) nCount
- 1 );
903 fResult
= pow( fResult
, 1.0 / (nCount
- 1) );
904 PushDouble( fResult
- 1.0 );
910 void ScInterpreter::ScISPMT()
911 { // rate ; period ; total_periods ; invest
912 if( MustHaveParamCount( GetByte(), 4 ) )
914 double fInvest
= GetDouble();
915 double fTotal
= GetDouble();
916 double fPeriod
= GetDouble();
917 double fRate
= GetDouble();
920 PushError( nGlobalError
);
922 PushDouble( fInvest
* fRate
* (fPeriod
/ fTotal
- 1.0) );
927 double ScInterpreter::ScGetBw(double fZins
, double fZzr
, double fRmz
,
928 double fZw
, double fF
)
932 fBw
= fZw
+ fRmz
* fZzr
;
934 fBw
= (fZw
* pow(1.0 + fZins
, -fZzr
))
935 + (fRmz
* (1.0 - pow(1.0 + fZins
, -fZzr
+ 1.0)) / fZins
)
938 fBw
= (fZw
* pow(1.0 + fZins
, -fZzr
))
939 + (fRmz
* (1.0 - pow(1.0 + fZins
, -fZzr
)) / fZins
);
943 void ScInterpreter::ScBW()
945 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
946 double nRmz
, nZzr
, nZins
, nZw
= 0, nFlag
= 0;
947 sal_uInt8 nParamCount
= GetByte();
948 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
950 if (nParamCount
== 5)
952 if (nParamCount
>= 4)
957 PushDouble(ScGetBw(nZins
, nZzr
, nRmz
, nZw
, nFlag
));
960 void ScInterpreter::ScDIA()
962 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
963 if ( MustHaveParamCount( GetByte(), 4 ) )
965 double nZr
= GetDouble();
966 double nDauer
= GetDouble();
967 double nRest
= GetDouble();
968 double nWert
= GetDouble();
969 double nDia
= ((nWert
- nRest
) * (nDauer
- nZr
+ 1.0)) /
970 ((nDauer
* (nDauer
+ 1.0)) / 2.0);
975 double ScInterpreter::ScGetGDA(double fWert
, double fRest
, double fDauer
,
976 double fPeriode
, double fFactor
)
978 double fGda
, fZins
, fAlterWert
, fNeuerWert
;
979 fZins
= fFactor
/ fDauer
;
989 fAlterWert
= fWert
* pow(1.0 - fZins
, fPeriode
- 1.0);
990 fNeuerWert
= fWert
* pow(1.0 - fZins
, fPeriode
);
992 if (fNeuerWert
< fRest
)
993 fGda
= fAlterWert
- fRest
;
995 fGda
= fAlterWert
- fNeuerWert
;
1001 void ScInterpreter::ScGDA()
1003 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1004 sal_uInt8 nParamCount
= GetByte();
1005 if ( MustHaveParamCount( nParamCount
, 4, 5 ) )
1008 if (nParamCount
== 5)
1009 nFactor
= GetDouble();
1012 double nPeriode
= GetDouble();
1013 double nDauer
= GetDouble();
1014 double nRest
= GetDouble();
1015 double nWert
= GetDouble();
1016 if (nWert
< 0.0 || nRest
< 0.0 || nFactor
<= 0.0 || nRest
> nWert
1017 || nPeriode
< 1.0 || nPeriode
> nDauer
)
1018 PushIllegalArgument();
1020 PushDouble(ScGetGDA(nWert
, nRest
, nDauer
, nPeriode
, nFactor
));
1024 void ScInterpreter::ScGDA2()
1026 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1027 sal_uInt8 nParamCount
= GetByte();
1028 if ( !MustHaveParamCount( nParamCount
, 4, 5 ) )
1031 if (nParamCount
== 4)
1034 nMonate
= ::rtl::math::approxFloor(GetDouble());
1035 double nPeriode
= GetDouble();
1036 double nDauer
= GetDouble();
1037 double nRest
= GetDouble();
1038 double nWert
= GetDouble();
1039 if (nMonate
< 1.0 || nMonate
> 12.0 || nDauer
> 1200.0 || nRest
< 0.0 ||
1040 nPeriode
> (nDauer
+ 1.0) || nRest
> nWert
|| nWert
< 0.0)
1042 PushIllegalArgument();
1045 double nAbRate
= 1.0 - pow(nRest
/ nWert
, 1.0 / nDauer
);
1046 nAbRate
= ::rtl::math::approxFloor((nAbRate
* 1000.0) + 0.5) / 1000.0;
1047 double nErsteAbRate
= nWert
* nAbRate
* nMonate
/ 12.0;
1049 if (::rtl::math::approxFloor(nPeriode
) == 1)
1050 nGda2
= nErsteAbRate
;
1053 double nSummAbRate
= nErsteAbRate
;
1054 double nMin
= nDauer
;
1055 if (nMin
> nPeriode
) nMin
= nPeriode
;
1056 sal_uInt16 iMax
= (sal_uInt16
)::rtl::math::approxFloor(nMin
);
1057 for (sal_uInt16 i
= 2; i
<= iMax
; i
++)
1059 nGda2
= (nWert
- nSummAbRate
) * nAbRate
;
1060 nSummAbRate
+= nGda2
;
1062 if (nPeriode
> nDauer
)
1063 nGda2
= ((nWert
- nSummAbRate
) * nAbRate
* (12.0 - nMonate
)) / 12.0;
1068 double ScInterpreter::ScInterVDB(double fWert
,double fRest
,double fDauer
,
1069 double fDauer1
,double fPeriode
,double fFactor
)
1072 double fIntEnd
= ::rtl::math::approxCeil(fPeriode
);
1073 sal_uLong nLoopEnd
= (sal_uLong
) fIntEnd
;
1076 double fRestwert
= fWert
- fRest
;
1077 bool bNowLia
= false;
1082 for ( i
= 1; i
<= nLoopEnd
; i
++)
1086 fGda
= ScGetGDA(fWert
, fRest
, fDauer
, (double) i
, fFactor
);
1087 fLia
= fRestwert
/ (fDauer1
- (double) (i
-1));
1106 fTerm
*= ( fPeriode
+ 1.0 - fIntEnd
);
1113 inline double DblMin( double a
, double b
)
1115 return (a
< b
) ? a
: b
;
1118 void ScInterpreter::ScVDB()
1120 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1121 sal_uInt8 nParamCount
= GetByte();
1122 if ( MustHaveParamCount( nParamCount
, 5, 7 ) )
1124 double fWert
, fRest
, fDauer
, fAnfang
, fEnde
, fFactor
, fVdb
= 0.0;
1126 if (nParamCount
== 7)
1130 if (nParamCount
>= 6)
1131 fFactor
= GetDouble();
1134 fEnde
= GetDouble();
1135 fAnfang
= GetDouble();
1136 fDauer
= GetDouble();
1137 fRest
= GetDouble();
1138 fWert
= GetDouble();
1139 if (fAnfang
< 0.0 || fEnde
< fAnfang
|| fEnde
> fDauer
|| fWert
< 0.0
1140 || fRest
> fWert
|| fFactor
<= 0.0)
1141 PushIllegalArgument();
1144 double fIntStart
= ::rtl::math::approxFloor(fAnfang
);
1145 double fIntEnd
= ::rtl::math::approxCeil(fEnde
);
1146 sal_uLong nLoopStart
= (sal_uLong
) fIntStart
;
1147 sal_uLong nLoopEnd
= (sal_uLong
) fIntEnd
;
1152 for (sal_uLong i
= nLoopStart
+ 1; i
<= nLoopEnd
; i
++)
1154 double fTerm
= ScGetGDA(fWert
, fRest
, fDauer
, (double) i
, fFactor
);
1156 // Teilperioden am Anfang / Ende beruecksichtigen:
1157 if ( i
== nLoopStart
+1 )
1158 fTerm
*= ( DblMin( fEnde
, fIntStart
+ 1.0 ) - fAnfang
);
1159 else if ( i
== nLoopEnd
)
1160 fTerm
*= ( fEnde
+ 1.0 - fIntEnd
);
1168 double fDauer1
=fDauer
;
1170 //@Die Frage aller Fragen: "Ist das hier richtig"
1171 if(!::rtl::math::approxEqual(fAnfang
,::rtl::math::approxFloor(fAnfang
)))
1175 if(fAnfang
>fDauer
/2 || ::rtl::math::approxEqual(fAnfang
,fDauer
/2))
1177 double fPart
=fAnfang
-fDauer
/2;
1185 fWert
-=ScInterVDB(fWert
,fRest
,fDauer
,fDauer1
,fAnfang
,fFactor
);
1186 fVdb
=ScInterVDB(fWert
,fRest
,fDauer
,fDauer
-fAnfang
,fEnde
-fAnfang
,fFactor
);
1193 void ScInterpreter::ScLaufz()
1195 if ( MustHaveParamCount( GetByte(), 3 ) )
1197 double nZukunft
= GetDouble();
1198 double nGegenwart
= GetDouble();
1199 double nZins
= GetDouble();
1200 PushDouble(log(nZukunft
/ nGegenwart
) / log(1.0 + nZins
));
1204 void ScInterpreter::ScLIA()
1206 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1207 if ( MustHaveParamCount( GetByte(), 3 ) )
1209 double nDauer
= GetDouble();
1210 double nRest
= GetDouble();
1211 double nWert
= GetDouble();
1212 PushDouble((nWert
- nRest
) / nDauer
);
1216 double ScInterpreter::ScGetRmz(double fRate
, double fNper
, double fPv
,
1217 double fFv
, double fPaytype
)
1221 fPayment
= (fPv
+ fFv
) / fNper
;
1224 if (fPaytype
> 0.0) // payment in advance
1225 fPayment
= (fFv
+ fPv
* exp( fNper
* ::rtl::math::log1p(fRate
) ) ) * fRate
/
1226 (::rtl::math::expm1( (fNper
+ 1) * ::rtl::math::log1p(fRate
) ) - fRate
);
1227 else // payment in arrear
1228 fPayment
= (fFv
+ fPv
* exp(fNper
* ::rtl::math::log1p(fRate
) ) ) * fRate
/
1229 ::rtl::math::expm1( fNper
* ::rtl::math::log1p(fRate
) );
1234 void ScInterpreter::ScRMZ()
1236 double nZins
, nZzr
, nBw
, nZw
= 0, nFlag
= 0;
1237 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1238 sal_uInt8 nParamCount
= GetByte();
1239 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
1241 if (nParamCount
== 5)
1242 nFlag
= GetDouble();
1243 if (nParamCount
>= 4)
1247 nZins
= GetDouble();
1248 PushDouble(ScGetRmz(nZins
, nZzr
, nBw
, nZw
, nFlag
));
1251 void ScInterpreter::ScZGZ()
1253 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1254 if ( MustHaveParamCount( GetByte(), 3 ) )
1256 double nZukunftswert
= GetDouble();
1257 double nGegenwartswert
= GetDouble();
1258 double nZeitraum
= GetDouble();
1259 PushDouble(pow(nZukunftswert
/ nGegenwartswert
, 1.0 / nZeitraum
) - 1.0);
1263 double ScInterpreter::ScGetZw(double fZins
, double fZzr
, double fRmz
,
1264 double fBw
, double fF
)
1268 fZw
= fBw
+ fRmz
* fZzr
;
1271 double fTerm
= pow(1.0 + fZins
, fZzr
);
1273 fZw
= fBw
* fTerm
+ fRmz
*(1.0 + fZins
)*(fTerm
- 1.0)/fZins
;
1275 fZw
= fBw
* fTerm
+ fRmz
*(fTerm
- 1.0)/fZins
;
1280 void ScInterpreter::ScZW()
1282 double nZins
, nZzr
, nRmz
, nBw
= 0, nFlag
= 0;
1283 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1284 sal_uInt8 nParamCount
= GetByte();
1285 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
1287 if (nParamCount
== 5)
1288 nFlag
= GetDouble();
1289 if (nParamCount
>= 4)
1293 nZins
= GetDouble();
1294 PushDouble(ScGetZw(nZins
, nZzr
, nRmz
, nBw
, nFlag
));
1297 void ScInterpreter::ScZZR()
1299 double nZins
, nRmz
, nBw
, nZw
= 0, nFlag
= 0;
1300 sal_uInt8 nParamCount
= GetByte();
1301 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
1303 if (nParamCount
== 5)
1304 nFlag
= GetDouble();
1305 if (nParamCount
>= 4)
1309 nZins
= GetDouble();
1311 PushDouble(-(nBw
+ nZw
)/nRmz
);
1312 else if (nFlag
> 0.0)
1313 PushDouble(log(-(nZins
*nZw
-nRmz
*(1.0+nZins
))/(nZins
*nBw
+nRmz
*(1.0+nZins
)))
1316 PushDouble(log(-(nZins
*nZw
-nRmz
)/(nZins
*nBw
+nRmz
))/log(1.0+nZins
));
1319 bool ScInterpreter::RateIteration( double fNper
, double fPayment
, double fPv
,
1320 double fFv
, double fPayType
, double & fGuess
)
1322 // See also #i15090#
1323 // Newton-Raphson method: x(i+1) = x(i) - f(x(i)) / f'(x(i))
1324 // This solution handles integer and non-integer values of Nper different.
1325 // If ODFF will constraint Nper to integer, the distinction of cases can be
1326 // removed; only the integer-part is needed then.
1327 bool bValid
= true, bFound
= false;
1328 double fX
, fXnew
, fTerm
, fTermDerivation
;
1329 double fGeoSeries
, fGeoSeriesDerivation
;
1330 const sal_uInt16 nIterationsMax
= 150;
1331 sal_uInt16 nCount
= 0;
1332 const double fEpsilonSmall
= 1.0E-14;
1333 // convert any fPayType situation to fPayType == zero situation
1334 fFv
= fFv
- fPayment
* fPayType
;
1335 fPv
= fPv
+ fPayment
* fPayType
;
1336 if (fNper
== ::rtl::math::round( fNper
, 0, rtl_math_RoundingMode_Corrected
))
1337 { // Nper is an integer value
1339 double fPowN
, fPowNminus1
; // for (1.0+fX)^Nper and (1.0+fX)^(Nper-1)
1340 while (!bFound
&& nCount
< nIterationsMax
)
1342 fPowNminus1
= pow( 1.0+fX
, fNper
-1.0);
1343 fPowN
= fPowNminus1
* (1.0+fX
);
1344 if (rtl::math::approxEqual( fabs(fX
), 0.0))
1347 fGeoSeriesDerivation
= fNper
* (fNper
-1.0)/2.0;
1351 fGeoSeries
= (fPowN
-1.0)/fX
;
1352 fGeoSeriesDerivation
= fNper
* fPowNminus1
/ fX
- fGeoSeries
/ fX
;
1354 fTerm
= fFv
+ fPv
*fPowN
+ fPayment
* fGeoSeries
;
1355 fTermDerivation
= fPv
* fNper
* fPowNminus1
+ fPayment
* fGeoSeriesDerivation
;
1356 if (fabs(fTerm
) < fEpsilonSmall
)
1357 bFound
= true; // will catch root which is at an extreme
1360 if (rtl::math::approxEqual( fabs(fTermDerivation
), 0.0))
1361 fXnew
= fX
+ 1.1 * SCdEpsilon
; // move away from zero slope
1363 fXnew
= fX
- fTerm
/ fTermDerivation
;
1365 // more accuracy not possible in oscillating cases
1366 bFound
= (fabs(fXnew
- fX
) < SCdEpsilon
);
1370 // Gnumeric returns roots < -1, Excel gives an error in that cases,
1371 // ODFF says nothing about it. Enable the statement, if you want Excel's
1373 //bValid =(fX >=-1.0);
1374 // Update 2013-06-17: Gnumeric (v1.12.2) doesn't return roots <= -1
1376 bValid
= (fX
> -1.0);
1379 { // Nper is not an integer value.
1380 fX
= (fGuess
< -1.0) ? -1.0 : fGuess
; // start with a valid fX
1381 while (bValid
&& !bFound
&& nCount
< nIterationsMax
)
1383 if (rtl::math::approxEqual( fabs(fX
), 0.0))
1386 fGeoSeriesDerivation
= fNper
* (fNper
-1.0)/2.0;
1390 fGeoSeries
= (pow( 1.0+fX
, fNper
) - 1.0) / fX
;
1391 fGeoSeriesDerivation
= fNper
* pow( 1.0+fX
, fNper
-1.0) / fX
- fGeoSeries
/ fX
;
1393 fTerm
= fFv
+ fPv
*pow(1.0 + fX
,fNper
)+ fPayment
* fGeoSeries
;
1394 fTermDerivation
= fPv
* fNper
* pow( 1.0+fX
, fNper
-1.0) + fPayment
* fGeoSeriesDerivation
;
1395 if (fabs(fTerm
) < fEpsilonSmall
)
1396 bFound
= true; // will catch root which is at an extreme
1399 if (rtl::math::approxEqual( fabs(fTermDerivation
), 0.0))
1400 fXnew
= fX
+ 1.1 * SCdEpsilon
; // move away from zero slope
1402 fXnew
= fX
- fTerm
/ fTermDerivation
;
1404 // more accuracy not possible in oscillating cases
1405 bFound
= (fabs(fXnew
- fX
) < SCdEpsilon
);
1407 bValid
= (fX
>= -1.0); // otherwise pow(1.0+fX,fNper) will fail
1411 fGuess
= fX
; // return approximate root
1412 return bValid
&& bFound
;
1415 // In Calc UI it is the function RATE(Nper;Pmt;Pv;Fv;Type;Guess)
1416 void ScInterpreter::ScZins()
1418 double fPv
, fPayment
, fNper
;
1419 // defaults for missing arguments, see ODFF spec
1420 double fFv
= 0, fPayType
= 0, fGuess
= 0.1, fOrigGuess
= 0.1;
1422 bool bDefaultGuess
= true;
1423 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1424 sal_uInt8 nParamCount
= GetByte();
1425 if ( !MustHaveParamCount( nParamCount
, 3, 6 ) )
1427 if (nParamCount
== 6)
1429 fOrigGuess
= fGuess
= GetDouble();
1430 bDefaultGuess
= false;
1432 if (nParamCount
>= 5)
1433 fPayType
= GetDouble();
1434 if (nParamCount
>= 4)
1437 fPayment
= GetDouble();
1438 fNper
= GetDouble();
1439 if (fNper
<= 0.0) // constraint from ODFF spec
1441 PushIllegalArgument();
1444 // other values for fPayType might be meaningful,
1445 // ODFF spec is not clear yet, enable statement if you want only 0 and 1
1446 //if (fPayType != 0.0) fPayType = 1.0;
1447 bValid
= RateIteration(fNper
, fPayment
, fPv
, fFv
, fPayType
, fGuess
);
1450 /* TODO: try also for specified guess values, not only default? As is,
1451 * a specified 0.1 guess may be error result but a default 0.1 guess
1452 * may succeed. On the other hand, using a different guess value than
1453 * the specified one may not be desired, even if that didn't match. */
1456 /* TODO: this is rather ugly, instead of looping over different
1457 * guess values and doing a Newton goal seek for each we could
1458 * first insert the values into the RATE equation to obtain a set
1459 * of y values and then do a bisecting goal seek, possibly using
1460 * different algorithms. */
1461 double fX
= fOrigGuess
;
1462 for (int nStep
= 2; nStep
<= 10 && !bValid
; ++nStep
)
1464 fGuess
= fX
* nStep
;
1465 bValid
= RateIteration( fNper
, fPayment
, fPv
, fFv
, fPayType
, fGuess
);
1468 fGuess
= fX
/ nStep
;
1469 bValid
= RateIteration( fNper
, fPayment
, fPv
, fFv
, fPayType
, fGuess
);
1474 SetError(errNoConvergence
);
1479 double ScInterpreter::ScGetZinsZ(double fZins
, double fZr
, double fZzr
, double fBw
,
1480 double fZw
, double fF
, double& fRmz
)
1482 fRmz
= ScGetRmz(fZins
, fZzr
, fBw
, fZw
, fF
); // fuer kapz auch bei fZr == 1
1484 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1495 fZinsZ
= ScGetZw(fZins
, fZr
-2.0, fRmz
, fBw
, 1.0) - fRmz
;
1497 fZinsZ
= ScGetZw(fZins
, fZr
-1.0, fRmz
, fBw
, 0.0);
1499 return fZinsZ
* fZins
;
1502 void ScInterpreter::ScZinsZ()
1504 double nZins
, nZr
, nZzr
, nBw
, nZw
= 0, nFlag
= 0;
1505 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1506 sal_uInt8 nParamCount
= GetByte();
1507 if ( !MustHaveParamCount( nParamCount
, 4, 6 ) )
1509 if (nParamCount
== 6)
1510 nFlag
= GetDouble();
1511 if (nParamCount
>= 5)
1516 nZins
= GetDouble();
1517 if (nZr
< 1.0 || nZr
> nZzr
)
1518 PushIllegalArgument();
1522 PushDouble(ScGetZinsZ(nZins
, nZr
, nZzr
, nBw
, nZw
, nFlag
, nRmz
));
1526 void ScInterpreter::ScKapz()
1528 double nZins
, nZr
, nZzr
, nBw
, nZw
= 0, nFlag
= 0;
1529 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1530 sal_uInt8 nParamCount
= GetByte();
1531 if ( !MustHaveParamCount( nParamCount
, 4, 6 ) )
1533 if (nParamCount
== 6)
1534 nFlag
= GetDouble();
1535 if (nParamCount
>= 5)
1540 nZins
= GetDouble();
1541 if (nZr
< 1.0 || nZr
> nZzr
)
1542 PushIllegalArgument();
1546 double nZinsz
= ScGetZinsZ(nZins
, nZr
, nZzr
, nBw
, nZw
, nFlag
, nRmz
);
1547 PushDouble(nRmz
- nZinsz
);
1551 void ScInterpreter::ScKumZinsZ()
1553 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1554 if ( MustHaveParamCount( GetByte(), 6 ) )
1556 double fZins
, fZzr
, fBw
, fAnfang
, fEnde
, fF
;
1558 fEnde
= ::rtl::math::approxFloor(GetDouble());
1559 fAnfang
= ::rtl::math::approxFloor(GetDouble());
1562 fZins
= GetDouble();
1563 if (fAnfang
< 1.0 || fEnde
< fAnfang
|| fZins
<= 0.0 ||
1564 fEnde
> fZzr
|| fZzr
<= 0.0 || fBw
<= 0.0)
1565 PushIllegalArgument();
1568 sal_uLong nAnfang
= (sal_uLong
) fAnfang
;
1569 sal_uLong nEnde
= (sal_uLong
) fEnde
;
1570 double fRmz
= ScGetRmz(fZins
, fZzr
, fBw
, 0.0, fF
);
1571 double fZinsZ
= 0.0;
1578 for (sal_uLong i
= nAnfang
; i
<= nEnde
; i
++)
1581 fZinsZ
+= ScGetZw(fZins
, (double)(i
-2), fRmz
, fBw
, 1.0) - fRmz
;
1583 fZinsZ
+= ScGetZw(fZins
, (double)(i
-1), fRmz
, fBw
, 0.0);
1591 void ScInterpreter::ScKumKapZ()
1593 nFuncFmtType
= NUMBERFORMAT_CURRENCY
;
1594 if ( MustHaveParamCount( GetByte(), 6 ) )
1596 double fZins
, fZzr
, fBw
, fAnfang
, fEnde
, fF
;
1598 fEnde
= ::rtl::math::approxFloor(GetDouble());
1599 fAnfang
= ::rtl::math::approxFloor(GetDouble());
1602 fZins
= GetDouble();
1603 if (fAnfang
< 1.0 || fEnde
< fAnfang
|| fZins
<= 0.0 ||
1604 fEnde
> fZzr
|| fZzr
<= 0.0 || fBw
<= 0.0)
1605 PushIllegalArgument();
1608 double fRmz
= ScGetRmz(fZins
, fZzr
, fBw
, 0.0, fF
);
1610 sal_uLong nAnfang
= (sal_uLong
) fAnfang
;
1611 sal_uLong nEnde
= (sal_uLong
) fEnde
;
1615 fKapZ
= fRmz
+ fBw
* fZins
;
1620 for (sal_uLong i
= nAnfang
; i
<= nEnde
; i
++)
1623 fKapZ
+= fRmz
- (ScGetZw(fZins
, (double)(i
-2), fRmz
, fBw
, 1.0) - fRmz
) * fZins
;
1625 fKapZ
+= fRmz
- ScGetZw(fZins
, (double)(i
-1), fRmz
, fBw
, 0.0) * fZins
;
1632 void ScInterpreter::ScEffektiv()
1634 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1635 if ( MustHaveParamCount( GetByte(), 2 ) )
1637 double fPerioden
= GetDouble();
1638 double fNominal
= GetDouble();
1639 if (fPerioden
< 1.0 || fNominal
<= 0.0)
1640 PushIllegalArgument();
1643 fPerioden
= ::rtl::math::approxFloor(fPerioden
);
1644 PushDouble(pow(1.0 + fNominal
/fPerioden
, fPerioden
) - 1.0);
1649 void ScInterpreter::ScNominal()
1651 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1652 if ( MustHaveParamCount( GetByte(), 2 ) )
1654 double fPerioden
= GetDouble();
1655 double fEffektiv
= GetDouble();
1656 if (fPerioden
< 1.0 || fEffektiv
<= 0.0)
1657 PushIllegalArgument();
1660 fPerioden
= ::rtl::math::approxFloor(fPerioden
);
1661 PushDouble( (pow(fEffektiv
+ 1.0, 1.0 / fPerioden
) - 1.0) * fPerioden
);
1666 void ScInterpreter::ScMod()
1668 if ( MustHaveParamCount( GetByte(), 2 ) )
1670 double fVal2
= GetDouble(); // Denominator
1671 double fVal1
= GetDouble(); // Numerator
1672 if (fVal2
== floor(fVal2
)) // a pure integral number stored in double
1674 double fResult
= fmod(fVal1
,fVal2
);
1675 if ( (fResult
!= 0.0) &&
1676 ((fVal1
> 0.0 && fVal2
< 0.0) || (fVal1
< 0.0 && fVal2
> 0.0)))
1678 PushDouble( fResult
);
1682 PushDouble( ::rtl::math::approxSub( fVal1
,
1683 ::rtl::math::approxFloor(fVal1
/ fVal2
) * fVal2
));
1688 void ScInterpreter::ScIntersect()
1690 formula::FormulaTokenRef p2nd
= PopToken();
1691 formula::FormulaTokenRef p1st
= PopToken();
1693 if (nGlobalError
|| !p2nd
|| !p1st
)
1695 PushIllegalArgument();
1699 StackVar sv1
= p1st
->GetType();
1700 StackVar sv2
= p2nd
->GetType();
1701 if ((sv1
!= svSingleRef
&& sv1
!= svDoubleRef
&& sv1
!= svRefList
) ||
1702 (sv2
!= svSingleRef
&& sv2
!= svDoubleRef
&& sv2
!= svRefList
))
1704 PushIllegalArgument();
1708 ScToken
* x1
= static_cast<ScToken
*>(p1st
.get());
1709 ScToken
* x2
= static_cast<ScToken
*>(p2nd
.get());
1710 if (sv1
== svRefList
|| sv2
== svRefList
)
1712 // Now this is a bit nasty but it simplifies things, and having
1713 // intersections with lists isn't too common, if at all..
1714 // Convert a reference to list.
1715 ScToken
* xt
[2] = { x1
, x2
};
1716 StackVar sv
[2] = { sv1
, sv2
};
1717 for (size_t i
=0; i
<2; ++i
)
1719 if (sv
[i
] == svSingleRef
)
1721 ScComplexRefData aRef
;
1722 aRef
.Ref1
= aRef
.Ref2
= xt
[i
]->GetSingleRef();
1723 xt
[i
] = new ScRefListToken
;
1724 xt
[i
]->GetRefList()->push_back( aRef
);
1726 else if (sv
[i
] == svDoubleRef
)
1728 ScComplexRefData aRef
= xt
[i
]->GetDoubleRef();
1729 xt
[i
] = new ScRefListToken
;
1730 xt
[i
]->GetRefList()->push_back( aRef
);
1733 x1
= xt
[0], x2
= xt
[1];
1735 ScTokenRef xRes
= new ScRefListToken
;
1736 ScRefList
* pRefList
= xRes
->GetRefList();
1737 ScRefList::const_iterator
end1( x1
->GetRefList()->end());
1738 ScRefList::const_iterator
end2( x2
->GetRefList()->end());
1739 for (ScRefList::const_iterator
it1( x1
->GetRefList()->begin());
1742 const ScAddress
& r11
= (*it1
).Ref1
.toAbs(aPos
);
1743 const ScAddress
& r12
= (*it1
).Ref2
.toAbs(aPos
);
1744 for (ScRefList::const_iterator
it2( x2
->GetRefList()->begin());
1747 const ScAddress
& r21
= (*it2
).Ref1
.toAbs(aPos
);
1748 const ScAddress
& r22
= (*it2
).Ref2
.toAbs(aPos
);
1749 SCCOL nCol1
= ::std::max( r11
.Col(), r21
.Col());
1750 SCROW nRow1
= ::std::max( r11
.Row(), r21
.Row());
1751 SCTAB nTab1
= ::std::max( r11
.Tab(), r21
.Tab());
1752 SCCOL nCol2
= ::std::min( r12
.Col(), r22
.Col());
1753 SCROW nRow2
= ::std::min( r12
.Row(), r22
.Row());
1754 SCTAB nTab2
= ::std::min( r12
.Tab(), r22
.Tab());
1755 if (nCol2
< nCol1
|| nRow2
< nRow1
|| nTab2
< nTab1
)
1759 ScComplexRefData aRef
;
1760 aRef
.InitRange( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
1761 pRefList
->push_back( aRef
);
1765 size_t n
= pRefList
->size();
1767 PushError( errNoRef
);
1770 const ScComplexRefData
& rRef
= (*pRefList
)[0];
1771 if (rRef
.Ref1
== rRef
.Ref2
)
1772 PushTempToken( new ScSingleRefToken( rRef
.Ref1
));
1774 PushTempToken( new ScDoubleRefToken( rRef
));
1777 PushTempToken( xRes
.get());
1781 ScToken
* pt
[2] = { x1
, x2
};
1782 StackVar sv
[2] = { sv1
, sv2
};
1783 SCCOL nC1
[2], nC2
[2];
1784 SCROW nR1
[2], nR2
[2];
1785 SCTAB nT1
[2], nT2
[2];
1786 for (size_t i
=0; i
<2; ++i
)
1794 const ScAddress
& r
= pt
[i
]->GetSingleRef().toAbs(aPos
);
1799 if (sv
[i
] == svDoubleRef
)
1801 const ScAddress
& r
= pt
[i
]->GetSingleRef2().toAbs(aPos
);
1815 ; // nothing, prevent compiler warning
1818 SCCOL nCol1
= ::std::max( nC1
[0], nC1
[1]);
1819 SCROW nRow1
= ::std::max( nR1
[0], nR1
[1]);
1820 SCTAB nTab1
= ::std::max( nT1
[0], nT1
[1]);
1821 SCCOL nCol2
= ::std::min( nC2
[0], nC2
[1]);
1822 SCROW nRow2
= ::std::min( nR2
[0], nR2
[1]);
1823 SCTAB nTab2
= ::std::min( nT2
[0], nT2
[1]);
1824 if (nCol2
< nCol1
|| nRow2
< nRow1
|| nTab2
< nTab1
)
1825 PushError( errNoRef
);
1826 else if (nCol2
== nCol1
&& nRow2
== nRow1
&& nTab2
== nTab1
)
1827 PushSingleRef( nCol1
, nRow1
, nTab1
);
1829 PushDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
1833 void ScInterpreter::ScRangeFunc()
1835 formula::FormulaTokenRef x2
= PopToken();
1836 formula::FormulaTokenRef x1
= PopToken();
1838 if (nGlobalError
|| !x2
|| !x1
)
1840 PushIllegalArgument();
1843 FormulaTokenRef xRes
= ScToken::ExtendRangeReference( *x1
, *x2
, aPos
, false);
1845 PushIllegalArgument();
1847 PushTempToken( xRes
.get());
1850 void ScInterpreter::ScUnionFunc()
1852 formula::FormulaTokenRef p2nd
= PopToken();
1853 formula::FormulaTokenRef p1st
= PopToken();
1855 if (nGlobalError
|| !p2nd
|| !p1st
)
1857 PushIllegalArgument();
1861 StackVar sv1
= p1st
->GetType();
1862 StackVar sv2
= p2nd
->GetType();
1863 if ((sv1
!= svSingleRef
&& sv1
!= svDoubleRef
&& sv1
!= svRefList
) ||
1864 (sv2
!= svSingleRef
&& sv2
!= svDoubleRef
&& sv2
!= svRefList
))
1866 PushIllegalArgument();
1870 ScToken
* x1
= static_cast<ScToken
*>(p1st
.get());
1871 ScToken
* x2
= static_cast<ScToken
*>(p2nd
.get());
1874 // Append to an existing RefList if there is one.
1875 if (sv1
== svRefList
)
1878 sv1
= svUnknown
; // mark as handled
1880 else if (sv2
== svRefList
)
1883 sv2
= svUnknown
; // mark as handled
1886 xRes
= new ScRefListToken
;
1887 ScRefList
* pRes
= xRes
->GetRefList();
1888 ScToken
* pt
[2] = { x1
, x2
};
1889 StackVar sv
[2] = { sv1
, sv2
};
1890 for (size_t i
=0; i
<2; ++i
)
1898 ScComplexRefData aRef
;
1899 aRef
.Ref1
= aRef
.Ref2
= pt
[i
]->GetSingleRef();
1900 pRes
->push_back( aRef
);
1904 pRes
->push_back( pt
[i
]->GetDoubleRef());
1908 const ScRefList
* p
= pt
[i
]->GetRefList();
1909 ScRefList::const_iterator
it( p
->begin());
1910 ScRefList::const_iterator
end( p
->end());
1911 for ( ; it
!= end
; ++it
)
1913 pRes
->push_back( *it
);
1918 ; // nothing, prevent compiler warning
1921 ValidateRef( *pRes
); // set #REF! if needed
1922 PushTempToken( xRes
.get());
1925 void ScInterpreter::ScCurrent()
1927 FormulaTokenRef
xTok( PopToken());
1930 PushTempToken( xTok
.get());
1931 PushTempToken( xTok
.get());
1934 PushError( errUnknownStackVariable
);
1937 void ScInterpreter::ScStyle()
1939 sal_uInt8 nParamCount
= GetByte();
1940 if (nParamCount
>= 1 && nParamCount
<= 3)
1942 OUString aStyle2
; // Vorlage nach Timer
1943 if (nParamCount
>= 3)
1944 aStyle2
= GetString().getString();
1945 long nTimeOut
= 0; // Timeout
1946 if (nParamCount
>= 2)
1947 nTimeOut
= (long)(GetDouble()*1000.0);
1948 OUString aStyle1
= GetString().getString(); // Vorlage fuer sofort
1954 // Request ausfuehren, um Vorlage anzuwenden
1957 if ( !pDok
->IsClipOrUndo() )
1959 SfxObjectShell
* pShell
= pDok
->GetDocumentShell();
1962 //! notify object shell directly
1964 ScRange
aRange(aPos
);
1965 ScAutoStyleHint
aHint( aRange
, aStyle1
, nTimeOut
, aStyle2
);
1966 pShell
->Broadcast( aHint
);
1973 PushIllegalParameter();
1976 static ScDdeLink
* lcl_GetDdeLink( sfx2::LinkManager
* pLinkMgr
,
1977 const OUString
& rA
, const OUString
& rT
, const OUString
& rI
, sal_uInt8 nM
)
1979 size_t nCount
= pLinkMgr
->GetLinks().size();
1980 for (size_t i
=0; i
<nCount
; i
++ )
1982 ::sfx2::SvBaseLink
* pBase
= *pLinkMgr
->GetLinks()[i
];
1983 if (pBase
->ISA(ScDdeLink
))
1985 ScDdeLink
* pLink
= static_cast<ScDdeLink
*>(pBase
);
1986 if ( pLink
->GetAppl() == rA
&&
1987 pLink
->GetTopic() == rT
&&
1988 pLink
->GetItem() == rI
&&
1989 pLink
->GetMode() == nM
)
1997 void ScInterpreter::ScDde()
1999 // Applikation, Datei, Bereich
2000 // Application, Topic, Item
2002 sal_uInt8 nParamCount
= GetByte();
2003 if ( MustHaveParamCount( nParamCount
, 3, 4 ) )
2005 sal_uInt8 nMode
= SC_DDE_DEFAULT
;
2006 if (nParamCount
== 4)
2007 nMode
= (sal_uInt8
) ::rtl::math::approxFloor(GetDouble());
2008 OUString aItem
= GetString().getString();
2009 OUString aTopic
= GetString().getString();
2010 OUString aAppl
= GetString().getString();
2012 if (nMode
> SC_DDE_TEXT
)
2013 nMode
= SC_DDE_DEFAULT
;
2015 // temporary documents (ScFunctionAccess) have no DocShell
2016 // and no LinkManager -> abort
2018 sfx2::LinkManager
* pLinkMgr
= pDok
->GetLinkManager();
2025 // Nach dem Laden muss neu interpretiert werden (Verknuepfungen aufbauen)
2027 if ( rArr
.IsRecalcModeNormal() )
2028 rArr
.SetExclusiveRecalcModeOnLoad();
2030 // solange der Link nicht ausgewertet ist, Idle abklemmen
2031 // (um zirkulaere Referenzen zu vermeiden)
2033 bool bOldEnabled
= pDok
->IsIdleEnabled();
2034 pDok
->EnableIdle(false);
2036 // Link-Objekt holen / anlegen
2038 ScDdeLink
* pLink
= lcl_GetDdeLink( pLinkMgr
, aAppl
, aTopic
, aItem
, nMode
);
2040 //! Dde-Links (zusaetzlich) effizienter am Dokument speichern !!!!!
2041 // ScDdeLink* pLink = pDok->GetDdeLink( aAppl, aTopic, aItem );
2043 bool bWasError
= ( pMyFormulaCell
&& pMyFormulaCell
->GetRawError() != 0 );
2047 pLink
= new ScDdeLink( pDok
, aAppl
, aTopic
, aItem
, nMode
);
2048 pLinkMgr
->InsertDDELink( pLink
, aAppl
, aTopic
, aItem
);
2049 if ( pLinkMgr
->GetLinks().size() == 1 ) // erster ?
2051 SfxBindings
* pBindings
= pDok
->GetViewBindings();
2053 pBindings
->Invalidate( SID_LINKS
); // Link-Manager enablen
2056 //! asynchron auswerten ???
2057 pLink
->TryUpdate(); // TryUpdate ruft Update nicht mehrfach auf
2061 // StartListening erst nach dem Update, sonst circular reference
2062 pMyFormulaCell
->StartListening( *pLink
);
2068 pMyFormulaCell
->StartListening( *pLink
);
2071 // Wenn aus dem Reschedule beim Ausfuehren des Links ein Fehler
2072 // (z.B. zirkulaere Referenz) entstanden ist, der vorher nicht da war,
2073 // das Fehler-Flag zuruecksetzen:
2075 if ( pMyFormulaCell
&& pMyFormulaCell
->GetRawError() && !bWasError
)
2076 pMyFormulaCell
->SetErrCode(0);
2080 const ScMatrix
* pLinkMat
= pLink
->GetResult();
2084 pLinkMat
->GetDimensions(nC
, nR
);
2085 ScMatrixRef pNewMat
= GetNewMat( nC
, nR
);
2088 pLinkMat
->MatCopy(*pNewMat
); // kopieren
2089 PushMatrix( pNewMat
);
2092 PushIllegalArgument();
2097 pDok
->EnableIdle(bOldEnabled
);
2098 pLinkMgr
->CloseCachedComps();
2102 void ScInterpreter::ScBase()
2103 { // Value, Base [, MinLen]
2104 sal_uInt8 nParamCount
= GetByte();
2105 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
2107 static const sal_Unicode pDigits
[] = {
2108 '0','1','2','3','4','5','6','7','8','9',
2109 'A','B','C','D','E','F','G','H','I','J','K','L','M',
2110 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
2113 static const int nDigits
= (sizeof (pDigits
)/sizeof(pDigits
[0]))-1;
2115 if ( nParamCount
== 3 )
2117 double fLen
= ::rtl::math::approxFloor( GetDouble() );
2118 if ( 1.0 <= fLen
&& fLen
< STRING_MAXLEN
)
2119 nMinLen
= (xub_StrLen
) fLen
;
2120 else if ( fLen
== 0.0 )
2123 nMinLen
= 0; // Error
2127 double fBase
= ::rtl::math::approxFloor( GetDouble() );
2128 double fVal
= ::rtl::math::approxFloor( GetDouble() );
2129 double fChars
= ((fVal
> 0.0 && fBase
> 0.0) ?
2130 (ceil( log( fVal
) / log( fBase
) ) + 2.0) :
2132 if ( fChars
>= STRING_MAXLEN
)
2133 nMinLen
= 0; // Error
2135 if ( !nGlobalError
&& nMinLen
&& 2 <= fBase
&& fBase
<= nDigits
&& 0 <= fVal
)
2137 const xub_StrLen nConstBuf
= 128;
2138 sal_Unicode aBuf
[nConstBuf
];
2139 sal_Int32 nBuf
= std::max
<sal_Int32
>( fChars
, nMinLen
+ 1 );
2140 sal_Unicode
* pBuf
= (nBuf
<= nConstBuf
? aBuf
: new sal_Unicode
[nBuf
]);
2141 for ( sal_Int32 j
= 0; j
< nBuf
; ++j
)
2145 sal_Unicode
* p
= pBuf
+ nBuf
- 1;
2147 if ( fVal
<= (sal_uLong
)(~0) )
2149 sal_uLong nVal
= (sal_uLong
) fVal
;
2150 sal_uLong nBase
= (sal_uLong
) fBase
;
2151 while ( nVal
&& p
> pBuf
)
2153 *--p
= pDigits
[ nVal
% nBase
];
2156 fVal
= (double) nVal
;
2161 while ( fVal
&& p
> pBuf
)
2163 //! mit fmod Rundungsfehler ab 2**48
2164 // double fDig = ::rtl::math::approxFloor( fmod( fVal, fBase ) );
2165 // so ist es etwas besser
2166 double fInt
= ::rtl::math::approxFloor( fVal
/ fBase
);
2167 double fMult
= fInt
* fBase
;
2168 #if OSL_DEBUG_LEVEL > 1
2169 // =BASIS(1e308;36) => GPF mit
2170 // nDig = (size_t) ::rtl::math::approxFloor( fVal - fMult );
2171 // trotz vorheriger Pruefung ob fVal >= fMult
2172 double fDebug1
= fVal
- fMult
;
2173 // fVal := 7,5975311883090e+290
2174 // fMult := 7,5975311883090e+290
2175 // fDebug1 := 1,3848924157003e+275 <- RoundOff-Error
2176 // fVal != fMult, aber: ::rtl::math::approxEqual( fVal, fMult ) == TRUE
2177 double fDebug2
= ::rtl::math::approxSub( fVal
, fMult
);
2178 // und ::rtl::math::approxSub( fVal, fMult ) == 0
2179 double fDebug3
= ( fInt
? fVal
/ fInt
: 0.0 );
2180 // Nach dem strange fDebug1 und fVal < fMult ist eigentlich
2181 // fDebug2 == fBase, trotzdem wird das mit einem Vergleich
2182 // nicht erkannt, dann schlaegt bDirt zu und alles wird wieder gut..
2184 // prevent compiler warnings
2185 (void)fDebug1
; (void)fDebug2
; (void)fDebug3
;
2189 { // da ist was gekippt
2195 double fDig
= ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal
, fMult
) );
2203 else if ( fDig
>= fBase
)
2204 nDig
= ((size_t) fBase
) - 1;
2206 nDig
= (size_t) fDig
;
2208 *--p
= pDigits
[ nDig
];
2213 PushError( errStringOverflow
);
2216 if ( nBuf
- (p
- pBuf
) <= nMinLen
)
2217 p
= pBuf
+ nBuf
- 1 - nMinLen
;
2218 PushStringBuffer( p
);
2224 PushIllegalArgument();
2228 void ScInterpreter::ScDecimal()
2230 if ( MustHaveParamCount( GetByte(), 2 ) )
2232 double fBase
= ::rtl::math::approxFloor( GetDouble() );
2233 OUString aStr
= GetString().getString();
2234 if ( !nGlobalError
&& 2 <= fBase
&& fBase
<= 36 )
2237 int nBase
= (int) fBase
;
2238 const sal_Unicode
* p
= aStr
.getStr();
2239 while ( *p
== ' ' || *p
== '\t' )
2240 p
++; // strip leading white space
2242 { // evtl. hex-prefix strippen
2243 if ( *p
== 'x' || *p
== 'X' )
2245 else if ( *p
== '0' && (*(p
+1) == 'x' || *(p
+1) == 'X') )
2251 if ( '0' <= *p
&& *p
<= '9' )
2253 else if ( 'A' <= *p
&& *p
<= 'Z' )
2254 n
= 10 + (*p
- 'A');
2255 else if ( 'a' <= *p
&& *p
<= 'z' )
2256 n
= 10 + (*p
- 'a');
2262 ( (nBase
== 2 && (*p
== 'b' || *p
== 'B'))
2263 ||(nBase
== 16 && (*p
== 'h' || *p
== 'H')) )
2265 ; // 101b und F00Dh sind ok
2268 PushIllegalArgument();
2273 fVal
= fVal
* fBase
+ n
;
2280 PushIllegalArgument();
2284 void ScInterpreter::ScConvert()
2285 { // Value, FromUnit, ToUnit
2286 if ( MustHaveParamCount( GetByte(), 3 ) )
2288 OUString aToUnit
= GetString().getString();
2289 OUString aFromUnit
= GetString().getString();
2290 double fVal
= GetDouble();
2292 PushError( nGlobalError
);
2294 { // erst die angegebene Reihenfolge suchen, wenn nicht gefunden den Kehrwert
2296 if ( ScGlobal::GetUnitConverter()->GetValue( fConv
, aFromUnit
, aToUnit
) )
2297 PushDouble( fVal
* fConv
);
2298 else if ( ScGlobal::GetUnitConverter()->GetValue( fConv
, aToUnit
, aFromUnit
) )
2299 PushDouble( fVal
/ fConv
);
2306 void ScInterpreter::ScRoman()
2308 sal_uInt8 nParamCount
= GetByte();
2309 if( MustHaveParamCount( nParamCount
, 1, 2 ) )
2311 double fMode
= (nParamCount
== 2) ? ::rtl::math::approxFloor( GetDouble() ) : 0.0;
2312 double fVal
= ::rtl::math::approxFloor( GetDouble() );
2314 PushError( nGlobalError
);
2315 else if( (fMode
>= 0.0) && (fMode
< 5.0) && (fVal
>= 0.0) && (fVal
< 4000.0) )
2317 static const sal_Unicode pChars
[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
2318 static const sal_uInt16 pValues
[] = { 1000, 500, 100, 50, 10, 5, 1 };
2319 static const sal_uInt16 nMaxIndex
= (sal_uInt16
)((sizeof(pValues
)/sizeof(pValues
[0])) - 1);
2322 sal_uInt16 nVal
= (sal_uInt16
) fVal
;
2323 sal_uInt16 nMode
= (sal_uInt16
) fMode
;
2325 for( sal_uInt16 i
= 0; i
<= nMaxIndex
/ 2; i
++ )
2327 sal_uInt16 nIndex
= 2 * i
;
2328 sal_uInt16 nDigit
= nVal
/ pValues
[ nIndex
];
2330 if( (nDigit
% 5) == 4 )
2332 // assert can't happen with nVal<4000 precondition
2333 assert( ((nDigit
== 4) ? (nIndex
>= 1) : (nIndex
>= 2)));
2335 sal_uInt16 nIndex2
= (nDigit
== 4) ? nIndex
- 1 : nIndex
- 2;
2336 sal_uInt16 nSteps
= 0;
2337 while( (nSteps
< nMode
) && (nIndex
< nMaxIndex
) )
2340 if( pValues
[ nIndex2
] - pValues
[ nIndex
+ 1 ] <= nVal
)
2345 aRoman
+= OUString( pChars
[ nIndex
] );
2346 aRoman
+= OUString( pChars
[ nIndex2
] );
2347 nVal
= sal::static_int_cast
<sal_uInt16
>( nVal
+ pValues
[ nIndex
] );
2348 nVal
= sal::static_int_cast
<sal_uInt16
>( nVal
- pValues
[ nIndex2
] );
2354 // assert can't happen with nVal<4000 precondition
2355 assert( nIndex
>= 1 );
2356 aRoman
+= OUString( pChars
[ nIndex
- 1 ] );
2358 sal_Int32 nPad
= nDigit
% 5;
2361 OUStringBuffer
aBuf(aRoman
);
2362 comphelper::string::padToLength(aBuf
, aBuf
.getLength() + nPad
,
2364 aRoman
= aBuf
.makeStringAndClear();
2366 nVal
%= pValues
[ nIndex
];
2370 PushString( aRoman
);
2373 PushIllegalArgument();
2377 static bool lcl_GetArabicValue( sal_Unicode cChar
, sal_uInt16
& rnValue
, bool& rbIsDec
)
2381 case 'M': rnValue
= 1000; rbIsDec
= true; break;
2382 case 'D': rnValue
= 500; rbIsDec
= false; break;
2383 case 'C': rnValue
= 100; rbIsDec
= true; break;
2384 case 'L': rnValue
= 50; rbIsDec
= false; break;
2385 case 'X': rnValue
= 10; rbIsDec
= true; break;
2386 case 'V': rnValue
= 5; rbIsDec
= false; break;
2387 case 'I': rnValue
= 1; rbIsDec
= true; break;
2388 default: return false;
2393 void ScInterpreter::ScArabic()
2395 OUString aRoman
= GetString().getString();
2397 PushError( nGlobalError
);
2400 aRoman
= aRoman
.toAsciiUpperCase();
2402 sal_uInt16 nValue
= 0;
2403 sal_uInt16 nValidRest
= 3999;
2404 sal_Int32 nCharIndex
= 0;
2405 sal_Int32 nCharCount
= aRoman
.getLength();
2408 while( bValid
&& (nCharIndex
< nCharCount
) )
2410 sal_uInt16 nDigit1
= 0;
2411 sal_uInt16 nDigit2
= 0;
2412 bool bIsDec1
= false;
2413 bValid
= lcl_GetArabicValue( aRoman
[nCharIndex
], nDigit1
, bIsDec1
);
2414 if( bValid
&& (nCharIndex
+ 1 < nCharCount
) )
2416 bool bIsDec2
= false;
2417 bValid
= lcl_GetArabicValue( aRoman
[nCharIndex
+ 1], nDigit2
, bIsDec2
);
2421 if( nDigit1
>= nDigit2
)
2423 nValue
= sal::static_int_cast
<sal_uInt16
>( nValue
+ nDigit1
);
2424 nValidRest
%= (nDigit1
* (bIsDec1
? 5 : 2));
2425 bValid
= (nValidRest
>= nDigit1
);
2427 nValidRest
= sal::static_int_cast
<sal_uInt16
>( nValidRest
- nDigit1
);
2430 else if( nDigit1
* 2 != nDigit2
)
2432 sal_uInt16 nDiff
= nDigit2
- nDigit1
;
2433 nValue
= sal::static_int_cast
<sal_uInt16
>( nValue
+ nDiff
);
2434 bValid
= (nValidRest
>= nDiff
);
2436 nValidRest
= nDigit1
- 1;
2446 PushIllegalArgument();
2450 void ScInterpreter::ScHyperLink()
2452 sal_uInt8 nParamCount
= GetByte();
2453 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
2456 svl::SharedString aStr
;
2457 ScMatValType nResultType
= SC_MATVAL_STRING
;
2459 if ( nParamCount
== 2 )
2461 switch ( GetStackType() )
2465 nResultType
= SC_MATVAL_VALUE
;
2474 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2477 ScRefCellValue aCell
;
2478 aCell
.assign(*pDok
, aAdr
);
2479 if (aCell
.hasEmptyValue())
2480 nResultType
= SC_MATVAL_EMPTY
;
2483 sal_uInt16 nErr
= GetCellErrCode(aCell
);
2486 else if (aCell
.hasNumeric())
2488 fVal
= GetCellValue(aAdr
, aCell
);
2489 nResultType
= SC_MATVAL_VALUE
;
2492 GetCellString(aStr
, aCell
);
2497 nResultType
= GetDoubleOrStringFromMatrix( fVal
, aStr
);
2504 nResultType
= SC_MATVAL_VALUE
;
2508 SetError( errIllegalArgument
);
2511 svl::SharedString aUrl
= GetString();
2512 ScMatrixRef pResMat
= GetNewMat( 1, 2);
2515 fVal
= CreateDoubleError( nGlobalError
);
2516 nResultType
= SC_MATVAL_VALUE
;
2518 if (nParamCount
== 2 || nGlobalError
)
2520 if (ScMatrix::IsValueType( nResultType
))
2521 pResMat
->PutDouble( fVal
, 0);
2522 else if (ScMatrix::IsRealStringType( nResultType
))
2523 pResMat
->PutString(aStr
, 0);
2524 else // EmptyType, EmptyPathType, mimic xcl
2525 pResMat
->PutDouble( 0.0, 0 );
2528 pResMat
->PutString(aUrl
, 0);
2529 pResMat
->PutString(aUrl
, 1);
2530 bMatrixFormula
= true;
2531 PushMatrix(pResMat
);
2535 /** Resources at the website of the European Commission:
2536 http://ec.europa.eu/economy_finance/euro/adoption/conversion/
2537 http://ec.europa.eu/economy_finance/euro/countries/
2539 static bool lclConvertMoney( const OUString
& aSearchUnit
, double& rfRate
, int& rnDec
)
2543 const sal_Char
* pCurrText
;
2547 ConvertInfo aConvertTable
[] = {
2549 { "ATS", 13.7603, 2 },
2550 { "BEF", 40.3399, 0 },
2551 { "DEM", 1.95583, 2 },
2552 { "ESP", 166.386, 0 },
2553 { "FIM", 5.94573, 2 },
2554 { "FRF", 6.55957, 2 },
2555 { "IEP", 0.787564, 2 },
2556 { "ITL", 1936.27, 0 },
2557 { "LUF", 40.3399, 0 },
2558 { "NLG", 2.20371, 2 },
2559 { "PTE", 200.482, 2 },
2560 { "GRD", 340.750, 2 },
2561 { "SIT", 239.640, 2 },
2562 { "MTL", 0.429300, 2 },
2563 { "CYP", 0.585274, 2 },
2564 { "SKK", 30.1260, 2 },
2565 { "EEK", 15.6466, 2 },
2566 { "LVL", 0.702804, 2 }
2569 const size_t nConversionCount
= sizeof( aConvertTable
) / sizeof( aConvertTable
[0] );
2570 for ( size_t i
= 0; i
< nConversionCount
; ++i
)
2571 if ( aSearchUnit
.equalsIgnoreAsciiCaseAscii( aConvertTable
[i
].pCurrText
) )
2573 rfRate
= aConvertTable
[i
].fRate
;
2574 rnDec
= aConvertTable
[i
].nDec
;
2580 void ScInterpreter::ScEuroConvert()
2581 { //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]]
2582 sal_uInt8 nParamCount
= GetByte();
2583 if ( MustHaveParamCount( nParamCount
, 3, 5 ) )
2585 double nPrecision
= 0.0;
2586 if ( nParamCount
== 5 )
2588 nPrecision
= ::rtl::math::approxFloor(GetDouble());
2589 if ( nPrecision
< 3 )
2591 PushIllegalArgument();
2595 bool bFullPrecision
= false;
2596 if ( nParamCount
>= 4 )
2597 bFullPrecision
= GetBool();
2598 OUString aToUnit
= GetString().getString();
2599 OUString aFromUnit
= GetString().getString();
2600 double fVal
= GetDouble();
2602 PushError( nGlobalError
);
2609 OUString
aEur( "EUR");
2610 if ( lclConvertMoney( aFromUnit
, fFromRate
, nFromDec
)
2611 && lclConvertMoney( aToUnit
, fToRate
, nToDec
) )
2614 if ( aFromUnit
.equalsIgnoreAsciiCase( aToUnit
) )
2618 if ( aFromUnit
.equalsIgnoreAsciiCase( aEur
) )
2619 fRes
= fVal
* fToRate
;
2622 double fIntermediate
= fVal
/ fFromRate
;
2624 fIntermediate
= ::rtl::math::round( fIntermediate
,
2626 fRes
= fIntermediate
* fToRate
;
2628 if ( !bFullPrecision
)
2629 fRes
= ::rtl::math::round( fRes
, nToDec
);
2634 PushIllegalArgument();
2640 #define UTF8_TH_0 "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214"
2641 #define UTF8_TH_1 "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207"
2642 #define UTF8_TH_2 "\340\270\252\340\270\255\340\270\207"
2643 #define UTF8_TH_3 "\340\270\252\340\270\262\340\270\241"
2644 #define UTF8_TH_4 "\340\270\252\340\270\265\340\271\210"
2645 #define UTF8_TH_5 "\340\270\253\340\271\211\340\270\262"
2646 #define UTF8_TH_6 "\340\270\253\340\270\201"
2647 #define UTF8_TH_7 "\340\271\200\340\270\210\340\271\207\340\270\224"
2648 #define UTF8_TH_8 "\340\271\201\340\270\233\340\270\224"
2649 #define UTF8_TH_9 "\340\271\200\340\270\201\340\271\211\340\270\262"
2650 #define UTF8_TH_10 "\340\270\252\340\270\264\340\270\232"
2651 #define UTF8_TH_11 "\340\271\200\340\270\255\340\271\207\340\270\224"
2652 #define UTF8_TH_20 "\340\270\242\340\270\265\340\271\210"
2653 #define UTF8_TH_1E2 "\340\270\243\340\271\211\340\270\255\340\270\242"
2654 #define UTF8_TH_1E3 "\340\270\236\340\270\261\340\270\231"
2655 #define UTF8_TH_1E4 "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231"
2656 #define UTF8_TH_1E5 "\340\271\201\340\270\252\340\270\231"
2657 #define UTF8_TH_1E6 "\340\270\245\340\271\211\340\270\262\340\270\231"
2658 #define UTF8_TH_DOT0 "\340\270\226\340\271\211\340\270\247\340\270\231"
2659 #define UTF8_TH_BAHT "\340\270\232\340\270\262\340\270\227"
2660 #define UTF8_TH_SATANG "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214"
2661 #define UTF8_TH_MINUS "\340\270\245\340\270\232"
2666 inline void lclSplitBlock( double& rfInt
, sal_Int32
& rnBlock
, double fValue
, double fSize
)
2668 rnBlock
= static_cast< sal_Int32
>( modf( (fValue
+ 0.1) / fSize
, &rfInt
) * fSize
+ 0.1 );
2671 /** Appends a digit (0 to 9) to the passed string. */
2672 void lclAppendDigit( OStringBuffer
& rText
, sal_Int32 nDigit
)
2676 case 0: rText
.append( UTF8_TH_0
); break;
2677 case 1: rText
.append( UTF8_TH_1
); break;
2678 case 2: rText
.append( UTF8_TH_2
); break;
2679 case 3: rText
.append( UTF8_TH_3
); break;
2680 case 4: rText
.append( UTF8_TH_4
); break;
2681 case 5: rText
.append( UTF8_TH_5
); break;
2682 case 6: rText
.append( UTF8_TH_6
); break;
2683 case 7: rText
.append( UTF8_TH_7
); break;
2684 case 8: rText
.append( UTF8_TH_8
); break;
2685 case 9: rText
.append( UTF8_TH_9
); break;
2686 default: OSL_FAIL( "lclAppendDigit - illegal digit" );
2690 /** Appends a value raised to a power of 10: nDigit*10^nPow10.
2691 @param nDigit A digit in the range from 1 to 9.
2692 @param nPow10 A value in the range from 2 to 5.
2694 void lclAppendPow10( OStringBuffer
& rText
, sal_Int32 nDigit
, sal_Int32 nPow10
)
2696 OSL_ENSURE( (1 <= nDigit
) && (nDigit
<= 9), "lclAppendPow10 - illegal digit" );
2697 lclAppendDigit( rText
, nDigit
);
2700 case 2: rText
.append( UTF8_TH_1E2
); break;
2701 case 3: rText
.append( UTF8_TH_1E3
); break;
2702 case 4: rText
.append( UTF8_TH_1E4
); break;
2703 case 5: rText
.append( UTF8_TH_1E5
); break;
2704 default: OSL_FAIL( "lclAppendPow10 - illegal power" );
2708 /** Appends a block of 6 digits (value from 1 to 999,999) to the passed string. */
2709 void lclAppendBlock( OStringBuffer
& rText
, sal_Int32 nValue
)
2711 OSL_ENSURE( (1 <= nValue
) && (nValue
<= 999999), "lclAppendBlock - illegal value" );
2712 if( nValue
>= 100000 )
2714 lclAppendPow10( rText
, nValue
/ 100000, 5 );
2717 if( nValue
>= 10000 )
2719 lclAppendPow10( rText
, nValue
/ 10000, 4 );
2722 if( nValue
>= 1000 )
2724 lclAppendPow10( rText
, nValue
/ 1000, 3 );
2729 lclAppendPow10( rText
, nValue
/ 100, 2 );
2734 sal_Int32 nTen
= nValue
/ 10;
2735 sal_Int32 nOne
= nValue
% 10;
2739 lclAppendDigit( rText
, nTen
);
2740 else if( nTen
== 2 )
2741 rText
.append( UTF8_TH_20
);
2742 rText
.append( UTF8_TH_10
);
2744 if( (nTen
> 0) && (nOne
== 1) )
2745 rText
.append( UTF8_TH_11
);
2747 lclAppendDigit( rText
, nOne
);
2753 void ScInterpreter::ScBahtText()
2755 sal_uInt8 nParamCount
= GetByte();
2756 if ( MustHaveParamCount( nParamCount
, 1 ) )
2758 double fValue
= GetDouble();
2761 PushError( nGlobalError
);
2766 bool bMinus
= fValue
< 0.0;
2767 fValue
= fabs( fValue
);
2769 // round to 2 digits after decimal point, fValue contains Satang as integer
2770 fValue
= ::rtl::math::approxFloor( fValue
* 100.0 + 0.5 );
2772 // split Baht and Satang
2774 sal_Int32 nSatang
= 0;
2775 lclSplitBlock( fBaht
, nSatang
, fValue
, 100.0 );
2777 OStringBuffer aText
;
2779 // generate text for Baht value
2783 aText
.append( UTF8_TH_0
);
2785 else while( fBaht
> 0.0 )
2787 OStringBuffer aBlock
;
2788 sal_Int32 nBlock
= 0;
2789 lclSplitBlock( fBaht
, nBlock
, fBaht
, 1.0e6
);
2791 lclAppendBlock( aBlock
, nBlock
);
2792 // add leading "million", if there will come more blocks
2794 aBlock
.insert( 0, OString(UTF8_TH_1E6
) );
2796 aText
.insert(0, aBlock
.makeStringAndClear());
2798 if (!aText
.isEmpty())
2799 aText
.append( UTF8_TH_BAHT
);
2801 // generate text for Satang value
2804 aText
.append( UTF8_TH_DOT0
);
2808 lclAppendBlock( aText
, nSatang
);
2809 aText
.append( UTF8_TH_SATANG
);
2812 // add the minus sign
2814 aText
.insert( 0, OString( UTF8_TH_MINUS
) );
2816 PushString( OStringToOUString(aText
.makeStringAndClear(), RTL_TEXTENCODING_UTF8
) );
2820 void ScInterpreter::ScGetPivotData()
2822 sal_uInt8 nParamCount
= GetByte();
2824 if (!MustHaveParamCount(nParamCount
, 2, 30) || (nParamCount
% 2) == 1)
2826 PushError(errNoRef
);
2830 bool bOldSyntax
= false;
2831 if (nParamCount
== 2)
2833 // if the first parameter is a ref, assume old syntax
2834 StackVar eFirstType
= GetStackType(2);
2835 if (eFirstType
== svSingleRef
|| eFirstType
== svDoubleRef
)
2839 std::vector
<sheet::DataPilotFieldFilter
> aFilters
;
2840 OUString aDataFieldName
;
2845 aDataFieldName
= GetString().getString();
2847 switch (GetStackType())
2850 PopDoubleRef(aBlock
);
2855 PopSingleRef(aAddr
);
2860 PushError(errNoRef
);
2866 // Standard syntax: separate name/value pairs
2868 sal_uInt16 nFilterCount
= nParamCount
/ 2 - 1;
2869 aFilters
.resize(nFilterCount
);
2871 sal_uInt16 i
= nFilterCount
;
2874 //! should allow numeric constraint values
2875 aFilters
[i
].MatchValue
= GetString().getString();
2876 aFilters
[i
].FieldName
= GetString().getString();
2879 switch (GetStackType())
2882 PopDoubleRef(aBlock
);
2887 PopSingleRef(aAddr
);
2892 PushError(errNoRef
);
2896 aDataFieldName
= GetString().getString(); // First parameter is data field name.
2899 // NOTE : MS Excel docs claim to use the 'most recent' which is not
2900 // exactly the same as what we do in ScDocument::GetDPAtBlock
2901 // However we do need to use GetDPABlock
2902 ScDPObject
* pDPObj
= pDok
->GetDPAtBlock(aBlock
);
2905 PushError(errNoRef
);
2911 OUString aFilterStr
= aDataFieldName
;
2912 std::vector
<sheet::GeneralFunction
> aFilterFuncs
;
2913 if (!pDPObj
->ParseFilters(aDataFieldName
, aFilters
, aFilterFuncs
, aFilterStr
))
2915 PushError(errNoRef
);
2919 // TODO : For now, we ignore filter functions since we couldn't find a
2920 // live example of how they are supposed to be used. We'll support
2921 // this again once we come across a real-world example.
2924 double fVal
= pDPObj
->GetPivotData(aDataFieldName
, aFilters
);
2925 if (rtl::math::isNan(fVal
))
2927 PushError(errNoRef
);
2933 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */