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 .
21 #include <interpre.hxx>
23 #include <comphelper/string.hxx>
24 #include <o3tl/float_int_conversion.hxx>
25 #include <o3tl/string_view.hxx>
26 #include <sfx2/bindings.hxx>
27 #include <sfx2/linkmgr.hxx>
28 #include <sfx2/objsh.hxx>
29 #include <svl/numformat.hxx>
30 #include <svl/zforlist.hxx>
31 #include <tools/duration.hxx>
32 #include <sal/macros.h>
33 #include <osl/diagnose.h>
36 #include <ddelink.hxx>
37 #include <scmatrix.hxx>
38 #include <formulacell.hxx>
39 #include <document.hxx>
40 #include <dociter.hxx>
42 #include <unitconv.hxx>
44 #include <dpobject.hxx>
45 #include <tokenarray.hxx>
46 #include <globalnames.hxx>
47 #include <stlpool.hxx>
48 #include <stlsheet.hxx>
49 #include <dpcache.hxx>
51 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
56 using namespace com::sun::star
;
57 using namespace formula
;
59 #define SCdEpsilon 1.0E-7
63 double ScInterpreter::GetDateSerial( sal_Int16 nYear
, sal_Int16 nMonth
, sal_Int16 nDay
,
66 if ( nYear
< 100 && !bStrict
)
67 nYear
= mrContext
.NFExpandTwoDigitYear( nYear
);
68 // Do not use a default Date ctor here because it asks system time with a
69 // performance penalty.
81 nY
= nYear
+ (nMonth
-1) / 12;
82 nM
= ((nMonth
-1) % 12) + 1;
86 nY
= nYear
+ (nMonth
-12) / 12;
87 nM
= 12 - (-nMonth
) % 12;
91 Date
aDate( nD
, nM
, nY
);
93 aDate
.AddDays( nDay
- 1 );
94 if (aDate
.IsValidAndGregorian())
95 return static_cast<double>(aDate
- mrContext
.NFGetNullDate());
98 SetError(FormulaError::NoValue
);
103 void ScInterpreter::ScGetActDate()
105 nFuncFmtType
= SvNumFormatType::DATE
;
106 Date
aActDate( Date::SYSTEM
);
107 tools::Long nDiff
= aActDate
- mrContext
.NFGetNullDate();
108 PushDouble(static_cast<double>(nDiff
));
111 void ScInterpreter::ScGetActTime()
113 nFuncFmtType
= SvNumFormatType::DATETIME
;
114 DateTime
aActTime( DateTime::SYSTEM
);
115 tools::Long nDiff
= aActTime
- mrContext
.NFGetNullDate();
116 double fTime
= aActTime
.GetHour() / static_cast<double>(::tools::Time::hourPerDay
) +
117 aActTime
.GetMin() / static_cast<double>(::tools::Time::minutePerDay
) +
118 aActTime
.GetSec() / static_cast<double>(::tools::Time::secondPerDay
) +
119 aActTime
.GetNanoSec() / static_cast<double>(::tools::Time::nanoSecPerDay
);
120 PushDouble( static_cast<double>(nDiff
) + fTime
);
123 void ScInterpreter::ScGetYear()
125 Date aDate
= mrContext
.NFGetNullDate();
126 aDate
.AddDays( GetFloor32());
127 PushDouble( static_cast<double>(aDate
.GetYear()) );
130 void ScInterpreter::ScGetMonth()
132 Date aDate
= mrContext
.NFGetNullDate();
133 aDate
.AddDays( GetFloor32());
134 PushDouble( static_cast<double>(aDate
.GetMonth()) );
137 void ScInterpreter::ScGetDay()
139 Date aDate
= mrContext
.NFGetNullDate();
140 aDate
.AddDays( GetFloor32());
141 PushDouble(static_cast<double>(aDate
.GetDay()));
144 void ScInterpreter::ScGetMin()
146 sal_uInt16 nHour
, nMinute
, nSecond
;
147 double fFractionOfSecond
;
148 tools::Time::GetClock( GetDouble(), nHour
, nMinute
, nSecond
, fFractionOfSecond
, 0);
149 PushDouble( nMinute
);
152 void ScInterpreter::ScGetSec()
154 sal_uInt16 nHour
, nMinute
, nSecond
;
155 double fFractionOfSecond
;
156 tools::Time::GetClock( GetDouble(), nHour
, nMinute
, nSecond
, fFractionOfSecond
, 0);
157 if ( fFractionOfSecond
>= 0.5 )
158 nSecond
= ( nSecond
+ 1 ) % 60;
159 PushDouble( nSecond
);
163 void ScInterpreter::ScGetHour()
165 sal_uInt16 nHour
, nMinute
, nSecond
;
166 double fFractionOfSecond
;
167 tools::Time::GetClock( GetDouble(), nHour
, nMinute
, nSecond
, fFractionOfSecond
, 0);
171 void ScInterpreter::ScGetDateValue()
173 OUString aInputString
= GetString().getString();
174 sal_uInt32 nFIndex
= 0; // for a default country/language
176 if (mrContext
.NFIsNumberFormat(aInputString
, nFIndex
, fVal
))
178 SvNumFormatType eType
= mrContext
.NFGetType(nFIndex
);
179 if (eType
== SvNumFormatType::DATE
|| eType
== SvNumFormatType::DATETIME
)
181 nFuncFmtType
= SvNumFormatType::DATE
;
182 PushDouble(::rtl::math::approxFloor(fVal
));
185 PushIllegalArgument();
188 PushIllegalArgument();
191 void ScInterpreter::ScGetDayOfWeek()
193 sal_uInt8 nParamCount
= GetByte();
194 if ( !MustHaveParamCount( nParamCount
, 1, 2 ) )
198 if (nParamCount
== 2)
203 Date aDate
= mrContext
.NFGetNullDate();
204 aDate
.AddDays( GetFloor32());
205 int nVal
= static_cast<int>(aDate
.GetDayOfWeek()); // MONDAY = 0
208 case 1: // Sunday = 1
214 case 2: // Monday = 1
217 case 3: // Monday = 0
220 case 11: // Monday = 1
221 case 12: // Tuesday = 1
222 case 13: // Wednesday = 1
223 case 14: // Thursday = 1
224 case 15: // Friday = 1
225 case 16: // Saturday = 1
226 case 17: // Sunday = 1
227 if (nVal
< nFlag
- 11) // x = nFlag - 11 = 0,1,2,3,4,5,6
228 nVal
+= 19 - nFlag
; // nVal += (8 - (nFlag - 11) = 8 - x = 8,7,6,5,4,3,2)
230 nVal
-= nFlag
- 12; // nVal -= ((nFlag - 11) - 1 = x - 1 = -1,0,1,2,3,4,5)
233 SetError( FormulaError::IllegalArgument
);
238 void ScInterpreter::ScWeeknumOOo()
240 if ( MustHaveParamCount( GetByte(), 2 ) )
242 sal_Int16 nFlag
= GetInt16();
244 Date aDate
= mrContext
.NFGetNullDate();
245 aDate
.AddDays( GetFloor32());
246 PushInt( static_cast<int>(aDate
.GetWeekOfYear( nFlag
== 1 ? SUNDAY
: MONDAY
)));
250 void ScInterpreter::ScGetWeekOfYear()
252 sal_uInt8 nParamCount
= GetByte();
253 if ( !MustHaveParamCount( nParamCount
, 1, 2 ) )
256 sal_Int16 nFlag
= ( nParamCount
== 1 ) ? 1 : GetInt16();
258 Date aDate
= mrContext
.NFGetNullDate();
259 aDate
.AddDays( GetFloor32());
261 sal_Int32 nMinimumNumberOfDaysInWeek
;
262 DayOfWeek eFirstDayOfWeek
;
266 eFirstDayOfWeek
= SUNDAY
;
267 nMinimumNumberOfDaysInWeek
= 1;
270 eFirstDayOfWeek
= MONDAY
;
271 nMinimumNumberOfDaysInWeek
= 1;
280 eFirstDayOfWeek
= static_cast<DayOfWeek
>( nFlag
- 11 ); // MONDAY := 0
281 nMinimumNumberOfDaysInWeek
= 1; //the week containing January 1 is week 1
286 eFirstDayOfWeek
= MONDAY
;
287 nMinimumNumberOfDaysInWeek
= 4;
290 PushIllegalArgument();
293 PushInt( static_cast<int>(aDate
.GetWeekOfYear( eFirstDayOfWeek
, nMinimumNumberOfDaysInWeek
)) );
296 void ScInterpreter::ScGetIsoWeekOfYear()
298 if ( MustHaveParamCount( GetByte(), 1 ) )
300 Date aDate
= mrContext
.NFGetNullDate();
301 aDate
.AddDays( GetFloor32());
302 PushInt( static_cast<int>(aDate
.GetWeekOfYear()) );
306 void ScInterpreter::ScEasterSunday()
308 nFuncFmtType
= SvNumFormatType::DATE
;
309 if ( !MustHaveParamCount( GetByte(), 1 ) )
312 sal_Int16 nYear
= GetInt16();
313 if (nGlobalError
!= FormulaError::NONE
)
315 PushError( nGlobalError
);
319 nYear
= mrContext
.NFExpandTwoDigitYear( nYear
);
320 if (nYear
< 1583 || nYear
> 9956)
322 // Valid Gregorian and maximum year constraints not met.
323 PushIllegalArgument();
326 // don't worry, be happy :)
327 int B
,C
,D
,E
,F
,G
,H
,I
,K
,L
,M
,N
,O
;
329 B
= int(nYear
/ 100);
333 F
= int((B
+ 8) / 25);
334 G
= int((B
- F
+ 1) / 3);
335 H
= (19 * N
+ B
- D
- G
+ 15) % 30;
338 L
= (32 + 2 * E
+ 2 * I
- H
- K
) % 7;
339 M
= int((N
+ 11 * H
+ 22 * L
) / 451);
340 O
= H
+ L
- 7 * M
+ 114;
341 sal_Int16 nDay
= sal::static_int_cast
<sal_Int16
>( O
% 31 + 1 );
342 sal_Int16 nMonth
= sal::static_int_cast
<sal_Int16
>( int(O
/ 31) );
343 PushDouble( GetDateSerial( nYear
, nMonth
, nDay
, true ) );
346 FormulaError
ScInterpreter::GetWeekendAndHolidayMasks(
347 const sal_uInt8 nParamCount
, const sal_uInt32 nNullDate
, vector
< double >& rSortArray
,
348 bool bWeekendMask
[ 7 ] )
350 if ( nParamCount
== 4 )
352 vector
< double > nWeekendDays
;
353 GetNumberSequenceArray( 1, nWeekendDays
, false );
354 if ( nGlobalError
!= FormulaError::NONE
)
358 if ( nWeekendDays
.size() != 7 )
359 return FormulaError::IllegalArgument
;
361 // Weekend days defined by string, Sunday...Saturday
362 for ( int i
= 0; i
< 7; i
++ )
363 bWeekendMask
[ i
] = static_cast<bool>(nWeekendDays
[ ( i
== 6 ? 0 : i
+ 1 ) ]);
368 for ( int i
= 0; i
< 7; i
++ )
369 bWeekendMask
[ i
] = false;
371 bWeekendMask
[ SATURDAY
] = true;
372 bWeekendMask
[ SUNDAY
] = true;
375 if ( nParamCount
>= 3 )
377 GetSortArray( 1, rSortArray
, nullptr, true, true );
378 size_t nMax
= rSortArray
.size();
379 for ( size_t i
= 0; i
< nMax
; i
++ )
380 rSortArray
.at( i
) = ::rtl::math::approxFloor( rSortArray
.at( i
) ) + nNullDate
;
386 FormulaError
ScInterpreter::GetWeekendAndHolidayMasks_MS(
387 const sal_uInt8 nParamCount
, const sal_uInt32 nNullDate
, vector
< double >& rSortArray
,
388 bool bWeekendMask
[ 7 ], bool bWorkdayFunction
)
390 FormulaError nErr
= FormulaError::NONE
;
391 OUString aWeekendDays
;
392 if ( nParamCount
== 4 )
394 GetSortArray( 1, rSortArray
, nullptr, true, true );
395 size_t nMax
= rSortArray
.size();
396 for ( size_t i
= 0; i
< nMax
; i
++ )
397 rSortArray
.at( i
) = ::rtl::math::approxFloor( rSortArray
.at( i
) ) + nNullDate
;
400 if ( nParamCount
>= 3 )
406 switch ( GetStackType() )
409 case svExternalDoubleRef
:
410 return FormulaError::NoValue
;
415 svl::SharedString aSharedString
;
416 bool bDouble
= GetDoubleOrString( fDouble
, aSharedString
);
419 if ( fDouble
>= 1.0 && fDouble
<= 17 )
420 aWeekendDays
= OUString::number( fDouble
);
422 return FormulaError::NoValue
;
426 if ( aSharedString
.isEmpty() || aSharedString
.getLength() != 7 ||
427 ( bWorkdayFunction
&& aSharedString
.getString() == "1111111" ) )
428 return FormulaError::NoValue
;
430 aWeekendDays
= aSharedString
.getString();
438 for ( int i
= 0; i
< 7; i
++ )
439 bWeekendMask
[ i
] = false;
441 if ( aWeekendDays
.isEmpty() )
443 bWeekendMask
[ SATURDAY
] = true;
444 bWeekendMask
[ SUNDAY
] = true;
448 switch ( aWeekendDays
.getLength() )
451 // Weekend days defined by code
452 switch ( aWeekendDays
[ 0 ] )
454 case '1' : bWeekendMask
[ SATURDAY
] = true; bWeekendMask
[ SUNDAY
] = true; break;
455 case '2' : bWeekendMask
[ SUNDAY
] = true; bWeekendMask
[ MONDAY
] = true; break;
456 case '3' : bWeekendMask
[ MONDAY
] = true; bWeekendMask
[ TUESDAY
] = true; break;
457 case '4' : bWeekendMask
[ TUESDAY
] = true; bWeekendMask
[ WEDNESDAY
] = true; break;
458 case '5' : bWeekendMask
[ WEDNESDAY
] = true; bWeekendMask
[ THURSDAY
] = true; break;
459 case '6' : bWeekendMask
[ THURSDAY
] = true; bWeekendMask
[ FRIDAY
] = true; break;
460 case '7' : bWeekendMask
[ FRIDAY
] = true; bWeekendMask
[ SATURDAY
] = true; break;
461 default : nErr
= FormulaError::IllegalArgument
; break;
465 // Weekend day defined by code
466 if ( aWeekendDays
[ 0 ] == '1' )
468 switch ( aWeekendDays
[ 1 ] )
470 case '1' : bWeekendMask
[ SUNDAY
] = true; break;
471 case '2' : bWeekendMask
[ MONDAY
] = true; break;
472 case '3' : bWeekendMask
[ TUESDAY
] = true; break;
473 case '4' : bWeekendMask
[ WEDNESDAY
] = true; break;
474 case '5' : bWeekendMask
[ THURSDAY
] = true; break;
475 case '6' : bWeekendMask
[ FRIDAY
] = true; break;
476 case '7' : bWeekendMask
[ SATURDAY
] = true; break;
477 default : nErr
= FormulaError::IllegalArgument
; break;
481 nErr
= FormulaError::IllegalArgument
;
484 // Weekend days defined by string
485 for ( int i
= 0; i
< 7 && nErr
== FormulaError::NONE
; i
++ )
487 switch ( aWeekendDays
[ i
] )
489 case '0' : bWeekendMask
[ i
] = false; break;
490 case '1' : bWeekendMask
[ i
] = true; break;
491 default : nErr
= FormulaError::IllegalArgument
; break;
496 nErr
= FormulaError::IllegalArgument
;
503 void ScInterpreter::ScNetWorkdays( bool bOOXML_Version
)
505 sal_uInt8 nParamCount
= GetByte();
506 if ( !MustHaveParamCount( nParamCount
, 2, 4 ) )
509 vector
<double> nSortArray
;
510 bool bWeekendMask
[ 7 ];
511 const Date
& rNullDate
= mrContext
.NFGetNullDate();
512 sal_uInt32 nNullDate
= Date::DateToDays( rNullDate
.GetDay(), rNullDate
.GetMonth(), rNullDate
.GetYear() );
514 if ( bOOXML_Version
)
516 nErr
= GetWeekendAndHolidayMasks_MS( nParamCount
, nNullDate
,
517 nSortArray
, bWeekendMask
, false );
521 nErr
= GetWeekendAndHolidayMasks( nParamCount
, nNullDate
,
522 nSortArray
, bWeekendMask
);
524 if ( nErr
!= FormulaError::NONE
)
528 sal_uInt32 nDate2
= GetUInt32();
529 sal_uInt32 nDate1
= GetUInt32();
530 if (nGlobalError
!= FormulaError::NONE
|| (nDate1
> SAL_MAX_UINT32
- nNullDate
) || nDate2
> (SAL_MAX_UINT32
- nNullDate
))
532 PushIllegalArgument();
540 bool bReverse
= ( nDate1
> nDate2
);
542 std::swap( nDate1
, nDate2
);
543 size_t nMax
= nSortArray
.size();
544 while ( nDate1
<= nDate2
)
546 if ( !bWeekendMask
[ GetDayOfWeek( nDate1
) ] )
548 while ( nRef
< nMax
&& nSortArray
.at( nRef
) < nDate1
)
550 if ( nRef
>= nMax
|| nSortArray
.at( nRef
) != nDate1
)
555 PushDouble( static_cast<double>( bReverse
? -nCnt
: nCnt
) );
559 void ScInterpreter::ScWorkday_MS()
561 sal_uInt8 nParamCount
= GetByte();
562 if ( !MustHaveParamCount( nParamCount
, 2, 4 ) )
565 nFuncFmtType
= SvNumFormatType::DATE
;
566 vector
<double> nSortArray
;
567 bool bWeekendMask
[ 7 ];
568 const Date
& rNullDate
= mrContext
.NFGetNullDate();
569 sal_uInt32 nNullDate
= Date::DateToDays( rNullDate
.GetDay(), rNullDate
.GetMonth(), rNullDate
.GetYear() );
570 FormulaError nErr
= GetWeekendAndHolidayMasks_MS( nParamCount
, nNullDate
,
571 nSortArray
, bWeekendMask
, true );
572 if ( nErr
!= FormulaError::NONE
)
576 sal_Int32 nDays
= GetFloor32();
577 sal_uInt32 nDate
= GetUInt32();
578 if (nGlobalError
!= FormulaError::NONE
|| (nDate
> SAL_MAX_UINT32
- nNullDate
))
580 PushIllegalArgument();
586 PushDouble( static_cast<double>( nDate
- nNullDate
) );
589 size_t nMax
= nSortArray
.size();
599 while ( bWeekendMask
[ GetDayOfWeek( nDate
) ] ); //jump over weekend day(s)
601 while ( nRef
< nMax
&& nSortArray
.at( nRef
) < nDate
)
604 if ( nRef
>= nMax
|| nSortArray
.at( nRef
) != nDate
)
610 sal_Int16 nRef
= nMax
- 1;
617 while ( bWeekendMask
[ GetDayOfWeek( nDate
) ] ); //jump over weekend day(s)
619 while ( nRef
>= 0 && nSortArray
.at( nRef
) > nDate
)
622 if (nRef
< 0 || nSortArray
.at(nRef
) != nDate
)
626 PushDouble( static_cast<double>( nDate
- nNullDate
) );
631 void ScInterpreter::ScGetDate()
633 nFuncFmtType
= SvNumFormatType::DATE
;
634 if ( !MustHaveParamCount( GetByte(), 3 ) )
637 sal_Int16 nDay
= GetInt16();
638 sal_Int16 nMonth
= GetInt16();
640 SetError( FormulaError::ParameterExpected
); // Year must be given.
641 sal_Int16 nYear
= GetInt16();
642 if (nGlobalError
!= FormulaError::NONE
|| nYear
< 0)
643 PushIllegalArgument();
645 PushDouble(GetDateSerial(nYear
, nMonth
, nDay
, false));
648 void ScInterpreter::ScGetTime()
650 nFuncFmtType
= SvNumFormatType::TIME
;
651 if ( MustHaveParamCount( GetByte(), 3 ) )
653 double fSec
= GetDouble();
654 double fMin
= GetDouble();
655 double fHour
= GetDouble();
656 double fTime
= fmod( (fHour
* ::tools::Time::secondPerHour
) + (fMin
* ::tools::Time::secondPerMinute
) + fSec
, DATE_TIME_FACTOR
) / DATE_TIME_FACTOR
;
658 PushIllegalArgument();
664 void ScInterpreter::ScGetDiffDate()
666 if ( MustHaveParamCount( GetByte(), 2 ) )
668 double fDate2
= GetDouble();
669 double fDate1
= GetDouble();
670 PushDouble(fDate1
- fDate2
);
674 void ScInterpreter::ScGetDiffDate360()
676 /* Implementation follows
677 * http://www.bondmarkets.com/eCommerce/SMD_Fields_030802.pdf
678 * Appendix B: Day-Count Bases, there are 7 different ways to calculate the
679 * 30-days count. That document also claims that Excel implements the "PSA
680 * 30" or "NASD 30" method (funny enough they also state that Excel is the
681 * only tool that does so).
683 * Note that the definition given in
684 * http://msdn.microsoft.com/library/en-us/office97/html/SEB7C.asp
685 * is _not_ the way how it is actually calculated by Excel (that would not
686 * even match any of the 7 methods mentioned above) and would result in the
687 * following test cases producing wrong results according to that appendix B:
689 * 28-Feb-95 31-Aug-95 181 instead of 180
690 * 29-Feb-96 31-Aug-96 181 instead of 180
691 * 30-Jan-96 31-Mar-96 61 instead of 60
692 * 31-Jan-96 31-Mar-96 61 instead of 60
694 * Still, there is a difference between OOoCalc and Excel:
696 * 02-Feb-99 31-Mar-00 results in 419
697 * 31-Mar-00 02-Feb-99 results in -418
698 * In Calc the result is 419 respectively -419. I consider the -418 a bug in Excel.
701 sal_uInt8 nParamCount
= GetByte();
702 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
705 bool bFlag
= nParamCount
== 3 && GetBool();
706 sal_Int32 nDate2
= GetFloor32();
707 sal_Int32 nDate1
= GetFloor32();
708 if (nGlobalError
!= FormulaError::NONE
)
709 PushError( nGlobalError
);
713 // #i84934# only for non-US European algorithm swap dates. Else
714 // follow Excel's meaningless extrapolation for "interoperability".
715 if (bFlag
&& (nDate2
< nDate1
))
724 Date aDate1
= mrContext
.NFGetNullDate();
725 aDate1
.AddDays( nDate1
);
726 Date aDate2
= mrContext
.NFGetNullDate();
727 aDate2
.AddDays( nDate2
);
728 if (aDate1
.GetDay() == 31)
732 if (aDate1
.GetMonth() == 2)
734 switch ( aDate1
.GetDay() )
737 if ( !aDate1
.IsLeapYear() )
746 if (aDate2
.GetDay() == 31)
750 if (aDate1
.GetDay() == 30)
756 PushDouble( static_cast<double>(nSign
) *
757 ( static_cast<double>(aDate2
.GetDay()) + static_cast<double>(aDate2
.GetMonth()) * 30.0 +
758 static_cast<double>(aDate2
.GetYear()) * 360.0
759 - static_cast<double>(aDate1
.GetDay()) - static_cast<double>(aDate1
.GetMonth()) * 30.0
760 - static_cast<double>(aDate1
.GetYear()) * 360.0) );
764 // fdo#44456 function DATEDIF as defined in ODF1.2 (Par. 6.10.3)
765 void ScInterpreter::ScGetDateDif()
767 if ( !MustHaveParamCount( GetByte(), 3 ) )
770 OUString aInterval
= GetString().getString();
771 sal_Int32 nDate2
= GetFloor32();
772 sal_Int32 nDate1
= GetFloor32();
774 if (nGlobalError
!= FormulaError::NONE
)
776 PushError( nGlobalError
);
780 // Excel doesn't swap dates or return negative numbers, so don't we.
783 PushIllegalArgument();
787 double dd
= nDate2
- nDate1
;
788 // Zero difference or number of days can be returned immediately.
789 if (dd
== 0.0 || aInterval
.equalsIgnoreAsciiCase( "d" ))
795 // split dates in day, month, year for use with formats other than "d"
796 sal_uInt16 d1
, m1
, d2
, m2
;
798 Date
aDate1( mrContext
.NFGetNullDate());
799 aDate1
.AddDays( nDate1
);
800 y1
= aDate1
.GetYear();
801 m1
= aDate1
.GetMonth();
802 d1
= aDate1
.GetDay();
803 Date
aDate2( mrContext
.NFGetNullDate());
804 aDate2
.AddDays( nDate2
);
805 y2
= aDate2
.GetYear();
806 m2
= aDate2
.GetMonth();
807 d2
= aDate2
.GetDay();
809 // Close the year 0 gap to calculate year difference.
810 if (y1
< 0 && y2
> 0)
812 else if (y1
> 0 && y2
< 0)
815 if ( aInterval
.equalsIgnoreAsciiCase( "m" ) )
817 // Return number of months.
818 int md
= m2
- m1
+ 12 * (y2
- y1
);
823 else if ( aInterval
.equalsIgnoreAsciiCase( "y" ) )
825 // Return number of years.
829 if (m2
> m1
|| (m2
== m1
&& d2
>= d1
))
830 yd
= y2
- y1
; // complete years between dates
832 yd
= y2
- y1
- 1; // one incomplete year
836 // Year is equal as we don't allow reversed arguments, no
837 // complete year between dates.
842 else if ( aInterval
.equalsIgnoreAsciiCase( "md" ) )
844 // Return number of days, excluding months and years.
845 // This is actually the remainder of days when subtracting years
846 // and months from the difference of dates. Birthday-like 23 years
847 // and 10 months and 19 days.
849 // Algorithm's roll-over behavior extracted from Excel by try and
851 // If day1 <= day2 then simply day2 - day1.
852 // If day1 > day2 then set month1 to month2-1 and year1 to
853 // year2(-1) and subtract dates, e.g. for 2012-01-28,2012-03-01 set
854 // 2012-02-28 and then (2012-03-01)-(2012-02-28) => 2 days (leap
856 // For 2011-01-29,2011-03-01 the non-existent 2011-02-29 rolls over
857 // to 2011-03-01 so the result is 0. Same for day 31 in months with
867 aDate1
.SetYear( y2
== 1 ? -1 : y2
- 1 );
868 aDate1
.SetMonth( 12 );
872 aDate1
.SetYear( y2
);
873 aDate1
.SetMonth( m2
- 1 );
876 nd
= aDate2
- aDate1
;
880 else if ( aInterval
.equalsIgnoreAsciiCase( "ym" ) )
882 // Return number of months, excluding years.
883 int md
= m2
- m1
+ 12 * (y2
- y1
);
889 else if ( aInterval
.equalsIgnoreAsciiCase( "yd" ) )
891 // Return number of days, excluding years.
893 // Condition corresponds with "y".
894 if (m2
> m1
|| (m2
== m1
&& d2
>= d1
))
895 aDate1
.SetYear( y2
);
897 aDate1
.SetYear( y2
- 1 );
898 // XXX NOTE: Excel for the case 1988-06-22,2012-05-11 returns
899 // 323, whereas the result here is 324. Don't they use the leap
901 // http://www.cpearson.com/excel/datedif.aspx "DATEDIF And Leap
902 // Years" is not correct and Excel 2010 correctly returns 0 in
903 // both cases mentioned there. Also using year1 as mentioned
904 // produces incorrect results in other cases and different from
905 // Excel 2010. Apparently they fixed some calculations.
907 double fd
= aDate2
- aDate1
;
911 PushIllegalArgument(); // unsupported format
914 void ScInterpreter::ScGetTimeValue()
916 OUString aInputString
= GetString().getString();
917 sal_uInt32 nFIndex
= 0; // damit default Land/Spr.
919 if (mrContext
.NFIsNumberFormat(aInputString
, nFIndex
, fVal
, SvNumInputOptions::LAX_TIME
))
921 SvNumFormatType eType
= mrContext
.NFGetType(nFIndex
);
922 if (eType
== SvNumFormatType::TIME
|| eType
== SvNumFormatType::DATETIME
)
924 nFuncFmtType
= SvNumFormatType::TIME
;
925 double fDateVal
= rtl::math::approxFloor(fVal
);
926 double fTimeVal
= fVal
- fDateVal
;
927 fTimeVal
= ::tools::Duration(fTimeVal
).GetInDays(); // force corrected
928 PushDouble(fTimeVal
);
931 PushIllegalArgument();
934 PushIllegalArgument();
937 void ScInterpreter::ScPlusMinus()
939 double fVal
= GetDouble();
948 void ScInterpreter::ScAbs()
950 PushDouble(std::abs(GetDouble()));
953 void ScInterpreter::ScInt()
955 PushDouble(::rtl::math::approxFloor(GetDouble()));
958 void ScInterpreter::RoundNumber( rtl_math_RoundingMode eMode
)
960 sal_uInt8 nParamCount
= GetByte();
961 if ( !MustHaveParamCount( nParamCount
, 1, 2 ) )
965 if (nParamCount
== 1)
966 fVal
= ::rtl::math::round( GetDouble(), 0, eMode
);
969 const sal_Int16 nDec
= GetInt16();
970 const double fX
= GetDouble();
971 if (nGlobalError
== FormulaError::NONE
)
973 // A quite aggressive approach with 12 significant digits.
974 // However, using 14 or some other doesn't work because other
975 // values may fail, like =ROUNDDOWN(2-5E-015;13) would produce
976 // 2 (another example in tdf#124286).
977 constexpr sal_Int16 kSigDig
= 12;
979 if ( ( eMode
== rtl_math_RoundingMode_Down
||
980 eMode
== rtl_math_RoundingMode_Up
) &&
981 nDec
< kSigDig
&& fmod( fX
, 1.0 ) != 0.0 )
984 // tdf124286 : round to significant digits before rounding
985 // down or up to avoid unexpected rounding errors
986 // caused by decimal -> binary -> decimal conversion
989 // Similar to RoundSignificant() but omitting the back-scaling
990 // and interim integer rounding before the final rounding,
991 // which would result in double rounding. Instead, adjust the
992 // decimals and round into integer part before scaling back.
993 const double fTemp
= floor( log10( std::abs(fRes
))) + 1.0 - kSigDig
;
994 // Avoid inaccuracy of negative powers of 10.
996 fRes
*= pow(10.0, -fTemp
);
998 fRes
/= pow(10.0, fTemp
);
999 if (std::isfinite(fRes
))
1001 // fRes is now at a decimal normalized scale.
1002 // Truncate up-rounding to opposite direction for values
1003 // like 0.0600000000000005 =ROUNDUP(8.06-8;2) that here now
1004 // is 600000000000.005 and otherwise would yield 0.07
1005 if (eMode
== rtl_math_RoundingMode_Up
)
1006 fRes
= ::rtl::math::approxFloor(fRes
);
1007 fVal
= ::rtl::math::round( fRes
, nDec
+ fTemp
, eMode
);
1009 fVal
/= pow(10.0, -fTemp
);
1011 fVal
*= pow(10.0, fTemp
);
1015 // Overflow. Let our round() decide if and how to round.
1016 fVal
= ::rtl::math::round( fX
, nDec
, eMode
);
1020 fVal
= ::rtl::math::round( fX
, nDec
, eMode
);
1026 void ScInterpreter::ScRound()
1028 RoundNumber( rtl_math_RoundingMode_Corrected
);
1031 void ScInterpreter::ScRoundDown()
1033 RoundNumber( rtl_math_RoundingMode_Down
);
1036 void ScInterpreter::ScRoundUp()
1038 RoundNumber( rtl_math_RoundingMode_Up
);
1041 void ScInterpreter::RoundSignificant( double fX
, double fDigits
, double &fRes
)
1043 double fTemp
= floor( log10( std::abs(fX
) ) ) + 1.0 - fDigits
;
1045 // Avoid inaccuracy of negative powers of 10.
1047 fIn
*= pow(10.0, -fTemp
);
1049 fIn
/= pow(10.0, fTemp
);
1050 // For very large fX there might be an overflow in fIn resulting in
1051 // non-finite. rtl::math::round() handles that and it will be propagated as
1053 fRes
= ::rtl::math::round(fIn
);
1055 fRes
/= pow(10.0, -fTemp
);
1057 fRes
*= pow(10.0, fTemp
);
1061 void ScInterpreter::ScRoundSignificant()
1063 if ( !MustHaveParamCount( GetByte(), 2 ) )
1066 double fDigits
= ::rtl::math::approxFloor( GetDouble() );
1067 double fX
= GetDouble();
1068 if ( nGlobalError
!= FormulaError::NONE
|| fDigits
< 1.0 )
1070 PushIllegalArgument();
1079 RoundSignificant( fX
, fDigits
, fRes
);
1084 /** tdf69552 ODFF1.2 function CEILING and Excel function CEILING.MATH
1085 In essence, the difference between the two is that ODFF-CEILING needs to
1086 have arguments value and significance of the same sign and with
1087 CEILING.MATH the sign of argument significance is irrevelevant.
1088 This is why ODFF-CEILING is exported to Excel as CEILING.MATH and
1089 CEILING.MATH is imported in Calc as CEILING.MATH
1091 void ScInterpreter::ScCeil( bool bODFF
)
1093 sal_uInt8 nParamCount
= GetByte();
1094 if ( !MustHaveParamCount( nParamCount
, 1, 3 ) )
1097 bool bAbs
= nParamCount
== 3 && GetBool();
1099 if ( nParamCount
== 1 )
1102 fDec
= ( fVal
< 0 ? -1 : 1 );
1106 bool bArgumentMissing
= IsMissing();
1109 if ( bArgumentMissing
)
1110 fDec
= ( fVal
< 0 ? -1 : 1 );
1112 if ( fVal
== 0 || fDec
== 0.0 )
1116 if ( bODFF
&& fVal
* fDec
< 0 )
1117 PushIllegalArgument();
1120 if ( fVal
* fDec
< 0.0 )
1123 if ( !bAbs
&& fVal
< 0.0 )
1124 PushDouble(::rtl::math::approxFloor( fVal
/ fDec
) * fDec
);
1126 PushDouble(::rtl::math::approxCeil( fVal
/ fDec
) * fDec
);
1131 void ScInterpreter::ScCeil_MS()
1133 sal_uInt8 nParamCount
= GetByte();
1134 if ( !MustHaveParamCount( nParamCount
, 2 ) )
1137 double fDec
= GetDouble();
1138 double fVal
= GetDouble();
1139 if ( fVal
== 0 || fDec
== 0.0 )
1141 else if ( fVal
* fDec
> 0 )
1142 PushDouble(::rtl::math::approxCeil( fVal
/ fDec
) * fDec
);
1143 else if ( fVal
< 0.0 )
1144 PushDouble(::rtl::math::approxFloor( fVal
/ -fDec
) * -fDec
);
1146 PushIllegalArgument();
1149 void ScInterpreter::ScCeil_Precise()
1151 sal_uInt8 nParamCount
= GetByte();
1152 if ( !MustHaveParamCount( nParamCount
, 1, 2 ) )
1156 if ( nParamCount
== 1 )
1163 fDec
= std::abs( GetDoubleWithDefault( 1.0 ));
1166 if ( fDec
== 0.0 || fVal
== 0.0 )
1169 PushDouble(::rtl::math::approxCeil( fVal
/ fDec
) * fDec
);
1172 /** tdf69552 ODFF1.2 function FLOOR and Excel function FLOOR.MATH
1173 In essence, the difference between the two is that ODFF-FLOOR needs to
1174 have arguments value and significance of the same sign and with
1175 FLOOR.MATH the sign of argument significance is irrevelevant.
1176 This is why ODFF-FLOOR is exported to Excel as FLOOR.MATH and
1177 FLOOR.MATH is imported in Calc as FLOOR.MATH
1179 void ScInterpreter::ScFloor( bool bODFF
)
1181 sal_uInt8 nParamCount
= GetByte();
1182 if ( !MustHaveParamCount( nParamCount
, 1, 3 ) )
1185 bool bAbs
= ( nParamCount
== 3 && GetBool() );
1187 if ( nParamCount
== 1 )
1190 fDec
= ( fVal
< 0 ? -1 : 1 );
1194 bool bArgumentMissing
= IsMissing();
1197 if ( bArgumentMissing
)
1198 fDec
= ( fVal
< 0 ? -1 : 1 );
1200 if ( fDec
== 0.0 || fVal
== 0.0 )
1204 if ( bODFF
&& ( fVal
* fDec
< 0.0 ) )
1205 PushIllegalArgument();
1208 if ( fVal
* fDec
< 0.0 )
1211 if ( !bAbs
&& fVal
< 0.0 )
1212 PushDouble(::rtl::math::approxCeil( fVal
/ fDec
) * fDec
);
1214 PushDouble(::rtl::math::approxFloor( fVal
/ fDec
) * fDec
);
1219 void ScInterpreter::ScFloor_MS()
1221 sal_uInt8 nParamCount
= GetByte();
1222 if ( !MustHaveParamCount( nParamCount
, 2 ) )
1225 double fDec
= GetDouble();
1226 double fVal
= GetDouble();
1230 else if ( fVal
* fDec
> 0 )
1231 PushDouble(::rtl::math::approxFloor( fVal
/ fDec
) * fDec
);
1232 else if ( fDec
== 0 )
1233 PushIllegalArgument();
1234 else if ( fVal
< 0.0 )
1235 PushDouble(::rtl::math::approxCeil( fVal
/ -fDec
) * -fDec
);
1237 PushIllegalArgument();
1240 void ScInterpreter::ScFloor_Precise()
1242 sal_uInt8 nParamCount
= GetByte();
1243 if ( !MustHaveParamCount( nParamCount
, 1, 2 ) )
1246 double fDec
= nParamCount
== 1 ? 1.0 : std::abs( GetDoubleWithDefault( 1.0 ) );
1247 double fVal
= GetDouble();
1248 if ( fDec
== 0.0 || fVal
== 0.0 )
1251 PushDouble(::rtl::math::approxFloor( fVal
/ fDec
) * fDec
);
1254 void ScInterpreter::ScEven()
1256 double fVal
= GetDouble();
1258 PushDouble(::rtl::math::approxFloor(fVal
/2.0) * 2.0);
1260 PushDouble(::rtl::math::approxCeil(fVal
/2.0) * 2.0);
1263 void ScInterpreter::ScOdd()
1265 double fVal
= GetDouble();
1268 fVal
= ::rtl::math::approxCeil(fVal
);
1269 if (fmod(fVal
, 2.0) == 0.0)
1274 fVal
= ::rtl::math::approxFloor(fVal
);
1275 if (fmod(fVal
, 2.0) == 0.0)
1281 void ScInterpreter::ScArcTan2()
1283 if ( MustHaveParamCount( GetByte(), 2 ) )
1285 double fVal2
= GetDouble();
1286 double fVal1
= GetDouble();
1287 PushDouble(atan2(fVal2
, fVal1
));
1291 void ScInterpreter::ScLog()
1293 sal_uInt8 nParamCount
= GetByte();
1294 if ( !MustHaveParamCount( nParamCount
, 1, 2 ) )
1297 double fBase
= nParamCount
== 2 ? GetDouble() : 10.0;
1298 double fVal
= GetDouble();
1299 if (fVal
> 0.0 && fBase
> 0.0 && fBase
!= 1.0)
1300 PushDouble(log(fVal
) / log(fBase
));
1302 PushIllegalArgument();
1305 void ScInterpreter::ScLn()
1307 double fVal
= GetDouble();
1309 PushDouble(log(fVal
));
1311 PushIllegalArgument();
1314 void ScInterpreter::ScLog10()
1316 double fVal
= GetDouble();
1318 PushDouble(log10(fVal
));
1320 PushIllegalArgument();
1323 void ScInterpreter::ScNPV()
1325 nFuncFmtType
= SvNumFormatType::CURRENCY
;
1326 short nParamCount
= GetByte();
1327 if ( !MustHaveParamCountMin( nParamCount
, 2) )
1330 KahanSum fVal
= 0.0;
1331 // We turn the stack upside down!
1332 ReverseStack( nParamCount
);
1333 if (nGlobalError
== FormulaError::NONE
)
1335 double fCount
= 1.0;
1336 double fRate
= GetDouble();
1338 size_t nRefInList
= 0;
1340 while (nParamCount
-- > 0)
1342 switch (GetStackType())
1346 fVal
+= GetDouble() / pow(1.0 + fRate
, fCount
);
1353 PopSingleRef( aAdr
);
1354 ScRefCellValue
aCell(mrDoc
, aAdr
);
1355 if (!aCell
.hasEmptyValue() && aCell
.hasNumeric())
1357 double fCellVal
= GetCellValue(aAdr
, aCell
);
1358 fVal
+= fCellVal
/ pow(1.0 + fRate
, fCount
);
1366 FormulaError nErr
= FormulaError::NONE
;
1368 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1369 ScHorizontalValueIterator
aValIter( mrDoc
, aRange
);
1370 while ((nErr
== FormulaError::NONE
) && aValIter
.GetNext(fCellVal
, nErr
))
1372 fVal
+= fCellVal
/ pow(1.0 + fRate
, fCount
);
1375 if ( nErr
!= FormulaError::NONE
)
1380 case svExternalSingleRef
:
1381 case svExternalDoubleRef
:
1383 ScMatrixRef pMat
= GetMatrix();
1387 pMat
->GetDimensions(nC
, nR
);
1388 if (nC
== 0 || nR
== 0)
1390 PushIllegalArgument();
1396 for ( SCSIZE j
= 0; j
< nC
; j
++ )
1398 for (SCSIZE k
= 0; k
< nR
; ++k
)
1400 if (!pMat
->IsValue(j
,k
))
1402 PushIllegalArgument();
1405 fx
= pMat
->GetDouble(j
,k
);
1406 fVal
+= fx
/ pow(1.0 + fRate
, fCount
);
1414 default : SetError(FormulaError::IllegalParameter
); break;
1418 PushDouble(fVal
.get());
1421 void ScInterpreter::ScIRR()
1423 nFuncFmtType
= SvNumFormatType::PERCENT
;
1424 sal_uInt8 nParamCount
= GetByte();
1425 if ( !MustHaveParamCount( nParamCount
, 1, 2 ) )
1427 double fEstimated
= nParamCount
== 2 ? GetDouble() : 0.1;
1429 // If it's -1 the default result for division by zero else startvalue
1430 double x
= fEstimated
== -1.0 ? 0.1 : fEstimated
;
1437 bool bIsMatrix
= false;
1438 switch (GetStackType())
1441 PopDoubleRef(aRange
);
1444 case svExternalSingleRef
:
1445 case svExternalDoubleRef
:
1449 pMat
->GetDimensions(nC
, nR
);
1450 if (nC
== 0 || nR
== 0)
1452 PushIllegalParameter();
1459 PushIllegalParameter();
1465 PushIllegalParameter();
1469 const sal_uInt16 nIterationsMax
= 20;
1470 sal_uInt16 nItCount
= 0;
1471 FormulaError nIterError
= FormulaError::NONE
;
1472 while (fEps
> SCdEpsilon
&& nItCount
< nIterationsMax
&& nGlobalError
== FormulaError::NONE
)
1473 { // Newtons method:
1474 KahanSum fNom
= 0.0;
1475 KahanSum fDenom
= 0.0;
1476 double fCount
= 0.0;
1479 for (SCSIZE j
= 0; j
< nC
&& nGlobalError
== FormulaError::NONE
; j
++)
1481 for (SCSIZE k
= 0; k
< nR
; k
++)
1483 if (!pMat
->IsValue(j
, k
))
1485 fValue
= pMat
->GetDouble(j
, k
);
1486 if (nGlobalError
!= FormulaError::NONE
)
1489 fNom
+= fValue
/ pow(1.0+x
,fCount
);
1490 fDenom
+= -fCount
* fValue
/ pow(1.0+x
,fCount
+1.0);
1497 ScValueIterator
aValIter(mrContext
, aRange
, mnSubTotalFlags
);
1498 bool bLoop
= aValIter
.GetFirst(fValue
, nIterError
);
1499 while (bLoop
&& nIterError
== FormulaError::NONE
)
1501 fNom
+= fValue
/ pow(1.0+x
,fCount
);
1502 fDenom
+= -fCount
* fValue
/ pow(1.0+x
,fCount
+1.0);
1505 bLoop
= aValIter
.GetNext(fValue
, nIterError
);
1507 SetError(nIterError
);
1509 double xNew
= x
- fNom
.get() / fDenom
.get(); // x(i+1) = x(i)-f(x(i))/f'(x(i))
1511 fEps
= std::abs(xNew
- x
);
1514 if (fEstimated
== 0.0 && std::abs(x
) < SCdEpsilon
)
1515 x
= 0.0; // adjust to zero
1516 if (fEps
< SCdEpsilon
)
1519 PushError( FormulaError::NoConvergence
);
1522 void ScInterpreter::ScMIRR()
1523 { // range_of_values ; rate_invest ; rate_reinvest
1524 nFuncFmtType
= SvNumFormatType::PERCENT
;
1525 if ( !MustHaveParamCount( GetByte(), 3 ) )
1528 double fRate1_reinvest
= GetDouble() + 1;
1529 double fRate1_invest
= GetDouble() + 1;
1535 bool bIsMatrix
= false;
1536 switch ( GetStackType() )
1539 PopDoubleRef( aRange
);
1542 case svExternalSingleRef
:
1543 case svExternalDoubleRef
:
1548 pMat
->GetDimensions( nC
, nR
);
1549 if ( nC
== 0 || nR
== 0 )
1550 SetError( FormulaError::IllegalArgument
);
1554 SetError( FormulaError::IllegalArgument
);
1558 SetError( FormulaError::IllegalParameter
);
1562 if ( nGlobalError
!= FormulaError::NONE
)
1563 PushError( nGlobalError
);
1566 KahanSum fNPV_reinvest
= 0.0;
1567 double fPow_reinvest
= 1.0;
1568 KahanSum fNPV_invest
= 0.0;
1569 double fPow_invest
= 1.0;
1570 sal_uLong nCount
= 0;
1571 bool bHasPosValue
= false;
1572 bool bHasNegValue
= false;
1577 for ( SCSIZE j
= 0; j
< nC
; j
++ )
1579 for ( SCSIZE k
= 0; k
< nR
; ++k
)
1581 if ( !pMat
->IsValue( j
, k
) )
1583 fX
= pMat
->GetDouble( j
, k
);
1584 if ( nGlobalError
!= FormulaError::NONE
)
1589 bHasPosValue
= true;
1590 fNPV_reinvest
+= fX
* fPow_reinvest
;
1592 else if ( fX
< 0.0 )
1594 bHasNegValue
= true;
1595 fNPV_invest
+= fX
* fPow_invest
;
1597 fPow_reinvest
/= fRate1_reinvest
;
1598 fPow_invest
/= fRate1_invest
;
1605 ScValueIterator
aValIter( mrContext
, aRange
, mnSubTotalFlags
);
1607 FormulaError nIterError
= FormulaError::NONE
;
1609 bool bLoop
= aValIter
.GetFirst( fCellValue
, nIterError
);
1612 if( fCellValue
> 0.0 ) // reinvestments
1614 bHasPosValue
= true;
1615 fNPV_reinvest
+= fCellValue
* fPow_reinvest
;
1617 else if( fCellValue
< 0.0 ) // investments
1619 bHasNegValue
= true;
1620 fNPV_invest
+= fCellValue
* fPow_invest
;
1622 fPow_reinvest
/= fRate1_reinvest
;
1623 fPow_invest
/= fRate1_invest
;
1626 bLoop
= aValIter
.GetNext( fCellValue
, nIterError
);
1629 if ( nIterError
!= FormulaError::NONE
)
1630 SetError( nIterError
);
1632 if ( !( bHasPosValue
&& bHasNegValue
) )
1633 SetError( FormulaError::IllegalArgument
);
1635 if ( nGlobalError
!= FormulaError::NONE
)
1636 PushError( nGlobalError
);
1639 double fResult
= -fNPV_reinvest
.get() / fNPV_invest
.get();
1640 fResult
*= pow( fRate1_reinvest
, static_cast<double>( nCount
- 1 ) );
1641 fResult
= pow( fResult
, div( 1.0, (nCount
- 1)) );
1642 PushDouble( fResult
- 1.0 );
1647 void ScInterpreter::ScISPMT()
1648 { // rate ; period ; total_periods ; invest
1649 if( MustHaveParamCount( GetByte(), 4 ) )
1651 double fInvest
= GetDouble();
1652 double fTotal
= GetDouble();
1653 double fPeriod
= GetDouble();
1654 double fRate
= GetDouble();
1656 if( nGlobalError
!= FormulaError::NONE
)
1657 PushError( nGlobalError
);
1659 PushDouble( fInvest
* fRate
* (fPeriod
/ fTotal
- 1.0) );
1663 // financial functions
1664 double ScInterpreter::ScGetPV(double fRate
, double fNper
, double fPmt
,
1665 double fFv
, bool bPayInAdvance
)
1669 fPv
= fFv
+ fPmt
* fNper
;
1673 fPv
= (fFv
* pow(1.0 + fRate
, -fNper
))
1674 + (fPmt
* (1.0 - pow(1.0 + fRate
, -fNper
+ 1.0)) / fRate
)
1677 fPv
= (fFv
* pow(1.0 + fRate
, -fNper
))
1678 + (fPmt
* (1.0 - pow(1.0 + fRate
, -fNper
)) / fRate
);
1683 void ScInterpreter::ScPV()
1685 nFuncFmtType
= SvNumFormatType::CURRENCY
;
1686 sal_uInt8 nParamCount
= GetByte();
1687 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
1690 bool bPayInAdvance
= nParamCount
== 5 && GetBool();
1691 double fFv
= nParamCount
>= 4 ? GetDouble() : 0;
1692 double fPmt
= GetDouble();
1693 double fNper
= GetDouble();
1694 double fRate
= GetDouble();
1695 PushDouble(ScGetPV(fRate
, fNper
, fPmt
, fFv
, bPayInAdvance
));
1698 void ScInterpreter::ScSYD()
1700 nFuncFmtType
= SvNumFormatType::CURRENCY
;
1701 if ( MustHaveParamCount( GetByte(), 4 ) )
1703 double fPer
= GetDouble();
1704 double fLife
= GetDouble();
1705 double fSalvage
= GetDouble();
1706 double fCost
= GetDouble();
1707 double fSyd
= ((fCost
- fSalvage
) * (fLife
- fPer
+ 1.0)) /
1708 ((fLife
* (fLife
+ 1.0)) / 2.0);
1713 double ScInterpreter::ScGetDDB(double fCost
, double fSalvage
, double fLife
,
1714 double fPeriod
, double fFactor
)
1716 double fDdb
, fRate
, fOldValue
, fNewValue
;
1717 fRate
= fFactor
/ fLife
;
1721 fOldValue
= fPeriod
== 1.0 ? fCost
: 0;
1724 fOldValue
= fCost
* pow(1.0 - fRate
, fPeriod
- 1.0);
1725 fNewValue
= fCost
* pow(1.0 - fRate
, fPeriod
);
1727 fDdb
= fNewValue
< fSalvage
? fOldValue
- fSalvage
: fOldValue
- fNewValue
;
1728 return fDdb
< 0 ? 0 : fDdb
;
1731 void ScInterpreter::ScDDB()
1733 nFuncFmtType
= SvNumFormatType::CURRENCY
;
1734 sal_uInt8 nParamCount
= GetByte();
1735 if ( !MustHaveParamCount( nParamCount
, 4, 5 ) )
1738 double fFactor
= nParamCount
== 5 ? GetDouble() : 2.0;
1739 double fPeriod
= GetDouble();
1740 double fLife
= GetDouble();
1741 double fSalvage
= GetDouble();
1742 double fCost
= GetDouble();
1743 if (fCost
< 0.0 || fSalvage
< 0.0 || fFactor
<= 0.0 || fSalvage
> fCost
1744 || fPeriod
< 1.0 || fPeriod
> fLife
)
1745 PushIllegalArgument();
1747 PushDouble(ScGetDDB(fCost
, fSalvage
, fLife
, fPeriod
, fFactor
));
1750 void ScInterpreter::ScDB()
1752 nFuncFmtType
= SvNumFormatType::CURRENCY
;
1753 sal_uInt8 nParamCount
= GetByte();
1754 if ( !MustHaveParamCount( nParamCount
, 4, 5 ) )
1756 double fMonths
= nParamCount
== 4 ? 12.0 : ::rtl::math::approxFloor(GetDouble());
1757 double fPeriod
= GetDouble();
1758 double fLife
= GetDouble();
1759 double fSalvage
= GetDouble();
1760 double fCost
= GetDouble();
1761 if (fMonths
< 1.0 || fMonths
> 12.0 || fLife
> 1200.0 || fSalvage
< 0.0 ||
1762 fPeriod
> (fLife
+ 1.0) || fSalvage
> fCost
|| fCost
<= 0.0 ||
1763 fLife
<= 0 || fPeriod
<= 0 )
1765 PushIllegalArgument();
1768 double fOffRate
= 1.0 - pow(fSalvage
/ fCost
, 1.0 / fLife
);
1769 fOffRate
= ::rtl::math::approxFloor((fOffRate
* 1000.0) + 0.5) / 1000.0;
1770 double fFirstOffRate
= fCost
* fOffRate
* fMonths
/ 12.0;
1772 if (::rtl::math::approxFloor(fPeriod
) == 1)
1773 fDb
= fFirstOffRate
;
1776 KahanSum fSumOffRate
= fFirstOffRate
;
1777 double fMin
= fLife
;
1778 if (fMin
> fPeriod
) fMin
= fPeriod
;
1779 sal_uInt16 iMax
= static_cast<sal_uInt16
>(::rtl::math::approxFloor(fMin
));
1780 for (sal_uInt16 i
= 2; i
<= iMax
; i
++)
1782 fDb
= -(fSumOffRate
- fCost
).get() * fOffRate
;
1785 if (fPeriod
> fLife
)
1786 fDb
= -(fSumOffRate
- fCost
).get() * fOffRate
* (12.0 - fMonths
) / 12.0;
1791 double ScInterpreter::ScInterVDB(double fCost
, double fSalvage
, double fLife
,
1792 double fLife1
, double fPeriod
, double fFactor
)
1794 KahanSum fVdb
= 0.0;
1795 double fIntEnd
= ::rtl::math::approxCeil(fPeriod
);
1796 sal_uLong nLoopEnd
= static_cast<sal_uLong
>(fIntEnd
);
1798 double fTerm
, fSln
= 0; // SLN: Straight-Line Depreciation
1799 double fSalvageValue
= fCost
- fSalvage
;
1800 bool bNowSln
= false;
1804 for ( i
= 1; i
<= nLoopEnd
; i
++)
1808 fDdb
= ScGetDDB(fCost
, fSalvage
, fLife
, static_cast<double>(i
), fFactor
);
1809 fSln
= fSalvageValue
/ (fLife1
- static_cast<double>(i
-1));
1819 fSalvageValue
-= fDdb
;
1828 fTerm
*= ( fPeriod
+ 1.0 - fIntEnd
);
1835 void ScInterpreter::ScVDB()
1837 nFuncFmtType
= SvNumFormatType::CURRENCY
;
1838 sal_uInt8 nParamCount
= GetByte();
1839 if ( !MustHaveParamCount( nParamCount
, 5, 7 ) )
1842 KahanSum fVdb
= 0.0;
1843 bool bNoSwitch
= nParamCount
== 7 && GetBool();
1844 double fFactor
= nParamCount
>= 6 ? GetDouble() : 2.0;
1845 double fEnd
= GetDouble();
1846 double fStart
= GetDouble();
1847 double fLife
= GetDouble();
1848 double fSalvage
= GetDouble();
1849 double fCost
= GetDouble();
1850 if (fStart
< 0.0 || fEnd
< fStart
|| fEnd
> fLife
|| fCost
< 0.0
1851 || fSalvage
> fCost
|| fFactor
<= 0.0)
1852 PushIllegalArgument();
1855 double fIntStart
= ::rtl::math::approxFloor(fStart
);
1856 double fIntEnd
= ::rtl::math::approxCeil(fEnd
);
1857 sal_uLong nLoopStart
= static_cast<sal_uLong
>(fIntStart
);
1858 sal_uLong nLoopEnd
= static_cast<sal_uLong
>(fIntEnd
);
1862 for (sal_uLong i
= nLoopStart
+ 1; i
<= nLoopEnd
; i
++)
1864 double fTerm
= ScGetDDB(fCost
, fSalvage
, fLife
, static_cast<double>(i
), fFactor
);
1866 //respect partial period in the Beginning/ End:
1867 if ( i
== nLoopStart
+1 )
1868 fTerm
*= ( std::min( fEnd
, fIntStart
+ 1.0 ) - fStart
);
1869 else if ( i
== nLoopEnd
)
1870 fTerm
*= ( fEnd
+ 1.0 - fIntEnd
);
1878 // respect partial period in the Beginning / End:
1879 if ( !::rtl::math::approxEqual( fStart
, fIntStart
) ||
1880 !::rtl::math::approxEqual( fEnd
, fIntEnd
) )
1882 if ( !::rtl::math::approxEqual( fStart
, fIntStart
) )
1884 // part to be subtracted at the beginning
1885 double fTempIntEnd
= fIntStart
+ 1.0;
1886 double fTempValue
= fCost
-
1887 ScInterVDB( fCost
, fSalvage
, fLife
, fLife
, fIntStart
, fFactor
);
1888 fPart
+= ( fStart
- fIntStart
) *
1889 ScInterVDB( fTempValue
, fSalvage
, fLife
, fLife
- fIntStart
,
1890 fTempIntEnd
- fIntStart
, fFactor
);
1892 if ( !::rtl::math::approxEqual( fEnd
, fIntEnd
) )
1894 // part to be subtracted at the end
1895 double fTempIntStart
= fIntEnd
- 1.0;
1896 double fTempValue
= fCost
-
1897 ScInterVDB( fCost
, fSalvage
, fLife
, fLife
, fTempIntStart
, fFactor
);
1898 fPart
+= ( fIntEnd
- fEnd
) *
1899 ScInterVDB( fTempValue
, fSalvage
, fLife
, fLife
- fTempIntStart
,
1900 fIntEnd
- fTempIntStart
, fFactor
);
1903 // calculate depreciation for whole periods
1904 fCost
-= ScInterVDB( fCost
, fSalvage
, fLife
, fLife
, fIntStart
, fFactor
);
1905 fVdb
= ScInterVDB( fCost
, fSalvage
, fLife
, fLife
- fIntStart
,
1906 fIntEnd
- fIntStart
, fFactor
);
1910 PushDouble(fVdb
.get());
1913 void ScInterpreter::ScPDuration()
1915 if ( MustHaveParamCount( GetByte(), 3 ) )
1917 double fFuture
= GetDouble();
1918 double fPresent
= GetDouble();
1919 double fRate
= GetDouble();
1920 if ( fFuture
<= 0.0 || fPresent
<= 0.0 || fRate
<= 0.0 )
1921 PushIllegalArgument();
1923 PushDouble( std::log( fFuture
/ fPresent
) / std::log1p( fRate
) );
1927 void ScInterpreter::ScSLN()
1929 nFuncFmtType
= SvNumFormatType::CURRENCY
;
1930 if ( MustHaveParamCount( GetByte(), 3 ) )
1932 double fLife
= GetDouble();
1933 double fSalvage
= GetDouble();
1934 double fCost
= GetDouble();
1935 PushDouble( div( fCost
- fSalvage
, fLife
) );
1939 double ScInterpreter::ScGetPMT(double fRate
, double fNper
, double fPv
,
1940 double fFv
, bool bPayInAdvance
)
1944 fPayment
= (fPv
+ fFv
) / fNper
;
1947 if (bPayInAdvance
) // payment in advance
1948 fPayment
= (fFv
+ fPv
* exp( fNper
* ::std::log1p(fRate
) ) ) * fRate
/
1949 (std::expm1( (fNper
+ 1) * ::std::log1p(fRate
) ) - fRate
);
1950 else // payment in arrear
1951 fPayment
= (fFv
+ fPv
* exp(fNper
* ::std::log1p(fRate
) ) ) * fRate
/
1952 std::expm1( fNper
* ::std::log1p(fRate
) );
1957 void ScInterpreter::ScPMT()
1959 nFuncFmtType
= SvNumFormatType::CURRENCY
;
1960 sal_uInt8 nParamCount
= GetByte();
1961 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
1963 bool bPayInAdvance
= nParamCount
== 5 && GetBool();
1964 double fFv
= nParamCount
>= 4 ? GetDouble() : 0;
1965 double fPv
= GetDouble();
1966 double fNper
= GetDouble();
1967 double fRate
= GetDouble();
1968 PushDouble(ScGetPMT(fRate
, fNper
, fPv
, fFv
, bPayInAdvance
));
1971 void ScInterpreter::ScRRI()
1973 nFuncFmtType
= SvNumFormatType::PERCENT
;
1974 if ( MustHaveParamCount( GetByte(), 3 ) )
1976 double fFutureValue
= GetDouble();
1977 double fPresentValue
= GetDouble();
1978 double fNrOfPeriods
= GetDouble();
1979 if ( fNrOfPeriods
<= 0.0 || fPresentValue
== 0.0 )
1980 PushIllegalArgument();
1982 PushDouble(pow(fFutureValue
/ fPresentValue
, 1.0 / fNrOfPeriods
) - 1.0);
1986 double ScInterpreter::ScGetFV(double fRate
, double fNper
, double fPmt
,
1987 double fPv
, bool bPayInAdvance
)
1991 fFv
= fPv
+ fPmt
* fNper
;
1994 double fTerm
= pow(1.0 + fRate
, fNper
);
1996 fFv
= fPv
* fTerm
+ fPmt
*(1.0 + fRate
)*(fTerm
- 1.0)/fRate
;
1998 fFv
= fPv
* fTerm
+ fPmt
*(fTerm
- 1.0)/fRate
;
2003 void ScInterpreter::ScFV()
2005 nFuncFmtType
= SvNumFormatType::CURRENCY
;
2006 sal_uInt8 nParamCount
= GetByte();
2007 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
2009 bool bPayInAdvance
= nParamCount
== 5 && GetBool();
2010 double fPv
= nParamCount
>= 4 ? GetDouble() : 0;
2011 double fPmt
= GetDouble();
2012 double fNper
= GetDouble();
2013 double fRate
= GetDouble();
2014 PushDouble(ScGetFV(fRate
, fNper
, fPmt
, fPv
, bPayInAdvance
));
2017 void ScInterpreter::ScNper()
2019 sal_uInt8 nParamCount
= GetByte();
2020 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
2022 bool bPayInAdvance
= nParamCount
== 5 && GetBool();
2023 double fFV
= nParamCount
>= 4 ? GetDouble() : 0;
2024 double fPV
= GetDouble(); // Present Value
2025 double fPmt
= GetDouble(); // Payment
2026 double fRate
= GetDouble();
2027 // Note that due to the function specification in ODFF1.2 (and Excel) the
2028 // amount to be paid to get from fPV to fFV is fFV_+_fPV.
2029 if ( fPV
+ fFV
== 0.0 )
2031 else if (fRate
== 0.0)
2032 PushDouble(-(fPV
+ fFV
)/fPmt
);
2033 else if (bPayInAdvance
)
2034 PushDouble(log(-(fRate
*fFV
-fPmt
*(1.0+fRate
))/(fRate
*fPV
+fPmt
*(1.0+fRate
)))
2035 / std::log1p(fRate
));
2037 PushDouble(log(-(fRate
*fFV
-fPmt
)/(fRate
*fPV
+fPmt
)) / std::log1p(fRate
));
2040 bool ScInterpreter::RateIteration( double fNper
, double fPayment
, double fPv
,
2041 double fFv
, bool bPayType
, double & fGuess
)
2043 // See also #i15090#
2044 // Newton-Raphson method: x(i+1) = x(i) - f(x(i)) / f'(x(i))
2045 // This solution handles integer and non-integer values of Nper different.
2046 // If ODFF will constraint Nper to integer, the distinction of cases can be
2047 // removed; only the integer-part is needed then.
2048 bool bValid
= true, bFound
= false;
2049 double fX
, fXnew
, fTerm
, fTermDerivation
;
2050 double fGeoSeries
, fGeoSeriesDerivation
;
2051 const sal_uInt16 nIterationsMax
= 150;
2052 sal_uInt16 nCount
= 0;
2053 const double fEpsilonSmall
= 1.0E-14;
2056 // payment at beginning of each period
2057 fFv
= fFv
- fPayment
;
2058 fPv
= fPv
+ fPayment
;
2060 if (fNper
== ::rtl::math::round( fNper
))
2061 { // Nper is an integer value
2063 while (!bFound
&& nCount
< nIterationsMax
)
2065 double fPowN
, fPowNminus1
; // for (1.0+fX)^Nper and (1.0+fX)^(Nper-1)
2066 fPowNminus1
= pow( 1.0+fX
, fNper
-1.0);
2067 fPowN
= fPowNminus1
* (1.0+fX
);
2071 fGeoSeriesDerivation
= fNper
* (fNper
-1.0)/2.0;
2075 fGeoSeries
= (fPowN
-1.0)/fX
;
2076 fGeoSeriesDerivation
= fNper
* fPowNminus1
/ fX
- fGeoSeries
/ fX
;
2078 fTerm
= fFv
+ fPv
*fPowN
+ fPayment
* fGeoSeries
;
2079 fTermDerivation
= fPv
* fNper
* fPowNminus1
+ fPayment
* fGeoSeriesDerivation
;
2080 if (std::abs(fTerm
) < fEpsilonSmall
)
2081 bFound
= true; // will catch root which is at an extreme
2084 if (fTermDerivation
== 0.0)
2085 fXnew
= fX
+ 1.1 * SCdEpsilon
; // move away from zero slope
2087 fXnew
= fX
- fTerm
/ fTermDerivation
;
2089 // more accuracy not possible in oscillating cases
2090 bFound
= (std::abs(fXnew
- fX
) < SCdEpsilon
);
2094 // Gnumeric returns roots < -1, Excel gives an error in that cases,
2095 // ODFF says nothing about it. Enable the statement, if you want Excel's
2097 //bValid =(fX >=-1.0);
2098 // Update 2013-06-17: Gnumeric (v1.12.2) doesn't return roots <= -1
2100 bValid
= (fX
> -1.0);
2103 { // Nper is not an integer value.
2104 fX
= (fGuess
< -1.0) ? -1.0 : fGuess
; // start with a valid fX
2105 while (bValid
&& !bFound
&& nCount
< nIterationsMax
)
2110 fGeoSeriesDerivation
= fNper
* (fNper
-1.0)/2.0;
2114 fGeoSeries
= (pow( 1.0+fX
, fNper
) - 1.0) / fX
;
2115 fGeoSeriesDerivation
= fNper
* pow( 1.0+fX
, fNper
-1.0) / fX
- fGeoSeries
/ fX
;
2117 fTerm
= fFv
+ fPv
*pow(1.0 + fX
,fNper
)+ fPayment
* fGeoSeries
;
2118 fTermDerivation
= fPv
* fNper
* pow( 1.0+fX
, fNper
-1.0) + fPayment
* fGeoSeriesDerivation
;
2119 if (std::abs(fTerm
) < fEpsilonSmall
)
2120 bFound
= true; // will catch root which is at an extreme
2123 if (fTermDerivation
== 0.0)
2124 fXnew
= fX
+ 1.1 * SCdEpsilon
; // move away from zero slope
2126 fXnew
= fX
- fTerm
/ fTermDerivation
;
2128 // more accuracy not possible in oscillating cases
2129 bFound
= (std::abs(fXnew
- fX
) < SCdEpsilon
);
2131 bValid
= (fX
>= -1.0); // otherwise pow(1.0+fX,fNper) will fail
2135 fGuess
= fX
; // return approximate root
2136 return bValid
&& bFound
;
2139 // In Calc UI it is the function RATE(Nper;Pmt;Pv;Fv;Type;Guess)
2140 void ScInterpreter::ScRate()
2142 nFuncFmtType
= SvNumFormatType::PERCENT
;
2143 sal_uInt8 nParamCount
= GetByte();
2144 if ( !MustHaveParamCount( nParamCount
, 3, 6 ) )
2147 // defaults for missing arguments, see ODFF spec
2148 double fGuess
= nParamCount
== 6 ? GetDouble() : 0.1;
2149 bool bDefaultGuess
= nParamCount
!= 6;
2150 bool bPayType
= nParamCount
>= 5 && GetBool();
2151 double fFv
= nParamCount
>= 4 ? GetDouble() : 0;
2152 double fPv
= GetDouble();
2153 double fPayment
= GetDouble();
2154 double fNper
= GetDouble();
2155 double fOrigGuess
= fGuess
;
2157 if (fNper
<= 0.0) // constraint from ODFF spec
2159 PushIllegalArgument();
2162 bool bValid
= RateIteration(fNper
, fPayment
, fPv
, fFv
, bPayType
, fGuess
);
2166 /* TODO: try also for specified guess values, not only default? As is,
2167 * a specified 0.1 guess may be error result but a default 0.1 guess
2168 * may succeed. On the other hand, using a different guess value than
2169 * the specified one may not be desired, even if that didn't match. */
2172 /* TODO: this is rather ugly, instead of looping over different
2173 * guess values and doing a Newton goal seek for each we could
2174 * first insert the values into the RATE equation to obtain a set
2175 * of y values and then do a bisecting goal seek, possibly using
2176 * different algorithms. */
2177 double fX
= fOrigGuess
;
2178 for (int nStep
= 2; nStep
<= 10 && !bValid
; ++nStep
)
2180 fGuess
= fX
* nStep
;
2181 bValid
= RateIteration( fNper
, fPayment
, fPv
, fFv
, bPayType
, fGuess
);
2184 fGuess
= fX
/ nStep
;
2185 bValid
= RateIteration( fNper
, fPayment
, fPv
, fFv
, bPayType
, fGuess
);
2190 SetError(FormulaError::NoConvergence
);
2195 double ScInterpreter::ScGetIpmt(double fRate
, double fPer
, double fNper
, double fPv
,
2196 double fFv
, bool bPayInAdvance
, double& fPmt
)
2198 fPmt
= ScGetPMT(fRate
, fNper
, fPv
, fFv
, bPayInAdvance
); // for PPMT also if fPer == 1
2200 nFuncFmtType
= SvNumFormatType::CURRENCY
;
2202 fIpmt
= bPayInAdvance
? 0.0 : -fPv
;
2206 fIpmt
= ScGetFV(fRate
, fPer
-2.0, fPmt
, fPv
, true) - fPmt
;
2208 fIpmt
= ScGetFV(fRate
, fPer
-1.0, fPmt
, fPv
, false);
2210 return fIpmt
* fRate
;
2213 void ScInterpreter::ScIpmt()
2215 nFuncFmtType
= SvNumFormatType::CURRENCY
;
2216 sal_uInt8 nParamCount
= GetByte();
2217 if ( !MustHaveParamCount( nParamCount
, 4, 6 ) )
2219 bool bPayInAdvance
= nParamCount
== 6 && GetBool();
2220 double fFv
= nParamCount
>= 5 ? GetDouble() : 0;
2221 double fPv
= GetDouble();
2222 double fNper
= GetDouble();
2223 double fPer
= GetDouble();
2224 double fRate
= GetDouble();
2225 if (fPer
< 1.0 || fPer
> fNper
)
2226 PushIllegalArgument();
2230 PushDouble(ScGetIpmt(fRate
, fPer
, fNper
, fPv
, fFv
, bPayInAdvance
, fPmt
));
2234 void ScInterpreter::ScPpmt()
2236 nFuncFmtType
= SvNumFormatType::CURRENCY
;
2237 sal_uInt8 nParamCount
= GetByte();
2238 if ( !MustHaveParamCount( nParamCount
, 4, 6 ) )
2240 bool bPayInAdvance
= nParamCount
== 6 && GetBool();
2241 double fFv
= nParamCount
>= 5 ? GetDouble() : 0;
2242 double fPv
= GetDouble();
2243 double fNper
= GetDouble();
2244 double fPer
= GetDouble();
2245 double fRate
= GetDouble();
2246 if (fPer
< 1.0 || fPer
> fNper
)
2247 PushIllegalArgument();
2251 double fInterestPer
= ScGetIpmt(fRate
, fPer
, fNper
, fPv
, fFv
, bPayInAdvance
, fPmt
);
2252 PushDouble(fPmt
- fInterestPer
);
2256 void ScInterpreter::ScCumIpmt()
2258 nFuncFmtType
= SvNumFormatType::CURRENCY
;
2259 if ( !MustHaveParamCount( GetByte(), 6 ) )
2262 double fFlag
= GetDoubleWithDefault( -1.0 );
2263 double fEnd
= ::rtl::math::approxFloor(GetDouble());
2264 double fStart
= ::rtl::math::approxFloor(GetDouble());
2265 double fPv
= GetDouble();
2266 double fNper
= GetDouble();
2267 double fRate
= GetDouble();
2268 if (fStart
< 1.0 || fEnd
< fStart
|| fRate
<= 0.0 ||
2269 fEnd
> fNper
|| fNper
<= 0.0 || fPv
<= 0.0 ||
2270 ( fFlag
!= 0.0 && fFlag
!= 1.0 ))
2271 PushIllegalArgument();
2274 bool bPayInAdvance
= static_cast<bool>(fFlag
);
2275 sal_uLong nStart
= static_cast<sal_uLong
>(fStart
);
2276 sal_uLong nEnd
= static_cast<sal_uLong
>(fEnd
) ;
2277 double fPmt
= ScGetPMT(fRate
, fNper
, fPv
, 0.0, bPayInAdvance
);
2278 KahanSum fIpmt
= 0.0;
2285 for (sal_uLong i
= nStart
; i
<= nEnd
; i
++)
2288 fIpmt
+= ScGetFV(fRate
, static_cast<double>(i
-2), fPmt
, fPv
, true) - fPmt
;
2290 fIpmt
+= ScGetFV(fRate
, static_cast<double>(i
-1), fPmt
, fPv
, false);
2293 PushDouble(fIpmt
.get());
2297 void ScInterpreter::ScCumPrinc()
2299 nFuncFmtType
= SvNumFormatType::CURRENCY
;
2300 if ( !MustHaveParamCount( GetByte(), 6 ) )
2303 double fFlag
= GetDoubleWithDefault( -1.0 );
2304 double fEnd
= ::rtl::math::approxFloor(GetDouble());
2305 double fStart
= ::rtl::math::approxFloor(GetDouble());
2306 double fPv
= GetDouble();
2307 double fNper
= GetDouble();
2308 double fRate
= GetDouble();
2309 if (fStart
< 1.0 || fEnd
< fStart
|| fRate
<= 0.0 ||
2310 fEnd
> fNper
|| fNper
<= 0.0 || fPv
<= 0.0 ||
2311 ( fFlag
!= 0.0 && fFlag
!= 1.0 ))
2312 PushIllegalArgument();
2315 bool bPayInAdvance
= static_cast<bool>(fFlag
);
2316 double fPmt
= ScGetPMT(fRate
, fNper
, fPv
, 0.0, bPayInAdvance
);
2317 KahanSum fPpmt
= 0.0;
2318 sal_uLong nStart
= static_cast<sal_uLong
>(fStart
);
2319 sal_uLong nEnd
= static_cast<sal_uLong
>(fEnd
);
2322 fPpmt
= bPayInAdvance
? fPmt
: fPmt
+ fPv
* fRate
;
2325 for (sal_uLong i
= nStart
; i
<= nEnd
; i
++)
2328 fPpmt
+= fPmt
- (ScGetFV(fRate
, static_cast<double>(i
-2), fPmt
, fPv
, true) - fPmt
) * fRate
;
2330 fPpmt
+= fPmt
- ScGetFV(fRate
, static_cast<double>(i
-1), fPmt
, fPv
, false) * fRate
;
2332 PushDouble(fPpmt
.get());
2336 void ScInterpreter::ScEffect()
2338 nFuncFmtType
= SvNumFormatType::PERCENT
;
2339 if ( !MustHaveParamCount( GetByte(), 2 ) )
2342 double fPeriods
= GetDouble();
2343 double fNominal
= GetDouble();
2344 if (fPeriods
< 1.0 || fNominal
< 0.0)
2345 PushIllegalArgument();
2346 else if ( fNominal
== 0.0 )
2350 fPeriods
= ::rtl::math::approxFloor(fPeriods
);
2351 PushDouble(pow(1.0 + fNominal
/fPeriods
, fPeriods
) - 1.0);
2355 void ScInterpreter::ScNominal()
2357 nFuncFmtType
= SvNumFormatType::PERCENT
;
2358 if ( MustHaveParamCount( GetByte(), 2 ) )
2360 double fPeriods
= GetDouble();
2361 double fEffective
= GetDouble();
2362 if (fPeriods
< 1.0 || fEffective
<= 0.0)
2363 PushIllegalArgument();
2366 fPeriods
= ::rtl::math::approxFloor(fPeriods
);
2367 PushDouble( (pow(fEffective
+ 1.0, 1.0 / fPeriods
) - 1.0) * fPeriods
);
2372 void ScInterpreter::ScMod()
2374 if ( !MustHaveParamCount( GetByte(), 2 ) )
2377 double fDenom
= GetDouble(); // Denominator
2378 if ( fDenom
== 0.0 )
2380 PushError(FormulaError::DivisionByZero
);
2383 double fNum
= GetDouble(); // Numerator
2384 double fRes
= ::rtl::math::approxSub( fNum
,
2385 ::rtl::math::approxFloor( fNum
/ fDenom
) * fDenom
);
2386 if ( ( fDenom
> 0 && fRes
>= 0 && fRes
< fDenom
) ||
2387 ( fDenom
< 0 && fRes
<= 0 && fRes
> fDenom
) )
2390 PushError( FormulaError::NoValue
);
2393 void ScInterpreter::ScIntersect()
2395 formula::FormulaConstTokenRef p2nd
= PopToken();
2396 formula::FormulaConstTokenRef p1st
= PopToken();
2398 if (nGlobalError
!= FormulaError::NONE
|| !p2nd
|| !p1st
)
2400 PushIllegalArgument();
2404 StackVar sv1
= p1st
->GetType();
2405 StackVar sv2
= p2nd
->GetType();
2406 if ((sv1
!= svSingleRef
&& sv1
!= svDoubleRef
&& sv1
!= svRefList
) ||
2407 (sv2
!= svSingleRef
&& sv2
!= svDoubleRef
&& sv2
!= svRefList
))
2409 PushIllegalArgument();
2413 const formula::FormulaToken
* x1
= p1st
.get();
2414 const formula::FormulaToken
* x2
= p2nd
.get();
2415 if (sv1
== svRefList
|| sv2
== svRefList
)
2417 // Now this is a bit nasty but it simplifies things, and having
2418 // intersections with lists isn't too common, if at all...
2419 // Convert a reference to list.
2420 const formula::FormulaToken
* xt
[2] = { x1
, x2
};
2421 StackVar sv
[2] = { sv1
, sv2
};
2422 // There may only be one reference; the other is necessarily a list
2423 // Ensure converted list proper destruction
2424 std::unique_ptr
<formula::FormulaToken
> p
;
2425 for (size_t i
=0; i
<2; ++i
)
2427 if (sv
[i
] == svSingleRef
)
2429 ScComplexRefData aRef
;
2430 aRef
.Ref1
= aRef
.Ref2
= *xt
[i
]->GetSingleRef();
2431 p
.reset(new ScRefListToken
);
2432 p
->GetRefList()->push_back( aRef
);
2435 else if (sv
[i
] == svDoubleRef
)
2437 ScComplexRefData aRef
= *xt
[i
]->GetDoubleRef();
2438 p
.reset(new ScRefListToken
);
2439 p
->GetRefList()->push_back( aRef
);
2446 ScTokenRef xRes
= new ScRefListToken
;
2447 ScRefList
* pRefList
= xRes
->GetRefList();
2448 for (const auto& rRef1
: *x1
->GetRefList())
2450 const ScAddress r11
= rRef1
.Ref1
.toAbs(mrDoc
, aPos
);
2451 const ScAddress r12
= rRef1
.Ref2
.toAbs(mrDoc
, aPos
);
2452 for (const auto& rRef2
: *x2
->GetRefList())
2454 const ScAddress r21
= rRef2
.Ref1
.toAbs(mrDoc
, aPos
);
2455 const ScAddress r22
= rRef2
.Ref2
.toAbs(mrDoc
, aPos
);
2456 SCCOL nCol1
= ::std::max( r11
.Col(), r21
.Col());
2457 SCROW nRow1
= ::std::max( r11
.Row(), r21
.Row());
2458 SCTAB nTab1
= ::std::max( r11
.Tab(), r21
.Tab());
2459 SCCOL nCol2
= ::std::min( r12
.Col(), r22
.Col());
2460 SCROW nRow2
= ::std::min( r12
.Row(), r22
.Row());
2461 SCTAB nTab2
= ::std::min( r12
.Tab(), r22
.Tab());
2462 if (nCol2
< nCol1
|| nRow2
< nRow1
|| nTab2
< nTab1
)
2466 ScComplexRefData aRef
;
2467 aRef
.InitRange( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
2468 pRefList
->push_back( aRef
);
2472 size_t n
= pRefList
->size();
2474 PushError( FormulaError::NoCode
);
2477 const ScComplexRefData
& rRef
= (*pRefList
)[0];
2478 if (rRef
.Ref1
== rRef
.Ref2
)
2479 PushTempToken( new ScSingleRefToken(mrDoc
.GetSheetLimits(), rRef
.Ref1
));
2481 PushTempToken( new ScDoubleRefToken(mrDoc
.GetSheetLimits(), rRef
));
2484 PushTokenRef( xRes
);
2488 const formula::FormulaToken
* pt
[2] = { x1
, x2
};
2489 StackVar sv
[2] = { sv1
, sv2
};
2490 SCCOL nC1
[2], nC2
[2];
2491 SCROW nR1
[2], nR2
[2];
2492 SCTAB nT1
[2], nT2
[2];
2493 for (size_t i
=0; i
<2; ++i
)
2501 const ScAddress r
= pt
[i
]->GetSingleRef()->toAbs(mrDoc
, aPos
);
2506 if (sv
[i
] == svDoubleRef
)
2508 const ScAddress r
= pt
[i
]->GetSingleRef2()->toAbs(mrDoc
, aPos
);
2522 ; // nothing, prevent compiler warning
2525 SCCOL nCol1
= ::std::max( nC1
[0], nC1
[1]);
2526 SCROW nRow1
= ::std::max( nR1
[0], nR1
[1]);
2527 SCTAB nTab1
= ::std::max( nT1
[0], nT1
[1]);
2528 SCCOL nCol2
= ::std::min( nC2
[0], nC2
[1]);
2529 SCROW nRow2
= ::std::min( nR2
[0], nR2
[1]);
2530 SCTAB nTab2
= ::std::min( nT2
[0], nT2
[1]);
2531 if (nCol2
< nCol1
|| nRow2
< nRow1
|| nTab2
< nTab1
)
2532 PushError( FormulaError::NoCode
);
2533 else if (nCol2
== nCol1
&& nRow2
== nRow1
&& nTab2
== nTab1
)
2534 PushSingleRef( nCol1
, nRow1
, nTab1
);
2536 PushDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
2540 void ScInterpreter::ScRangeFunc()
2542 formula::FormulaConstTokenRef x2
= PopToken();
2543 formula::FormulaConstTokenRef x1
= PopToken();
2545 if (nGlobalError
!= FormulaError::NONE
|| !x2
|| !x1
)
2547 PushIllegalArgument();
2550 // We explicitly tell extendRangeReference() to not reuse the token,
2551 // casting const away spares two clones.
2552 FormulaTokenRef xRes
= extendRangeReference(
2553 mrDoc
.GetSheetLimits(), const_cast<FormulaToken
&>(*x1
), const_cast<FormulaToken
&>(*x2
), aPos
, false);
2555 PushIllegalArgument();
2557 PushTokenRef( xRes
);
2560 void ScInterpreter::ScUnionFunc()
2562 formula::FormulaConstTokenRef p2nd
= PopToken();
2563 formula::FormulaConstTokenRef p1st
= PopToken();
2565 if (nGlobalError
!= FormulaError::NONE
|| !p2nd
|| !p1st
)
2567 PushIllegalArgument();
2571 StackVar sv1
= p1st
->GetType();
2572 StackVar sv2
= p2nd
->GetType();
2573 if ((sv1
!= svSingleRef
&& sv1
!= svDoubleRef
&& sv1
!= svRefList
) ||
2574 (sv2
!= svSingleRef
&& sv2
!= svDoubleRef
&& sv2
!= svRefList
))
2576 PushIllegalArgument();
2580 const formula::FormulaToken
* x1
= p1st
.get();
2581 const formula::FormulaToken
* x2
= p2nd
.get();
2584 // Append to an existing RefList if there is one.
2585 if (sv1
== svRefList
)
2588 sv1
= svUnknown
; // mark as handled
2590 else if (sv2
== svRefList
)
2593 sv2
= svUnknown
; // mark as handled
2596 xRes
= new ScRefListToken
;
2597 ScRefList
* pRes
= xRes
->GetRefList();
2598 const formula::FormulaToken
* pt
[2] = { x1
, x2
};
2599 StackVar sv
[2] = { sv1
, sv2
};
2600 for (size_t i
=0; i
<2; ++i
)
2608 ScComplexRefData aRef
;
2609 aRef
.Ref1
= aRef
.Ref2
= *pt
[i
]->GetSingleRef();
2610 pRes
->push_back( aRef
);
2614 pRes
->push_back( *pt
[i
]->GetDoubleRef());
2618 const ScRefList
* p
= pt
[i
]->GetRefList();
2619 for (const auto& rRef
: *p
)
2621 pRes
->push_back( rRef
);
2626 ; // nothing, prevent compiler warning
2629 ValidateRef( *pRes
); // set #REF! if needed
2630 PushTokenRef( xRes
);
2633 void ScInterpreter::ScCurrent()
2635 FormulaConstTokenRef
xTok( PopToken());
2638 PushTokenRef( xTok
);
2639 PushTokenRef( xTok
);
2642 PushError( FormulaError::UnknownStackVariable
);
2645 void ScInterpreter::ScStyle()
2647 sal_uInt8 nParamCount
= GetByte();
2648 if (!MustHaveParamCount(nParamCount
, 1, 3))
2651 OUString aStyle2
; // Style after timer
2652 if (nParamCount
>= 3)
2653 aStyle2
= GetString().getString();
2654 tools::Long nTimeOut
= 0; // timeout
2655 if (nParamCount
>= 2)
2656 nTimeOut
= static_cast<tools::Long
>(GetDouble()*1000.0);
2657 OUString aStyle1
= GetString().getString(); // Style for immediate
2662 // Execute request to apply style
2663 if ( !mrDoc
.IsClipOrUndo() )
2665 ScDocShell
* pShell
= mrDoc
.GetDocumentShell();
2668 // Normalize style names right here, making sure that character case is correct,
2669 // and that we only apply anything when there's something to apply
2670 auto pPool
= mrDoc
.GetStyleSheetPool();
2671 if (!aStyle1
.isEmpty())
2673 if (auto pNewStyle
= pPool
->FindAutoStyle(aStyle1
))
2674 aStyle1
= pNewStyle
->GetName();
2678 if (!aStyle2
.isEmpty())
2680 if (auto pNewStyle
= pPool
->FindAutoStyle(aStyle2
))
2681 aStyle2
= pNewStyle
->GetName();
2685 // notify object shell directly!
2686 if (!aStyle1
.isEmpty() || !aStyle2
.isEmpty())
2688 const ScStyleSheet
* pStyle
= mrDoc
.GetStyle(aPos
.Col(), aPos
.Row(), aPos
.Tab());
2690 const bool bNotify
= !pStyle
2691 || (!aStyle1
.isEmpty() && pStyle
->GetName() != aStyle1
)
2692 || (!aStyle2
.isEmpty() && pStyle
->GetName() != aStyle2
);
2695 ScRange
aRange(aPos
);
2696 ScAutoStyleHint
aHint(aRange
, aStyle1
, nTimeOut
, aStyle2
);
2697 pShell
->Broadcast(aHint
);
2706 static ScDdeLink
* lcl_GetDdeLink( const sfx2::LinkManager
* pLinkMgr
,
2707 std::u16string_view rA
, std::u16string_view rT
, std::u16string_view rI
, sal_uInt8 nM
)
2709 size_t nCount
= pLinkMgr
->GetLinks().size();
2710 for (size_t i
=0; i
<nCount
; i
++ )
2712 ::sfx2::SvBaseLink
* pBase
= pLinkMgr
->GetLinks()[i
].get();
2713 if (ScDdeLink
* pLink
= dynamic_cast<ScDdeLink
*>(pBase
))
2715 if ( pLink
->GetAppl() == rA
&&
2716 pLink
->GetTopic() == rT
&&
2717 pLink
->GetItem() == rI
&&
2718 pLink
->GetMode() == nM
)
2726 void ScInterpreter::ScDde()
2728 // application, file, scope
2729 // application, Topic, Item
2731 sal_uInt8 nParamCount
= GetByte();
2732 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
2735 sal_uInt8 nMode
= SC_DDE_DEFAULT
;
2736 if (nParamCount
== 4)
2738 sal_uInt32 nTmp
= GetUInt32();
2739 if (nGlobalError
!= FormulaError::NONE
|| nTmp
> SAL_MAX_UINT8
)
2741 PushIllegalArgument();
2744 nMode
= static_cast<sal_uInt8
>(nTmp
);
2746 OUString aItem
= GetString().getString();
2747 OUString aTopic
= GetString().getString();
2748 OUString aAppl
= GetString().getString();
2750 if (nMode
> SC_DDE_TEXT
)
2751 nMode
= SC_DDE_DEFAULT
;
2753 // temporary documents (ScFunctionAccess) have no DocShell
2754 // and no LinkManager -> abort
2756 //sfx2::LinkManager* pLinkMgr = mrDoc.GetLinkManager();
2763 // Need to reinterpret after loading (build links)
2764 pArr
->AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT
);
2766 // while the link is not evaluated, idle must be disabled (to avoid circular references)
2768 bool bOldEnabled
= mrDoc
.IsIdleEnabled();
2769 mrDoc
.EnableIdle(false);
2771 // Get/ Create link object
2773 ScDdeLink
* pLink
= lcl_GetDdeLink( mpLinkManager
, aAppl
, aTopic
, aItem
, nMode
);
2775 //TODO: Save Dde-links (in addition) more efficient at document !!!!!
2776 // ScDdeLink* pLink = mrDoc.GetDdeLink( aAppl, aTopic, aItem );
2778 bool bWasError
= ( pMyFormulaCell
&& pMyFormulaCell
->GetRawError() != FormulaError::NONE
);
2782 pLink
= new ScDdeLink( mrDoc
, aAppl
, aTopic
, aItem
, nMode
);
2783 mpLinkManager
->InsertDDELink( pLink
, aAppl
, aTopic
, aItem
);
2784 if ( mpLinkManager
->GetLinks().size() == 1 ) // the first one?
2786 SfxBindings
* pBindings
= mrDoc
.GetViewBindings();
2788 pBindings
->Invalidate( SID_LINKS
); // Link-Manager enabled
2791 //if the document was just loaded, but the ScDdeLink entry was missing, then
2792 //don't update this link until the links are updated in response to the users
2794 if (!mrDoc
.HasLinkFormulaNeedingCheck())
2796 //TODO: evaluate asynchron ???
2797 pLink
->TryUpdate(); // TryUpdate doesn't call Update multiple times
2802 // StartListening after the Update to avoid circular references
2803 pMyFormulaCell
->StartListening( *pLink
);
2809 pMyFormulaCell
->StartListening( *pLink
);
2812 // If a new Error from Reschedule appears when the link is executed then reset the errorflag
2815 if ( pMyFormulaCell
&& pMyFormulaCell
->GetRawError() != FormulaError::NONE
&& !bWasError
)
2816 pMyFormulaCell
->SetErrCode(FormulaError::NONE
);
2820 const ScMatrix
* pLinkMat
= pLink
->GetResult();
2824 pLinkMat
->GetDimensions(nC
, nR
);
2825 ScMatrixRef pNewMat
= GetNewMat( nC
, nR
, /*bEmpty*/true);
2828 pLinkMat
->MatCopy(*pNewMat
); // copy
2829 PushMatrix( pNewMat
);
2832 PushIllegalArgument();
2837 mrDoc
.EnableIdle(bOldEnabled
);
2838 mpLinkManager
->CloseCachedComps();
2841 void ScInterpreter::ScBase()
2842 { // Value, Base [, MinLen]
2843 sal_uInt8 nParamCount
= GetByte();
2844 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
2847 static const sal_Unicode pDigits
[] = {
2848 '0','1','2','3','4','5','6','7','8','9',
2849 'A','B','C','D','E','F','G','H','I','J','K','L','M',
2850 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
2853 static const int nDigits
= SAL_N_ELEMENTS(pDigits
) - 1;
2855 if ( nParamCount
== 3 )
2857 double fLen
= ::rtl::math::approxFloor( GetDouble() );
2858 if ( 1.0 <= fLen
&& fLen
< SAL_MAX_UINT16
)
2859 nMinLen
= static_cast<sal_Int32
>(fLen
);
2861 nMinLen
= fLen
== 0.0 ? 1 : 0; // 0 means error
2865 double fBase
= ::rtl::math::approxFloor( GetDouble() );
2866 double fVal
= ::rtl::math::approxFloor( GetDouble() );
2867 double fChars
= ((fVal
> 0.0 && fBase
> 0.0) ?
2868 (ceil( log( fVal
) / log( fBase
) ) + 2.0) :
2870 if ( fChars
>= SAL_MAX_UINT16
)
2871 nMinLen
= 0; // Error
2873 if ( nGlobalError
== FormulaError::NONE
&& nMinLen
&& 2 <= fBase
&& fBase
<= nDigits
&& 0 <= fVal
)
2875 const sal_Int32 nConstBuf
= 128;
2876 sal_Unicode aBuf
[nConstBuf
];
2877 sal_Int32 nBuf
= std::max
<sal_Int32
>( fChars
, nMinLen
+ 1 );
2878 sal_Unicode
* pBuf
= (nBuf
<= nConstBuf
? aBuf
: new sal_Unicode
[nBuf
]);
2879 for ( sal_Int32 j
= 0; j
< nBuf
; ++j
)
2883 sal_Unicode
* p
= pBuf
+ nBuf
- 1;
2885 if ( o3tl::convertsToAtMost(fVal
, sal_uLong(~0)) )
2887 sal_uLong nVal
= static_cast<sal_uLong
>(fVal
);
2888 sal_uLong nBase
= static_cast<sal_uLong
>(fBase
);
2889 while ( nVal
&& p
> pBuf
)
2891 *--p
= pDigits
[ nVal
% nBase
];
2894 fVal
= static_cast<double>(nVal
);
2899 while ( fVal
&& p
> pBuf
)
2901 //TODO: roundoff error starting with numbers greater than 2**48
2902 // double fDig = ::rtl::math::approxFloor( fmod( fVal, fBase ) );
2903 // a little bit better:
2904 double fInt
= ::rtl::math::approxFloor( fVal
/ fBase
);
2905 double fMult
= fInt
* fBase
;
2907 // =BASIS(1e308;36) => GPF with
2908 // nDig = (size_t) ::rtl::math::approxFloor( fVal - fMult );
2909 // in spite off previous test if fVal >= fMult
2910 double fDebug1
= fVal
- fMult
;
2911 // fVal := 7,5975311883090e+290
2912 // fMult := 7,5975311883090e+290
2913 // fDebug1 := 1,3848924157003e+275 <- RoundOff-Error
2914 // fVal != fMult, aber: ::rtl::math::approxEqual( fVal, fMult ) == TRUE
2915 double fDebug2
= ::rtl::math::approxSub( fVal
, fMult
);
2916 // and ::rtl::math::approxSub( fVal, fMult ) == 0
2917 double fDebug3
= ( fInt
? fVal
/ fInt
: 0.0 );
2919 // Actual after strange fDebug1 and fVal < fMult is fDebug2 == fBase, but
2920 // anyway it can't be compared, then bDirt is executed an everything is good...
2922 // prevent compiler warnings
2923 (void)fDebug1
; (void)fDebug2
; (void)fDebug3
;
2927 { // something is wrong there
2933 double fDig
= ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal
, fMult
) );
2941 else if ( fDig
>= fBase
)
2942 nDig
= static_cast<size_t>(fBase
) - 1;
2944 nDig
= static_cast<size_t>(fDig
);
2946 *--p
= pDigits
[ nDig
];
2951 PushError( FormulaError::StringOverflow
);
2954 if ( nBuf
- (p
- pBuf
) <= nMinLen
)
2955 p
= pBuf
+ nBuf
- 1 - nMinLen
;
2956 PushStringBuffer( p
);
2962 PushIllegalArgument();
2965 void ScInterpreter::ScDecimal()
2967 if ( !MustHaveParamCount( GetByte(), 2 ) )
2970 double fBase
= ::rtl::math::approxFloor( GetDouble() );
2971 OUString aStr
= GetString().getString();
2972 if ( nGlobalError
== FormulaError::NONE
&& 2 <= fBase
&& fBase
<= 36 )
2975 int nBase
= static_cast<int>(fBase
);
2976 const sal_Unicode
* p
= aStr
.getStr();
2977 while ( *p
== ' ' || *p
== '\t' )
2978 p
++; // strip leading white space
2980 { // evtl. hex-prefix stripped
2981 if ( *p
== 'x' || *p
== 'X' )
2983 else if ( *p
== '0' && (*(p
+1) == 'x' || *(p
+1) == 'X') )
2989 if ( '0' <= *p
&& *p
<= '9' )
2991 else if ( 'A' <= *p
&& *p
<= 'Z' )
2992 n
= 10 + (*p
- 'A');
2993 else if ( 'a' <= *p
&& *p
<= 'z' )
2994 n
= 10 + (*p
- 'a');
3000 ( (nBase
== 2 && (*p
== 'b' || *p
== 'B'))
3001 ||(nBase
== 16 && (*p
== 'h' || *p
== 'H')) )
3003 ; // 101b and F00Dh are ok
3006 PushIllegalArgument();
3011 fVal
= fVal
* fBase
+ n
;
3018 PushIllegalArgument();
3021 void ScInterpreter::ScConvertOOo()
3022 { // Value, FromUnit, ToUnit
3023 if ( !MustHaveParamCount( GetByte(), 3 ) )
3026 OUString aToUnit
= GetString().getString();
3027 OUString aFromUnit
= GetString().getString();
3028 double fVal
= GetDouble();
3029 if ( nGlobalError
!= FormulaError::NONE
)
3030 PushError( nGlobalError
);
3033 // first of all search for the given order; if it can't be found then search for the inverse
3035 if ( ScGlobal::GetUnitConverter()->GetValue( fConv
, aFromUnit
, aToUnit
) )
3036 PushDouble( fVal
* fConv
);
3037 else if ( ScGlobal::GetUnitConverter()->GetValue( fConv
, aToUnit
, aFromUnit
) )
3038 PushDouble( fVal
/ fConv
);
3044 void ScInterpreter::ScRoman()
3046 sal_uInt8 nParamCount
= GetByte();
3047 if( !MustHaveParamCount( nParamCount
, 1, 2 ) )
3050 double fMode
= (nParamCount
== 2) ? ::rtl::math::approxFloor( GetDouble() ) : 0.0;
3051 double fVal
= ::rtl::math::approxFloor( GetDouble() );
3052 if( nGlobalError
!= FormulaError::NONE
)
3053 PushError( nGlobalError
);
3054 else if( (fMode
>= 0.0) && (fMode
< 5.0) && (fVal
>= 0.0) && (fVal
< 4000.0) )
3056 static const sal_Unicode pChars
[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
3057 static const sal_uInt16 pValues
[] = { 1000, 500, 100, 50, 10, 5, 1 };
3058 static const sal_uInt16 nMaxIndex
= sal_uInt16(SAL_N_ELEMENTS(pValues
) - 1);
3060 OUStringBuffer aRoman
;
3061 sal_uInt16 nVal
= static_cast<sal_uInt16
>(fVal
);
3062 sal_uInt16 nMode
= static_cast<sal_uInt16
>(fMode
);
3064 for( sal_uInt16 i
= 0; i
<= nMaxIndex
/ 2; i
++ )
3066 sal_uInt16 nIndex
= 2 * i
;
3067 sal_uInt16 nDigit
= nVal
/ pValues
[ nIndex
];
3069 if( (nDigit
% 5) == 4 )
3071 // assert can't happen with nVal<4000 precondition
3072 assert( ((nDigit
== 4) ? (nIndex
>= 1) : (nIndex
>= 2)));
3074 sal_uInt16 nIndex2
= (nDigit
== 4) ? nIndex
- 1 : nIndex
- 2;
3075 sal_uInt16 nSteps
= 0;
3076 while( (nSteps
< nMode
) && (nIndex
< nMaxIndex
) )
3079 if( pValues
[ nIndex2
] - pValues
[ nIndex
+ 1 ] <= nVal
)
3084 aRoman
.append( OUStringChar(pChars
[ nIndex
]) + OUStringChar(pChars
[ nIndex2
]) );
3085 nVal
= sal::static_int_cast
<sal_uInt16
>( nVal
+ pValues
[ nIndex
] );
3086 nVal
= sal::static_int_cast
<sal_uInt16
>( nVal
- pValues
[ nIndex2
] );
3092 // assert can't happen with nVal<4000 precondition
3093 assert( nIndex
>= 1 );
3094 aRoman
.append( pChars
[ nIndex
- 1 ] );
3096 sal_Int32 nPad
= nDigit
% 5;
3099 comphelper::string::padToLength(aRoman
, aRoman
.getLength() + nPad
,
3102 nVal
%= pValues
[ nIndex
];
3106 PushString( aRoman
.makeStringAndClear() );
3109 PushIllegalArgument();
3112 static bool lcl_GetArabicValue( sal_Unicode cChar
, sal_uInt16
& rnValue
, bool& rbIsDec
)
3116 case 'M': rnValue
= 1000; rbIsDec
= true; break;
3117 case 'D': rnValue
= 500; rbIsDec
= false; break;
3118 case 'C': rnValue
= 100; rbIsDec
= true; break;
3119 case 'L': rnValue
= 50; rbIsDec
= false; break;
3120 case 'X': rnValue
= 10; rbIsDec
= true; break;
3121 case 'V': rnValue
= 5; rbIsDec
= false; break;
3122 case 'I': rnValue
= 1; rbIsDec
= true; break;
3123 default: return false;
3128 void ScInterpreter::ScArabic()
3130 OUString aRoman
= GetString().getString();
3131 if( nGlobalError
!= FormulaError::NONE
)
3132 PushError( nGlobalError
);
3135 aRoman
= aRoman
.toAsciiUpperCase();
3137 sal_uInt16 nValue
= 0;
3138 sal_uInt16 nValidRest
= 3999;
3139 sal_Int32 nCharIndex
= 0;
3140 sal_Int32 nCharCount
= aRoman
.getLength();
3143 while( bValid
&& (nCharIndex
< nCharCount
) )
3145 sal_uInt16 nDigit1
= 0;
3146 sal_uInt16 nDigit2
= 0;
3147 bool bIsDec1
= false;
3148 bValid
= lcl_GetArabicValue( aRoman
[nCharIndex
], nDigit1
, bIsDec1
);
3149 if( bValid
&& (nCharIndex
+ 1 < nCharCount
) )
3151 bool bIsDec2
= false;
3152 bValid
= lcl_GetArabicValue( aRoman
[nCharIndex
+ 1], nDigit2
, bIsDec2
);
3156 if( nDigit1
>= nDigit2
)
3158 nValue
= sal::static_int_cast
<sal_uInt16
>( nValue
+ nDigit1
);
3159 nValidRest
%= (nDigit1
* (bIsDec1
? 5 : 2));
3160 bValid
= (nValidRest
>= nDigit1
);
3162 nValidRest
= sal::static_int_cast
<sal_uInt16
>( nValidRest
- nDigit1
);
3165 else if( nDigit1
* 2 != nDigit2
)
3167 sal_uInt16 nDiff
= nDigit2
- nDigit1
;
3168 nValue
= sal::static_int_cast
<sal_uInt16
>( nValue
+ nDiff
);
3169 bValid
= (nValidRest
>= nDiff
);
3171 nValidRest
= nDigit1
- 1;
3181 PushIllegalArgument();
3185 void ScInterpreter::ScHyperLink()
3187 sal_uInt8 nParamCount
= GetByte();
3188 if ( !MustHaveParamCount( nParamCount
, 1, 2 ) )
3192 svl::SharedString aStr
;
3193 ScMatValType nResultType
= ScMatValType::String
;
3195 if ( nParamCount
== 2 )
3197 switch ( GetStackType() )
3201 nResultType
= ScMatValType::Value
;
3210 if ( !PopDoubleRefOrSingleRef( aAdr
) )
3213 ScRefCellValue
aCell(mrDoc
, aAdr
);
3214 if (aCell
.hasEmptyValue())
3215 nResultType
= ScMatValType::Empty
;
3218 FormulaError nErr
= GetCellErrCode(aCell
);
3219 if (nErr
!= FormulaError::NONE
)
3221 else if (aCell
.hasNumeric())
3223 fVal
= GetCellValue(aAdr
, aCell
);
3224 nResultType
= ScMatValType::Value
;
3227 GetCellString(aStr
, aCell
);
3232 nResultType
= GetDoubleOrStringFromMatrix( fVal
, aStr
);
3239 nResultType
= ScMatValType::Value
;
3243 SetError( FormulaError::IllegalArgument
);
3246 svl::SharedString aUrl
= GetString();
3247 ScMatrixRef pResMat
= GetNewMat( 1, 2);
3248 if (nGlobalError
!= FormulaError::NONE
)
3250 fVal
= CreateDoubleError( nGlobalError
);
3251 nResultType
= ScMatValType::Value
;
3253 if (nParamCount
== 2 || nGlobalError
!= FormulaError::NONE
)
3255 if (ScMatrix::IsValueType( nResultType
))
3256 pResMat
->PutDouble( fVal
, 0);
3257 else if (ScMatrix::IsRealStringType( nResultType
))
3258 pResMat
->PutString(aStr
, 0);
3259 else // EmptyType, EmptyPathType, mimic xcl
3260 pResMat
->PutDouble( 0.0, 0 );
3263 pResMat
->PutString(aUrl
, 0);
3264 pResMat
->PutString(aUrl
, 1);
3265 bMatrixFormula
= true;
3266 PushMatrix(pResMat
);
3269 /** Resources at the website of the European Commission:
3270 http://ec.europa.eu/economy_finance/euro/adoption/conversion/
3271 http://ec.europa.eu/economy_finance/euro/countries/
3273 static bool lclConvertMoney( std::u16string_view aSearchUnit
, double& rfRate
, int& rnDec
)
3277 const char* pCurrText
;
3281 static const ConvertInfo aConvertTable
[] = {
3283 { "ATS", 13.7603, 2 },
3284 { "BEF", 40.3399, 0 },
3285 { "DEM", 1.95583, 2 },
3286 { "ESP", 166.386, 0 },
3287 { "FIM", 5.94573, 2 },
3288 { "FRF", 6.55957, 2 },
3289 { "IEP", 0.787564, 2 },
3290 { "ITL", 1936.27, 0 },
3291 { "LUF", 40.3399, 0 },
3292 { "NLG", 2.20371, 2 },
3293 { "PTE", 200.482, 2 },
3294 { "GRD", 340.750, 2 },
3295 { "SIT", 239.640, 2 },
3296 { "MTL", 0.429300, 2 },
3297 { "CYP", 0.585274, 2 },
3298 { "SKK", 30.1260, 2 },
3299 { "EEK", 15.6466, 2 },
3300 { "LVL", 0.702804, 2 },
3301 { "LTL", 3.45280, 2 },
3302 { "HRK", 7.53450, 2 }
3305 for (const auto & i
: aConvertTable
)
3306 if ( o3tl::equalsIgnoreAsciiCase( aSearchUnit
, i
.pCurrText
) )
3315 void ScInterpreter::ScEuroConvert()
3316 { //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]]
3317 sal_uInt8 nParamCount
= GetByte();
3318 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
3321 double fPrecision
= 0.0;
3322 if ( nParamCount
== 5 )
3324 fPrecision
= ::rtl::math::approxFloor(GetDouble());
3325 if ( fPrecision
< 3 )
3327 PushIllegalArgument();
3332 bool bFullPrecision
= nParamCount
>= 4 && GetBool();
3333 OUString aToUnit
= GetString().getString();
3334 OUString aFromUnit
= GetString().getString();
3335 double fVal
= GetDouble();
3336 if ( nGlobalError
!= FormulaError::NONE
)
3337 PushError( nGlobalError
);
3344 if ( lclConvertMoney( aFromUnit
, fFromRate
, nFromDec
)
3345 && lclConvertMoney( aToUnit
, fToRate
, nToDec
) )
3348 if ( aFromUnit
.equalsIgnoreAsciiCase( aToUnit
) )
3352 if ( aFromUnit
.equalsIgnoreAsciiCase( "EUR" ) )
3353 fRes
= fVal
* fToRate
;
3356 double fIntermediate
= fVal
/ fFromRate
;
3358 fIntermediate
= ::rtl::math::round( fIntermediate
,
3359 static_cast<int>(fPrecision
) );
3360 fRes
= fIntermediate
* fToRate
;
3362 if ( !bFullPrecision
)
3363 fRes
= ::rtl::math::round( fRes
, nToDec
);
3368 PushIllegalArgument();
3373 #define UTF8_TH_0 "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214"
3374 #define UTF8_TH_1 "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207"
3375 #define UTF8_TH_2 "\340\270\252\340\270\255\340\270\207"
3376 #define UTF8_TH_3 "\340\270\252\340\270\262\340\270\241"
3377 #define UTF8_TH_4 "\340\270\252\340\270\265\340\271\210"
3378 #define UTF8_TH_5 "\340\270\253\340\271\211\340\270\262"
3379 #define UTF8_TH_6 "\340\270\253\340\270\201"
3380 #define UTF8_TH_7 "\340\271\200\340\270\210\340\271\207\340\270\224"
3381 #define UTF8_TH_8 "\340\271\201\340\270\233\340\270\224"
3382 #define UTF8_TH_9 "\340\271\200\340\270\201\340\271\211\340\270\262"
3383 #define UTF8_TH_10 "\340\270\252\340\270\264\340\270\232"
3384 #define UTF8_TH_11 "\340\271\200\340\270\255\340\271\207\340\270\224"
3385 #define UTF8_TH_20 "\340\270\242\340\270\265\340\271\210"
3386 #define UTF8_TH_1E2 "\340\270\243\340\271\211\340\270\255\340\270\242"
3387 #define UTF8_TH_1E3 "\340\270\236\340\270\261\340\270\231"
3388 #define UTF8_TH_1E4 "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231"
3389 #define UTF8_TH_1E5 "\340\271\201\340\270\252\340\270\231"
3390 #define UTF8_TH_1E6 "\340\270\245\340\271\211\340\270\262\340\270\231"
3391 #define UTF8_TH_DOT0 "\340\270\226\340\271\211\340\270\247\340\270\231"
3392 #define UTF8_TH_BAHT "\340\270\232\340\270\262\340\270\227"
3393 #define UTF8_TH_SATANG "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214"
3394 #define UTF8_TH_MINUS "\340\270\245\340\270\232"
3399 void lclSplitBlock( double& rfInt
, sal_Int32
& rnBlock
, double fValue
, double fSize
)
3401 rnBlock
= static_cast< sal_Int32
>( modf( (fValue
+ 0.1) / fSize
, &rfInt
) * fSize
+ 0.1 );
3404 /** Appends a digit (0 to 9) to the passed string. */
3405 void lclAppendDigit( OStringBuffer
& rText
, sal_Int32 nDigit
)
3409 case 0: rText
.append( UTF8_TH_0
); break;
3410 case 1: rText
.append( UTF8_TH_1
); break;
3411 case 2: rText
.append( UTF8_TH_2
); break;
3412 case 3: rText
.append( UTF8_TH_3
); break;
3413 case 4: rText
.append( UTF8_TH_4
); break;
3414 case 5: rText
.append( UTF8_TH_5
); break;
3415 case 6: rText
.append( UTF8_TH_6
); break;
3416 case 7: rText
.append( UTF8_TH_7
); break;
3417 case 8: rText
.append( UTF8_TH_8
); break;
3418 case 9: rText
.append( UTF8_TH_9
); break;
3419 default: OSL_FAIL( "lclAppendDigit - illegal digit" );
3423 /** Appends a value raised to a power of 10: nDigit*10^nPow10.
3424 @param nDigit A digit in the range from 1 to 9.
3425 @param nPow10 A value in the range from 2 to 5.
3427 void lclAppendPow10( OStringBuffer
& rText
, sal_Int32 nDigit
, sal_Int32 nPow10
)
3429 OSL_ENSURE( (1 <= nDigit
) && (nDigit
<= 9), "lclAppendPow10 - illegal digit" );
3430 lclAppendDigit( rText
, nDigit
);
3433 case 2: rText
.append( UTF8_TH_1E2
); break;
3434 case 3: rText
.append( UTF8_TH_1E3
); break;
3435 case 4: rText
.append( UTF8_TH_1E4
); break;
3436 case 5: rText
.append( UTF8_TH_1E5
); break;
3437 default: OSL_FAIL( "lclAppendPow10 - illegal power" );
3441 /** Appends a block of 6 digits (value from 1 to 999,999) to the passed string. */
3442 void lclAppendBlock( OStringBuffer
& rText
, sal_Int32 nValue
)
3444 OSL_ENSURE( (1 <= nValue
) && (nValue
<= 999999), "lclAppendBlock - illegal value" );
3445 if( nValue
>= 100000 )
3447 lclAppendPow10( rText
, nValue
/ 100000, 5 );
3450 if( nValue
>= 10000 )
3452 lclAppendPow10( rText
, nValue
/ 10000, 4 );
3455 if( nValue
>= 1000 )
3457 lclAppendPow10( rText
, nValue
/ 1000, 3 );
3462 lclAppendPow10( rText
, nValue
/ 100, 2 );
3468 sal_Int32 nTen
= nValue
/ 10;
3469 sal_Int32 nOne
= nValue
% 10;
3473 lclAppendDigit( rText
, nTen
);
3474 else if( nTen
== 2 )
3475 rText
.append( UTF8_TH_20
);
3476 rText
.append( UTF8_TH_10
);
3478 if( (nTen
> 0) && (nOne
== 1) )
3479 rText
.append( UTF8_TH_11
);
3481 lclAppendDigit( rText
, nOne
);
3486 void ScInterpreter::ScBahtText()
3488 sal_uInt8 nParamCount
= GetByte();
3489 if ( !MustHaveParamCount( nParamCount
, 1 ) )
3492 double fValue
= GetDouble();
3493 if( nGlobalError
!= FormulaError::NONE
)
3495 PushError( nGlobalError
);
3500 bool bMinus
= fValue
< 0.0;
3501 fValue
= std::abs( fValue
);
3503 // round to 2 digits after decimal point, fValue contains Satang as integer
3504 fValue
= ::rtl::math::approxFloor( fValue
* 100.0 + 0.5 );
3506 // split Baht and Satang
3508 sal_Int32 nSatang
= 0;
3509 lclSplitBlock( fBaht
, nSatang
, fValue
, 100.0 );
3511 OStringBuffer aText
;
3513 // generate text for Baht value
3517 aText
.append( UTF8_TH_0
);
3519 else while( fBaht
> 0.0 )
3521 OStringBuffer aBlock
;
3522 sal_Int32 nBlock
= 0;
3523 lclSplitBlock( fBaht
, nBlock
, fBaht
, 1.0e6
);
3525 lclAppendBlock( aBlock
, nBlock
);
3526 // add leading "million", if there will come more blocks
3528 aBlock
.insert( 0, UTF8_TH_1E6
);
3530 aText
.insert(0, aBlock
);
3532 if (!aText
.isEmpty())
3533 aText
.append( UTF8_TH_BAHT
);
3535 // generate text for Satang value
3538 aText
.append( UTF8_TH_DOT0
);
3542 lclAppendBlock( aText
, nSatang
);
3543 aText
.append( UTF8_TH_SATANG
);
3546 // add the minus sign
3548 aText
.insert( 0, UTF8_TH_MINUS
);
3550 PushString( OStringToOUString(aText
, RTL_TEXTENCODING_UTF8
) );
3553 void ScInterpreter::ScGetPivotData()
3555 sal_uInt8 nParamCount
= GetByte();
3557 if (!MustHaveParamCountMin(nParamCount
, 2) || (nParamCount
% 2) == 1)
3559 PushError(FormulaError::NoRef
);
3563 bool bOldSyntax
= false;
3564 if (nParamCount
== 2)
3566 // if the first parameter is a ref, assume old syntax
3567 StackVar eFirstType
= GetStackType(2);
3568 if (eFirstType
== svSingleRef
|| eFirstType
== svDoubleRef
)
3572 std::vector
<sheet::DataPilotFieldFilter
> aFilters
;
3573 OUString aDataFieldName
;
3578 aDataFieldName
= GetString().getString();
3580 switch (GetStackType())
3583 PopDoubleRef(aBlock
);
3588 PopSingleRef(aAddr
);
3593 PushError(FormulaError::NoRef
);
3599 // Standard syntax: separate name/value pairs
3601 sal_uInt16 nFilterCount
= nParamCount
/ 2 - 1;
3602 aFilters
.resize(nFilterCount
);
3604 sal_uInt16 i
= nFilterCount
;
3608 /* TODO: also, in case of numeric the entire filter match should
3609 * not be on a (even if locale independent) formatted string down
3610 * below in pDPObj->GetPivotData(). */
3612 bool bEvaluateFormatIndex
;
3613 switch (GetRawStackType())
3617 bEvaluateFormatIndex
= true;
3620 bEvaluateFormatIndex
= false;
3624 svl::SharedString aSharedString
;
3625 bool bDouble
= GetDoubleOrString( fDouble
, aSharedString
);
3626 if (nGlobalError
!= FormulaError::NONE
)
3628 PushError( nGlobalError
);
3634 sal_uInt32 nNumFormat
;
3635 if (bEvaluateFormatIndex
&& nCurFmtIndex
)
3636 nNumFormat
= nCurFmtIndex
;
3639 if (nCurFmtType
== SvNumFormatType::UNDEFINED
)
3642 nNumFormat
= mrContext
.NFGetStandardFormat( nCurFmtType
, ScGlobal::eLnge
);
3644 const Color
* pColor
;
3645 mrContext
.NFGetOutputString( fDouble
, nNumFormat
, aFilters
[i
].MatchValueName
, &pColor
);
3646 aFilters
[i
].MatchValue
= ScDPCache::GetLocaleIndependentFormattedString(
3647 fDouble
, mrContext
, nNumFormat
);
3651 aFilters
[i
].MatchValueName
= aSharedString
.getString();
3653 // Parse possible number from MatchValueName and format
3654 // locale independent as MatchValue.
3655 sal_uInt32 nNumFormat
= 0;
3657 if (mrContext
.NFIsNumberFormat( aFilters
[i
].MatchValueName
, nNumFormat
, fValue
))
3658 aFilters
[i
].MatchValue
= ScDPCache::GetLocaleIndependentFormattedString(
3659 fValue
, mrContext
, nNumFormat
);
3661 aFilters
[i
].MatchValue
= aFilters
[i
].MatchValueName
;
3664 aFilters
[i
].FieldName
= GetString().getString();
3667 switch (GetStackType())
3670 PopDoubleRef(aBlock
);
3675 PopSingleRef(aAddr
);
3680 PushError(FormulaError::NoRef
);
3684 aDataFieldName
= GetString().getString(); // First parameter is data field name.
3687 // Early bail-out, don't grind through data pilot cache and all.
3688 if (nGlobalError
!= FormulaError::NONE
)
3690 PushError( nGlobalError
);
3694 // NOTE : MS Excel docs claim to use the 'most recent' which is not
3695 // exactly the same as what we do in ScDocument::GetDPAtBlock
3696 // However we do need to use GetDPABlock
3697 ScDPObject
* pDPObj
= mrDoc
.GetDPAtBlock(aBlock
);
3700 PushError(FormulaError::NoRef
);
3706 OUString aFilterStr
= aDataFieldName
;
3707 std::vector
<sal_Int16
> aFilterFuncs
;
3708 if (!pDPObj
->ParseFilters(aDataFieldName
, aFilters
, aFilterFuncs
, aFilterStr
))
3710 PushError(FormulaError::NoRef
);
3714 // TODO : For now, we ignore filter functions since we couldn't find a
3715 // live example of how they are supposed to be used. We'll support
3716 // this again once we come across a real-world example.
3719 double fVal
= pDPObj
->GetPivotData(aDataFieldName
, aFilters
);
3720 if (std::isnan(fVal
))
3722 PushError(FormulaError::NoRef
);
3728 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */