LibreOffice Module sc (master) 1
interpr2.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <memory>
21#include <interpre.hxx>
22
23#include <comphelper/string.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 <sal/macros.h>
32#include <osl/diagnose.h>
33
34#include <sc.hrc>
35#include <ddelink.hxx>
36#include <scmatrix.hxx>
37#include <formulacell.hxx>
38#include <document.hxx>
39#include <dociter.hxx>
40#include <unitconv.hxx>
41#include <hints.hxx>
42#include <dpobject.hxx>
43#include <tokenarray.hxx>
44#include <globalnames.hxx>
45#include <stlpool.hxx>
46#include <stlsheet.hxx>
47#include <dpcache.hxx>
48
49#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
50
51#include <string.h>
52
53using ::std::vector;
54using namespace com::sun::star;
55using namespace formula;
56
57#define SCdEpsilon 1.0E-7
58
59// Date and Time
60
61double ScInterpreter::GetDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay,
62 bool bStrict )
63{
64 if ( nYear < 100 && !bStrict )
65 nYear = pFormatter->ExpandTwoDigitYear( nYear );
66 // Do not use a default Date ctor here because it asks system time with a
67 // performance penalty.
68 sal_Int16 nY, nM, nD;
69 if (bStrict)
70 {
71 nY = nYear;
72 nM = nMonth;
73 nD = nDay;
74 }
75 else
76 {
77 if (nMonth > 0)
78 {
79 nY = nYear + (nMonth-1) / 12;
80 nM = ((nMonth-1) % 12) + 1;
81 }
82 else
83 {
84 nY = nYear + (nMonth-12) / 12;
85 nM = 12 - (-nMonth) % 12;
86 }
87 nD = 1;
88 }
89 Date aDate( nD, nM, nY);
90 if (!bStrict)
91 aDate.AddDays( nDay - 1 );
92 if (aDate.IsValidAndGregorian())
93 return static_cast<double>(aDate - pFormatter->GetNullDate());
94 else
95 {
96 SetError(FormulaError::NoValue);
97 return 0;
98 }
99}
100
102{
103 nFuncFmtType = SvNumFormatType::DATE;
104 Date aActDate( Date::SYSTEM );
105 tools::Long nDiff = aActDate - pFormatter->GetNullDate();
106 PushDouble(static_cast<double>(nDiff));
107}
108
110{
111 nFuncFmtType = SvNumFormatType::DATETIME;
112 DateTime aActTime( DateTime::SYSTEM );
113 tools::Long nDiff = aActTime - pFormatter->GetNullDate();
114 double fTime = aActTime.GetHour() / static_cast<double>(::tools::Time::hourPerDay) +
115 aActTime.GetMin() / static_cast<double>(::tools::Time::minutePerDay) +
116 aActTime.GetSec() / static_cast<double>(::tools::Time::secondPerDay) +
117 aActTime.GetNanoSec() / static_cast<double>(::tools::Time::nanoSecPerDay);
118 PushDouble( static_cast<double>(nDiff) + fTime );
119}
120
122{
123 Date aDate = pFormatter->GetNullDate();
124 aDate.AddDays( GetInt32());
125 PushDouble( static_cast<double>(aDate.GetYear()) );
126}
127
129{
130 Date aDate = pFormatter->GetNullDate();
131 aDate.AddDays( GetInt32());
132 PushDouble( static_cast<double>(aDate.GetMonth()) );
133}
134
136{
137 Date aDate = pFormatter->GetNullDate();
138 aDate.AddDays( GetInt32());
139 PushDouble(static_cast<double>(aDate.GetDay()));
140}
141
143{
144 sal_uInt16 nHour, nMinute, nSecond;
145 double fFractionOfSecond;
146 tools::Time::GetClock( GetDouble(), nHour, nMinute, nSecond, fFractionOfSecond, 0);
147 PushDouble( nMinute);
148}
149
151{
152 sal_uInt16 nHour, nMinute, nSecond;
153 double fFractionOfSecond;
154 tools::Time::GetClock( GetDouble(), nHour, nMinute, nSecond, fFractionOfSecond, 0);
155 if ( fFractionOfSecond >= 0.5 )
156 nSecond = ( nSecond + 1 ) % 60;
157 PushDouble( nSecond );
158
159}
160
162{
163 sal_uInt16 nHour, nMinute, nSecond;
164 double fFractionOfSecond;
165 tools::Time::GetClock( GetDouble(), nHour, nMinute, nSecond, fFractionOfSecond, 0);
166 PushDouble( nHour);
167}
168
170{
171 OUString aInputString = GetString().getString();
172 sal_uInt32 nFIndex = 0; // for a default country/language
173 double fVal;
174 if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
175 {
177 if (eType == SvNumFormatType::DATE || eType == SvNumFormatType::DATETIME)
178 {
179 nFuncFmtType = SvNumFormatType::DATE;
180 PushDouble(::rtl::math::approxFloor(fVal));
181 }
182 else
184 }
185 else
187}
188
190{
191 sal_uInt8 nParamCount = GetByte();
192 if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
193 return;
194
195 sal_Int16 nFlag;
196 if (nParamCount == 2)
197 nFlag = GetInt16();
198 else
199 nFlag = 1;
200
201 Date aDate = pFormatter->GetNullDate();
202 aDate.AddDays( GetInt32());
203 int nVal = static_cast<int>(aDate.GetDayOfWeek()); // MONDAY = 0
204 switch (nFlag)
205 {
206 case 1: // Sunday = 1
207 if (nVal == 6)
208 nVal = 1;
209 else
210 nVal += 2;
211 break;
212 case 2: // Monday = 1
213 nVal += 1;
214 break;
215 case 3: // Monday = 0
216 ; // nothing
217 break;
218 case 11: // Monday = 1
219 case 12: // Tuesday = 1
220 case 13: // Wednesday = 1
221 case 14: // Thursday = 1
222 case 15: // Friday = 1
223 case 16: // Saturday = 1
224 case 17: // Sunday = 1
225 if (nVal < nFlag - 11) // x = nFlag - 11 = 0,1,2,3,4,5,6
226 nVal += 19 - nFlag; // nVal += (8 - (nFlag - 11) = 8 - x = 8,7,6,5,4,3,2)
227 else
228 nVal -= nFlag - 12; // nVal -= ((nFlag - 11) - 1 = x - 1 = -1,0,1,2,3,4,5)
229 break;
230 default:
231 SetError( FormulaError::IllegalArgument);
232 }
233 PushInt( nVal );
234}
235
237{
238 if ( MustHaveParamCount( GetByte(), 2 ) )
239 {
240 sal_Int16 nFlag = GetInt16();
241
242 Date aDate = pFormatter->GetNullDate();
243 aDate.AddDays( GetInt32());
244 PushInt( static_cast<int>(aDate.GetWeekOfYear( nFlag == 1 ? SUNDAY : MONDAY )));
245 }
246}
247
249{
250 sal_uInt8 nParamCount = GetByte();
251 if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
252 return;
253
254 sal_Int16 nFlag = ( nParamCount == 1 ) ? 1 : GetInt16();
255
256 Date aDate = pFormatter->GetNullDate();
257 aDate.AddDays( GetInt32());
258
259 sal_Int32 nMinimumNumberOfDaysInWeek;
260 DayOfWeek eFirstDayOfWeek;
261 switch ( nFlag )
262 {
263 case 1 :
264 eFirstDayOfWeek = SUNDAY;
265 nMinimumNumberOfDaysInWeek = 1;
266 break;
267 case 2 :
268 eFirstDayOfWeek = MONDAY;
269 nMinimumNumberOfDaysInWeek = 1;
270 break;
271 case 11 :
272 case 12 :
273 case 13 :
274 case 14 :
275 case 15 :
276 case 16 :
277 case 17 :
278 eFirstDayOfWeek = static_cast<DayOfWeek>( nFlag - 11 ); // MONDAY := 0
279 nMinimumNumberOfDaysInWeek = 1; //the week containing January 1 is week 1
280 break;
281 case 21 :
282 case 150 :
283 // ISO 8601
284 eFirstDayOfWeek = MONDAY;
285 nMinimumNumberOfDaysInWeek = 4;
286 break;
287 default :
289 return;
290 }
291 PushInt( static_cast<int>(aDate.GetWeekOfYear( eFirstDayOfWeek, nMinimumNumberOfDaysInWeek )) );
292}
293
295{
296 if ( MustHaveParamCount( GetByte(), 1 ) )
297 {
298 Date aDate = pFormatter->GetNullDate();
299 aDate.AddDays( GetInt32());
300 PushInt( static_cast<int>(aDate.GetWeekOfYear()) );
301 }
302}
303
305{
306 nFuncFmtType = SvNumFormatType::DATE;
307 if ( !MustHaveParamCount( GetByte(), 1 ) )
308 return;
309
310 sal_Int16 nYear = GetInt16();
311 if (nGlobalError != FormulaError::NONE)
312 {
314 return;
315 }
316 if ( nYear < 100 )
317 nYear = pFormatter->ExpandTwoDigitYear( nYear );
318 if (nYear < 1583 || nYear > 9956)
319 {
320 // Valid Gregorian and maximum year constraints not met.
322 return;
323 }
324 // don't worry, be happy :)
325 int B,C,D,E,F,G,H,I,K,L,M,N,O;
326 N = nYear % 19;
327 B = int(nYear / 100);
328 C = nYear % 100;
329 D = int(B / 4);
330 E = B % 4;
331 F = int((B + 8) / 25);
332 G = int((B - F + 1) / 3);
333 H = (19 * N + B - D - G + 15) % 30;
334 I = int(C / 4);
335 K = C % 4;
336 L = (32 + 2 * E + 2 * I - H - K) % 7;
337 M = int((N + 11 * H + 22 * L) / 451);
338 O = H + L - 7 * M + 114;
339 sal_Int16 nDay = sal::static_int_cast<sal_Int16>( O % 31 + 1 );
340 sal_Int16 nMonth = sal::static_int_cast<sal_Int16>( int(O / 31) );
341 PushDouble( GetDateSerial( nYear, nMonth, nDay, true ) );
342}
343
345 const sal_uInt8 nParamCount, const sal_uInt32 nNullDate, vector< double >& rSortArray,
346 bool bWeekendMask[ 7 ] )
347{
348 if ( nParamCount == 4 )
349 {
350 vector< double > nWeekendDays;
351 GetNumberSequenceArray( 1, nWeekendDays, false );
352 if ( nGlobalError != FormulaError::NONE )
353 return nGlobalError;
354 else
355 {
356 if ( nWeekendDays.size() != 7 )
357 return FormulaError::IllegalArgument;
358
359 // Weekend days defined by string, Sunday...Saturday
360 for ( int i = 0; i < 7; i++ )
361 bWeekendMask[ i ] = static_cast<bool>(nWeekendDays[ ( i == 6 ? 0 : i + 1 ) ]);
362 }
363 }
364 else
365 {
366 for ( int i = 0; i < 7; i++ )
367 bWeekendMask[ i] = false;
368
369 bWeekendMask[ SATURDAY ] = true;
370 bWeekendMask[ SUNDAY ] = true;
371 }
372
373 if ( nParamCount >= 3 )
374 {
375 GetSortArray( 1, rSortArray, nullptr, true, true );
376 size_t nMax = rSortArray.size();
377 for ( size_t i = 0; i < nMax; i++ )
378 rSortArray.at( i ) = ::rtl::math::approxFloor( rSortArray.at( i ) ) + nNullDate;
379 }
380
381 return nGlobalError;
382}
383
385 const sal_uInt8 nParamCount, const sal_uInt32 nNullDate, vector< double >& rSortArray,
386 bool bWeekendMask[ 7 ], bool bWorkdayFunction )
387{
388 FormulaError nErr = FormulaError::NONE;
389 OUString aWeekendDays;
390 if ( nParamCount == 4 )
391 {
392 GetSortArray( 1, rSortArray, nullptr, true, true );
393 size_t nMax = rSortArray.size();
394 for ( size_t i = 0; i < nMax; i++ )
395 rSortArray.at( i ) = ::rtl::math::approxFloor( rSortArray.at( i ) ) + nNullDate;
396 }
397
398 if ( nParamCount >= 3 )
399 {
400 if ( IsMissing() )
401 Pop();
402 else
403 {
404 switch ( GetStackType() )
405 {
406 case svDoubleRef :
408 return FormulaError::NoValue;
409
410 default :
411 {
412 double fDouble;
413 svl::SharedString aSharedString;
414 bool bDouble = GetDoubleOrString( fDouble, aSharedString);
415 if ( bDouble )
416 {
417 if ( fDouble >= 1.0 && fDouble <= 17 )
418 aWeekendDays = OUString::number( fDouble );
419 else
420 return FormulaError::NoValue;
421 }
422 else
423 {
424 if ( aSharedString.isEmpty() || aSharedString.getLength() != 7 ||
425 ( bWorkdayFunction && aSharedString.getString() == "1111111" ) )
426 return FormulaError::NoValue;
427 else
428 aWeekendDays = aSharedString.getString();
429 }
430 }
431 break;
432 }
433 }
434 }
435
436 for ( int i = 0; i < 7; i++ )
437 bWeekendMask[ i] = false;
438
439 if ( aWeekendDays.isEmpty() )
440 {
441 bWeekendMask[ SATURDAY ] = true;
442 bWeekendMask[ SUNDAY ] = true;
443 }
444 else
445 {
446 switch ( aWeekendDays.getLength() )
447 {
448 case 1 :
449 // Weekend days defined by code
450 switch ( aWeekendDays[ 0 ] )
451 {
452 case '1' : bWeekendMask[ SATURDAY ] = true; bWeekendMask[ SUNDAY ] = true; break;
453 case '2' : bWeekendMask[ SUNDAY ] = true; bWeekendMask[ MONDAY ] = true; break;
454 case '3' : bWeekendMask[ MONDAY ] = true; bWeekendMask[ TUESDAY ] = true; break;
455 case '4' : bWeekendMask[ TUESDAY ] = true; bWeekendMask[ WEDNESDAY ] = true; break;
456 case '5' : bWeekendMask[ WEDNESDAY ] = true; bWeekendMask[ THURSDAY ] = true; break;
457 case '6' : bWeekendMask[ THURSDAY ] = true; bWeekendMask[ FRIDAY ] = true; break;
458 case '7' : bWeekendMask[ FRIDAY ] = true; bWeekendMask[ SATURDAY ] = true; break;
459 default : nErr = FormulaError::IllegalArgument; break;
460 }
461 break;
462 case 2 :
463 // Weekend day defined by code
464 if ( aWeekendDays[ 0 ] == '1' )
465 {
466 switch ( aWeekendDays[ 1 ] )
467 {
468 case '1' : bWeekendMask[ SUNDAY ] = true; break;
469 case '2' : bWeekendMask[ MONDAY ] = true; break;
470 case '3' : bWeekendMask[ TUESDAY ] = true; break;
471 case '4' : bWeekendMask[ WEDNESDAY ] = true; break;
472 case '5' : bWeekendMask[ THURSDAY ] = true; break;
473 case '6' : bWeekendMask[ FRIDAY ] = true; break;
474 case '7' : bWeekendMask[ SATURDAY ] = true; break;
475 default : nErr = FormulaError::IllegalArgument; break;
476 }
477 }
478 else
479 nErr = FormulaError::IllegalArgument;
480 break;
481 case 7 :
482 // Weekend days defined by string
483 for ( int i = 0; i < 7 && nErr == FormulaError::NONE; i++ )
484 {
485 switch ( aWeekendDays[ i ] )
486 {
487 case '0' : bWeekendMask[ i ] = false; break;
488 case '1' : bWeekendMask[ i ] = true; break;
489 default : nErr = FormulaError::IllegalArgument; break;
490 }
491 }
492 break;
493 default :
494 nErr = FormulaError::IllegalArgument;
495 break;
496 }
497 }
498 return nErr;
499}
500
501void ScInterpreter::ScNetWorkdays( bool bOOXML_Version )
502{
503 sal_uInt8 nParamCount = GetByte();
504 if ( !MustHaveParamCount( nParamCount, 2, 4 ) )
505 return;
506
507 vector<double> nSortArray;
508 bool bWeekendMask[ 7 ];
509 const Date& rNullDate = pFormatter->GetNullDate();
510 sal_uInt32 nNullDate = Date::DateToDays( rNullDate.GetDay(), rNullDate.GetMonth(), rNullDate.GetYear() );
511 FormulaError nErr;
512 if ( bOOXML_Version )
513 {
514 nErr = GetWeekendAndHolidayMasks_MS( nParamCount, nNullDate,
515 nSortArray, bWeekendMask, false );
516 }
517 else
518 {
519 nErr = GetWeekendAndHolidayMasks( nParamCount, nNullDate,
520 nSortArray, bWeekendMask );
521 }
522 if ( nErr != FormulaError::NONE )
523 PushError( nErr );
524 else
525 {
526 sal_uInt32 nDate2 = GetUInt32();
527 sal_uInt32 nDate1 = GetUInt32();
528 if (nGlobalError != FormulaError::NONE || (nDate1 > SAL_MAX_UINT32 - nNullDate) || nDate2 > (SAL_MAX_UINT32 - nNullDate))
529 {
531 return;
532 }
533 nDate2 += nNullDate;
534 nDate1 += nNullDate;
535
536 sal_Int32 nCnt = 0;
537 size_t nRef = 0;
538 bool bReverse = ( nDate1 > nDate2 );
539 if ( bReverse )
540 std::swap( nDate1, nDate2 );
541 size_t nMax = nSortArray.size();
542 while ( nDate1 <= nDate2 )
543 {
544 if ( !bWeekendMask[ GetDayOfWeek( nDate1 ) ] )
545 {
546 while ( nRef < nMax && nSortArray.at( nRef ) < nDate1 )
547 nRef++;
548 if ( nRef >= nMax || nSortArray.at( nRef ) != nDate1 )
549 nCnt++;
550 }
551 ++nDate1;
552 }
553 PushDouble( static_cast<double>( bReverse ? -nCnt : nCnt ) );
554 }
555}
556
558{
559 sal_uInt8 nParamCount = GetByte();
560 if ( !MustHaveParamCount( nParamCount, 2, 4 ) )
561 return;
562
563 nFuncFmtType = SvNumFormatType::DATE;
564 vector<double> nSortArray;
565 bool bWeekendMask[ 7 ];
566 const Date& rNullDate = pFormatter->GetNullDate();
567 sal_uInt32 nNullDate = Date::DateToDays( rNullDate.GetDay(), rNullDate.GetMonth(), rNullDate.GetYear() );
568 FormulaError nErr = GetWeekendAndHolidayMasks_MS( nParamCount, nNullDate,
569 nSortArray, bWeekendMask, true );
570 if ( nErr != FormulaError::NONE )
571 PushError( nErr );
572 else
573 {
574 sal_Int32 nDays = GetInt32();
575 sal_uInt32 nDate = GetUInt32();
576 if (nGlobalError != FormulaError::NONE || (nDate > SAL_MAX_UINT32 - nNullDate))
577 {
579 return;
580 }
581 nDate += nNullDate;
582
583 if ( !nDays )
584 PushDouble( static_cast<double>( nDate - nNullDate ) );
585 else
586 {
587 size_t nMax = nSortArray.size();
588 if ( nDays > 0 )
589 {
590 size_t nRef = 0;
591 while ( nDays )
592 {
593 do
594 {
595 ++nDate;
596 }
597 while ( bWeekendMask[ GetDayOfWeek( nDate ) ] ); //jump over weekend day(s)
598
599 while ( nRef < nMax && nSortArray.at( nRef ) < nDate )
600 nRef++;
601
602 if ( nRef >= nMax || nSortArray.at( nRef ) != nDate || nRef >= nMax )
603 nDays--;
604 }
605 }
606 else
607 {
608 sal_Int16 nRef = nMax - 1;
609 while ( nDays )
610 {
611 do
612 {
613 --nDate;
614 }
615 while ( bWeekendMask[ GetDayOfWeek( nDate ) ] ); //jump over weekend day(s)
616
617 while ( nRef >= 0 && nSortArray.at( nRef ) > nDate )
618 nRef--;
619
620 if (nRef < 0 || nSortArray.at(nRef) != nDate)
621 nDays++;
622 }
623 }
624 PushDouble( static_cast<double>( nDate - nNullDate ) );
625 }
626 }
627}
628
630{
631 nFuncFmtType = SvNumFormatType::DATE;
632 if ( !MustHaveParamCount( GetByte(), 3 ) )
633 return;
634
635 sal_Int16 nDay = GetInt16();
636 sal_Int16 nMonth = GetInt16();
637 if (IsMissing())
638 SetError( FormulaError::ParameterExpected); // Year must be given.
639 sal_Int16 nYear = GetInt16();
640 if (nGlobalError != FormulaError::NONE || nYear < 0)
642 else
643 PushDouble(GetDateSerial(nYear, nMonth, nDay, false));
644}
645
647{
648 nFuncFmtType = SvNumFormatType::TIME;
649 if ( MustHaveParamCount( GetByte(), 3 ) )
650 {
651 double fSec = GetDouble();
652 double fMin = GetDouble();
653 double fHour = GetDouble();
654 double fTime = fmod( (fHour * ::tools::Time::secondPerHour) + (fMin * ::tools::Time::secondPerMinute) + fSec, DATE_TIME_FACTOR) / DATE_TIME_FACTOR;
655 if (fTime < 0)
657 else
658 PushDouble( fTime);
659 }
660}
661
663{
664 if ( MustHaveParamCount( GetByte(), 2 ) )
665 {
666 double fDate2 = GetDouble();
667 double fDate1 = GetDouble();
668 PushDouble(fDate1 - fDate2);
669 }
670}
671
673{
674 /* Implementation follows
675 * http://www.bondmarkets.com/eCommerce/SMD_Fields_030802.pdf
676 * Appendix B: Day-Count Bases, there are 7 different ways to calculate the
677 * 30-days count. That document also claims that Excel implements the "PSA
678 * 30" or "NASD 30" method (funny enough they also state that Excel is the
679 * only tool that does so).
680 *
681 * Note that the definition given in
682 * http://msdn.microsoft.com/library/en-us/office97/html/SEB7C.asp
683 * is _not_ the way how it is actually calculated by Excel (that would not
684 * even match any of the 7 methods mentioned above) and would result in the
685 * following test cases producing wrong results according to that appendix B:
686 *
687 * 28-Feb-95 31-Aug-95 181 instead of 180
688 * 29-Feb-96 31-Aug-96 181 instead of 180
689 * 30-Jan-96 31-Mar-96 61 instead of 60
690 * 31-Jan-96 31-Mar-96 61 instead of 60
691 *
692 * Still, there is a difference between OOoCalc and Excel:
693 * In Excel:
694 * 02-Feb-99 31-Mar-00 results in 419
695 * 31-Mar-00 02-Feb-99 results in -418
696 * In Calc the result is 419 respectively -419. I consider the -418 a bug in Excel.
697 */
698
699 sal_uInt8 nParamCount = GetByte();
700 if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
701 return;
702
703 bool bFlag = nParamCount == 3 && GetBool();
704 sal_Int32 nDate2 = GetInt32();
705 sal_Int32 nDate1 = GetInt32();
706 if (nGlobalError != FormulaError::NONE)
708 else
709 {
710 sal_Int32 nSign;
711 // #i84934# only for non-US European algorithm swap dates. Else
712 // follow Excel's meaningless extrapolation for "interoperability".
713 if (bFlag && (nDate2 < nDate1))
714 {
715 nSign = nDate1;
716 nDate1 = nDate2;
717 nDate2 = nSign;
718 nSign = -1;
719 }
720 else
721 nSign = 1;
722 Date aDate1 = pFormatter->GetNullDate();
723 aDate1.AddDays( nDate1);
724 Date aDate2 = pFormatter->GetNullDate();
725 aDate2.AddDays( nDate2);
726 if (aDate1.GetDay() == 31)
727 aDate1.AddDays( -1);
728 else if (!bFlag)
729 {
730 if (aDate1.GetMonth() == 2)
731 {
732 switch ( aDate1.GetDay() )
733 {
734 case 28 :
735 if ( !aDate1.IsLeapYear() )
736 aDate1.SetDay(30);
737 break;
738 case 29 :
739 aDate1.SetDay(30);
740 break;
741 }
742 }
743 }
744 if (aDate2.GetDay() == 31)
745 {
746 if (!bFlag )
747 {
748 if (aDate1.GetDay() == 30)
749 aDate2.AddDays( -1);
750 }
751 else
752 aDate2.SetDay(30);
753 }
754 PushDouble( static_cast<double>(nSign) *
755 ( static_cast<double>(aDate2.GetDay()) + static_cast<double>(aDate2.GetMonth()) * 30.0 +
756 static_cast<double>(aDate2.GetYear()) * 360.0
757 - static_cast<double>(aDate1.GetDay()) - static_cast<double>(aDate1.GetMonth()) * 30.0
758 - static_cast<double>(aDate1.GetYear()) * 360.0) );
759 }
760}
761
762// fdo#44456 function DATEDIF as defined in ODF1.2 (Par. 6.10.3)
764{
765 if ( !MustHaveParamCount( GetByte(), 3 ) )
766 return;
767
768 OUString aInterval = GetString().getString();
769 sal_Int32 nDate2 = GetInt32();
770 sal_Int32 nDate1 = GetInt32();
771
772 if (nGlobalError != FormulaError::NONE)
773 {
775 return;
776 }
777
778 // Excel doesn't swap dates or return negative numbers, so don't we.
779 if (nDate1 > nDate2)
780 {
782 return;
783 }
784
785 double dd = nDate2 - nDate1;
786 // Zero difference or number of days can be returned immediately.
787 if (dd == 0.0 || aInterval.equalsIgnoreAsciiCase( "d" ))
788 {
789 PushDouble( dd );
790 return;
791 }
792
793 // split dates in day, month, year for use with formats other than "d"
794 sal_uInt16 d1, m1, d2, m2;
795 sal_Int16 y1, y2;
796 Date aDate1( pFormatter->GetNullDate());
797 aDate1.AddDays( nDate1);
798 y1 = aDate1.GetYear();
799 m1 = aDate1.GetMonth();
800 d1 = aDate1.GetDay();
801 Date aDate2( pFormatter->GetNullDate());
802 aDate2.AddDays( nDate2);
803 y2 = aDate2.GetYear();
804 m2 = aDate2.GetMonth();
805 d2 = aDate2.GetDay();
806
807 // Close the year 0 gap to calculate year difference.
808 if (y1 < 0 && y2 > 0)
809 ++y1;
810 else if (y1 > 0 && y2 < 0)
811 ++y2;
812
813 if ( aInterval.equalsIgnoreAsciiCase( "m" ) )
814 {
815 // Return number of months.
816 int md = m2 - m1 + 12 * (y2 - y1);
817 if (d1 > d2)
818 --md;
819 PushInt( md );
820 }
821 else if ( aInterval.equalsIgnoreAsciiCase( "y" ) )
822 {
823 // Return number of years.
824 int yd;
825 if ( y2 > y1 )
826 {
827 if (m2 > m1 || (m2 == m1 && d2 >= d1))
828 yd = y2 - y1; // complete years between dates
829 else
830 yd = y2 - y1 - 1; // one incomplete year
831 }
832 else
833 {
834 // Year is equal as we don't allow reversed arguments, no
835 // complete year between dates.
836 yd = 0;
837 }
838 PushInt( yd );
839 }
840 else if ( aInterval.equalsIgnoreAsciiCase( "md" ) )
841 {
842 // Return number of days, excluding months and years.
843 // This is actually the remainder of days when subtracting years
844 // and months from the difference of dates. Birthday-like 23 years
845 // and 10 months and 19 days.
846
847 // Algorithm's roll-over behavior extracted from Excel by try and
848 // error...
849 // If day1 <= day2 then simply day2 - day1.
850 // If day1 > day2 then set month1 to month2-1 and year1 to
851 // year2(-1) and subtract dates, e.g. for 2012-01-28,2012-03-01 set
852 // 2012-02-28 and then (2012-03-01)-(2012-02-28) => 2 days (leap
853 // year).
854 // For 2011-01-29,2011-03-01 the non-existent 2011-02-29 rolls over
855 // to 2011-03-01 so the result is 0. Same for day 31 in months with
856 // only 30 days.
857
858 tools::Long nd;
859 if (d1 <= d2)
860 nd = d2 - d1;
861 else
862 {
863 if (m2 == 1)
864 {
865 aDate1.SetYear( y2 == 1 ? -1 : y2 - 1 );
866 aDate1.SetMonth( 12 );
867 }
868 else
869 {
870 aDate1.SetYear( y2 );
871 aDate1.SetMonth( m2 - 1 );
872 }
873 aDate1.Normalize();
874 nd = aDate2 - aDate1;
875 }
876 PushDouble( nd );
877 }
878 else if ( aInterval.equalsIgnoreAsciiCase( "ym" ) )
879 {
880 // Return number of months, excluding years.
881 int md = m2 - m1 + 12 * (y2 - y1);
882 if (d1 > d2)
883 --md;
884 md %= 12;
885 PushInt( md );
886 }
887 else if ( aInterval.equalsIgnoreAsciiCase( "yd" ) )
888 {
889 // Return number of days, excluding years.
890
891 // Condition corresponds with "y".
892 if (m2 > m1 || (m2 == m1 && d2 >= d1))
893 aDate1.SetYear( y2 );
894 else
895 aDate1.SetYear( y2 - 1 );
896 // XXX NOTE: Excel for the case 1988-06-22,2012-05-11 returns
897 // 323, whereas the result here is 324. Don't they use the leap
898 // year of 2012?
899 // http://www.cpearson.com/excel/datedif.aspx "DATEDIF And Leap
900 // Years" is not correct and Excel 2010 correctly returns 0 in
901 // both cases mentioned there. Also using year1 as mentioned
902 // produces incorrect results in other cases and different from
903 // Excel 2010. Apparently they fixed some calculations.
904 aDate1.Normalize();
905 double fd = aDate2 - aDate1;
906 PushDouble( fd );
907 }
908 else
909 PushIllegalArgument(); // unsupported format
910}
911
913{
914 OUString aInputString = GetString().getString();
915 sal_uInt32 nFIndex = 0; // damit default Land/Spr.
916 double fVal;
917 if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal, SvNumInputOptions::LAX_TIME))
918 {
920 if (eType == SvNumFormatType::TIME || eType == SvNumFormatType::DATETIME)
921 {
922 nFuncFmtType = SvNumFormatType::TIME;
923 double fDateVal = rtl::math::approxFloor(fVal);
924 double fTimeVal = fVal - fDateVal;
925 PushDouble(fTimeVal);
926 }
927 else
929 }
930 else
932}
933
935{
936 double fVal = GetDouble();
937 short n = 0;
938 if (fVal < 0.0)
939 n = -1;
940 else if (fVal > 0.0)
941 n = 1;
942 PushInt( n );
943}
944
946{
947 PushDouble(std::abs(GetDouble()));
948}
949
951{
952 PushDouble(::rtl::math::approxFloor(GetDouble()));
953}
954
955void ScInterpreter::RoundNumber( rtl_math_RoundingMode eMode )
956{
957 sal_uInt8 nParamCount = GetByte();
958 if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
959 return;
960
961 double fVal = 0.0;
962 if (nParamCount == 1)
963 fVal = ::rtl::math::round( GetDouble(), 0, eMode );
964 else
965 {
966 const sal_Int16 nDec = GetInt16();
967 const double fX = GetDouble();
968 if (nGlobalError == FormulaError::NONE)
969 {
970 // A quite aggressive approach with 12 significant digits.
971 // However, using 14 or some other doesn't work because other
972 // values may fail, like =ROUNDDOWN(2-5E-015;13) would produce
973 // 2 (another example in tdf#124286).
974 constexpr sal_Int16 kSigDig = 12;
975
976 if ( ( eMode == rtl_math_RoundingMode_Down ||
977 eMode == rtl_math_RoundingMode_Up ) &&
978 nDec < kSigDig && fmod( fX, 1.0 ) != 0.0 )
979
980 {
981 // tdf124286 : round to significant digits before rounding
982 // down or up to avoid unexpected rounding errors
983 // caused by decimal -> binary -> decimal conversion
984
985 double fRes = fX;
986 // Similar to RoundSignificant() but omitting the back-scaling
987 // and interim integer rounding before the final rounding,
988 // which would result in double rounding. Instead, adjust the
989 // decimals and round into integer part before scaling back.
990 const double fTemp = floor( log10( std::abs(fRes))) + 1.0 - kSigDig;
991 // Avoid inaccuracy of negative powers of 10.
992 if (fTemp < 0.0)
993 fRes *= pow(10.0, -fTemp);
994 else
995 fRes /= pow(10.0, fTemp);
996 if (std::isfinite(fRes))
997 {
998 // fRes is now at a decimal normalized scale.
999 // Truncate up-rounding to opposite direction for values
1000 // like 0.0600000000000005 =ROUNDUP(8.06-8;2) that here now
1001 // is 600000000000.005 and otherwise would yield 0.07
1002 if (eMode == rtl_math_RoundingMode_Up)
1003 fRes = ::rtl::math::approxFloor(fRes);
1004 fVal = ::rtl::math::round( fRes, nDec + fTemp, eMode );
1005 if (fTemp < 0.0)
1006 fVal /= pow(10.0, -fTemp);
1007 else
1008 fVal *= pow(10.0, fTemp);
1009 }
1010 else
1011 {
1012 // Overflow. Let our round() decide if and how to round.
1013 fVal = ::rtl::math::round( fX, nDec, eMode );
1014 }
1015 }
1016 else
1017 fVal = ::rtl::math::round( fX, nDec, eMode );
1018 }
1019 }
1020 PushDouble(fVal);
1021}
1022
1024{
1025 RoundNumber( rtl_math_RoundingMode_Corrected );
1026}
1027
1029{
1030 RoundNumber( rtl_math_RoundingMode_Down );
1031}
1032
1034{
1035 RoundNumber( rtl_math_RoundingMode_Up );
1036}
1037
1038void ScInterpreter::RoundSignificant( double fX, double fDigits, double &fRes )
1039{
1040 double fTemp = floor( log10( std::abs(fX) ) ) + 1.0 - fDigits;
1041 double fIn = fX;
1042 // Avoid inaccuracy of negative powers of 10.
1043 if (fTemp < 0.0)
1044 fIn *= pow(10.0, -fTemp);
1045 else
1046 fIn /= pow(10.0, fTemp);
1047 // For very large fX there might be an overflow in fIn resulting in
1048 // non-finite. rtl::math::round() handles that and it will be propagated as
1049 // usual.
1050 fRes = ::rtl::math::round(fIn);
1051 if (fTemp < 0.0)
1052 fRes /= pow(10.0, -fTemp);
1053 else
1054 fRes *= pow(10.0, fTemp);
1055}
1056
1057// tdf#105931
1059{
1060 if ( !MustHaveParamCount( GetByte(), 2 ) )
1061 return;
1062
1063 double fDigits = ::rtl::math::approxFloor( GetDouble() );
1064 double fX = GetDouble();
1065 if ( nGlobalError != FormulaError::NONE || fDigits < 1.0 )
1066 {
1068 return;
1069 }
1070
1071 if ( fX == 0.0 )
1072 PushDouble( 0.0 );
1073 else
1074 {
1075 double fRes;
1076 RoundSignificant( fX, fDigits, fRes );
1077 PushDouble( fRes );
1078 }
1079}
1080
1088void ScInterpreter::ScCeil( bool bODFF )
1089{
1090 sal_uInt8 nParamCount = GetByte();
1091 if ( !MustHaveParamCount( nParamCount, 1, 3 ) )
1092 return;
1093
1094 bool bAbs = nParamCount == 3 && GetBool();
1095 double fDec, fVal;
1096 if ( nParamCount == 1 )
1097 {
1098 fVal = GetDouble();
1099 fDec = ( fVal < 0 ? -1 : 1 );
1100 }
1101 else
1102 {
1103 bool bArgumentMissing = IsMissing();
1104 fDec = GetDouble();
1105 fVal = GetDouble();
1106 if ( bArgumentMissing )
1107 fDec = ( fVal < 0 ? -1 : 1 );
1108 }
1109 if ( fVal == 0 || fDec == 0.0 )
1110 PushInt( 0 );
1111 else
1112 {
1113 if ( bODFF && fVal * fDec < 0 )
1115 else
1116 {
1117 if ( fVal * fDec < 0.0 )
1118 fDec = -fDec;
1119
1120 if ( !bAbs && fVal < 0.0 )
1121 PushDouble(::rtl::math::approxFloor( fVal / fDec ) * fDec );
1122 else
1123 PushDouble(::rtl::math::approxCeil( fVal / fDec ) * fDec );
1124 }
1125 }
1126}
1127
1129{
1130 sal_uInt8 nParamCount = GetByte();
1131 if ( !MustHaveParamCount( nParamCount, 2 ) )
1132 return;
1133
1134 double fDec = GetDouble();
1135 double fVal = GetDouble();
1136 if ( fVal == 0 || fDec == 0.0 )
1137 PushInt(0);
1138 else if ( fVal * fDec > 0 )
1139 PushDouble(::rtl::math::approxCeil( fVal / fDec ) * fDec );
1140 else if ( fVal < 0.0 )
1141 PushDouble(::rtl::math::approxFloor( fVal / -fDec ) * -fDec );
1142 else
1144}
1145
1147{
1148 sal_uInt8 nParamCount = GetByte();
1149 if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
1150 return;
1151
1152 double fDec, fVal;
1153 if ( nParamCount == 1 )
1154 {
1155 fVal = GetDouble();
1156 fDec = 1.0;
1157 }
1158 else
1159 {
1160 fDec = std::abs( GetDoubleWithDefault( 1.0 ));
1161 fVal = GetDouble();
1162 }
1163 if ( fDec == 0.0 || fVal == 0.0 )
1164 PushInt( 0 );
1165 else
1166 PushDouble(::rtl::math::approxCeil( fVal / fDec ) * fDec );
1167}
1168
1176void ScInterpreter::ScFloor( bool bODFF )
1177{
1178 sal_uInt8 nParamCount = GetByte();
1179 if ( !MustHaveParamCount( nParamCount, 1, 3 ) )
1180 return;
1181
1182 bool bAbs = ( nParamCount == 3 && GetBool() );
1183 double fDec, fVal;
1184 if ( nParamCount == 1 )
1185 {
1186 fVal = GetDouble();
1187 fDec = ( fVal < 0 ? -1 : 1 );
1188 }
1189 else
1190 {
1191 bool bArgumentMissing = IsMissing();
1192 fDec = GetDouble();
1193 fVal = GetDouble();
1194 if ( bArgumentMissing )
1195 fDec = ( fVal < 0 ? -1 : 1 );
1196 }
1197 if ( fDec == 0.0 || fVal == 0.0 )
1198 PushInt( 0 );
1199 else
1200 {
1201 if ( bODFF && ( fVal * fDec < 0.0 ) )
1203 else
1204 {
1205 if ( fVal * fDec < 0.0 )
1206 fDec = -fDec;
1207
1208 if ( !bAbs && fVal < 0.0 )
1209 PushDouble(::rtl::math::approxCeil( fVal / fDec ) * fDec );
1210 else
1211 PushDouble(::rtl::math::approxFloor( fVal / fDec ) * fDec );
1212 }
1213 }
1214}
1215
1217{
1218 sal_uInt8 nParamCount = GetByte();
1219 if ( !MustHaveParamCount( nParamCount, 2 ) )
1220 return;
1221
1222 double fDec = GetDouble();
1223 double fVal = GetDouble();
1224
1225 if ( fVal == 0 )
1226 PushInt( 0 );
1227 else if ( fVal * fDec > 0 )
1228 PushDouble(::rtl::math::approxFloor( fVal / fDec ) * fDec );
1229 else if ( fDec == 0 )
1231 else if ( fVal < 0.0 )
1232 PushDouble(::rtl::math::approxCeil( fVal / -fDec ) * -fDec );
1233 else
1235}
1236
1238{
1239 sal_uInt8 nParamCount = GetByte();
1240 if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
1241 return;
1242
1243 double fDec = nParamCount == 1 ? 1.0 : std::abs( GetDoubleWithDefault( 1.0 ) );
1244 double fVal = GetDouble();
1245 if ( fDec == 0.0 || fVal == 0.0 )
1246 PushInt( 0 );
1247 else
1248 PushDouble(::rtl::math::approxFloor( fVal / fDec ) * fDec );
1249}
1250
1252{
1253 double fVal = GetDouble();
1254 if (fVal < 0.0)
1255 PushDouble(::rtl::math::approxFloor(fVal/2.0) * 2.0);
1256 else
1257 PushDouble(::rtl::math::approxCeil(fVal/2.0) * 2.0);
1258}
1259
1261{
1262 double fVal = GetDouble();
1263 if (fVal >= 0.0)
1264 {
1265 fVal = ::rtl::math::approxCeil(fVal);
1266 if (fmod(fVal, 2.0) == 0.0)
1267 ++fVal;
1268 }
1269 else
1270 {
1271 fVal = ::rtl::math::approxFloor(fVal);
1272 if (fmod(fVal, 2.0) == 0.0)
1273 --fVal;
1274 }
1275 PushDouble(fVal);
1276}
1277
1279{
1280 if ( MustHaveParamCount( GetByte(), 2 ) )
1281 {
1282 double fVal2 = GetDouble();
1283 double fVal1 = GetDouble();
1284 PushDouble(atan2(fVal2, fVal1));
1285 }
1286}
1287
1289{
1290 sal_uInt8 nParamCount = GetByte();
1291 if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
1292 return;
1293
1294 double fBase = nParamCount == 2 ? GetDouble() : 10.0;
1295 double fVal = GetDouble();
1296 if (fVal > 0.0 && fBase > 0.0 && fBase != 1.0)
1297 PushDouble(log(fVal) / log(fBase));
1298 else
1300}
1301
1303{
1304 double fVal = GetDouble();
1305 if (fVal > 0.0)
1306 PushDouble(log(fVal));
1307 else
1309}
1310
1312{
1313 double fVal = GetDouble();
1314 if (fVal > 0.0)
1315 PushDouble(log10(fVal));
1316 else
1318}
1319
1321{
1322 nFuncFmtType = SvNumFormatType::CURRENCY;
1323 short nParamCount = GetByte();
1324 if ( !MustHaveParamCountMin( nParamCount, 2) )
1325 return;
1326
1327 KahanSum fVal = 0.0;
1328 // We turn the stack upside down!
1329 ReverseStack( nParamCount);
1330 if (nGlobalError == FormulaError::NONE)
1331 {
1332 double fCount = 1.0;
1333 double fRate = GetDouble();
1334 --nParamCount;
1335 size_t nRefInList = 0;
1336 ScRange aRange;
1337 while (nParamCount-- > 0)
1338 {
1339 switch (GetStackType())
1340 {
1341 case svDouble :
1342 {
1343 fVal += GetDouble() / pow(1.0 + fRate, fCount);
1344 fCount++;
1345 }
1346 break;
1347 case svSingleRef :
1348 {
1349 ScAddress aAdr;
1350 PopSingleRef( aAdr );
1351 ScRefCellValue aCell(mrDoc, aAdr);
1352 if (!aCell.hasEmptyValue() && aCell.hasNumeric())
1353 {
1354 double fCellVal = GetCellValue(aAdr, aCell);
1355 fVal += fCellVal / pow(1.0 + fRate, fCount);
1356 fCount++;
1357 }
1358 }
1359 break;
1360 case svDoubleRef :
1361 case svRefList :
1362 {
1363 FormulaError nErr = FormulaError::NONE;
1364 double fCellVal;
1365 PopDoubleRef( aRange, nParamCount, nRefInList);
1366 ScHorizontalValueIterator aValIter( mrDoc, aRange );
1367 while ((nErr == FormulaError::NONE) && aValIter.GetNext(fCellVal, nErr))
1368 {
1369 fVal += fCellVal / pow(1.0 + fRate, fCount);
1370 fCount++;
1371 }
1372 if ( nErr != FormulaError::NONE )
1373 SetError(nErr);
1374 }
1375 break;
1376 case svMatrix :
1379 {
1380 ScMatrixRef pMat = GetMatrix();
1381 if (pMat)
1382 {
1383 SCSIZE nC, nR;
1384 pMat->GetDimensions(nC, nR);
1385 if (nC == 0 || nR == 0)
1386 {
1388 return;
1389 }
1390 else
1391 {
1392 double fx;
1393 for ( SCSIZE j = 0; j < nC; j++ )
1394 {
1395 for (SCSIZE k = 0; k < nR; ++k)
1396 {
1397 if (!pMat->IsValue(j,k))
1398 {
1400 return;
1401 }
1402 fx = pMat->GetDouble(j,k);
1403 fVal += fx / pow(1.0 + fRate, fCount);
1404 fCount++;
1405 }
1406 }
1407 }
1408 }
1409 }
1410 break;
1411 default : SetError(FormulaError::IllegalParameter); break;
1412 }
1413 }
1414 }
1415 PushDouble(fVal.get());
1416}
1417
1419{
1420 nFuncFmtType = SvNumFormatType::PERCENT;
1421 sal_uInt8 nParamCount = GetByte();
1422 if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
1423 return;
1424 double fEstimated = nParamCount == 2 ? GetDouble() : 0.1;
1425 double fEps = 1.0;
1426 // If it's -1 the default result for division by zero else startvalue
1427 double x = fEstimated == -1.0 ? 0.1 : fEstimated;
1428 double fValue;
1429
1430 ScRange aRange;
1431 ScMatrixRef pMat;
1432 SCSIZE nC = 0;
1433 SCSIZE nR = 0;
1434 bool bIsMatrix = false;
1435 switch (GetStackType())
1436 {
1437 case svDoubleRef:
1438 PopDoubleRef(aRange);
1439 break;
1440 case svMatrix:
1443 pMat = GetMatrix();
1444 if (pMat)
1445 {
1446 pMat->GetDimensions(nC, nR);
1447 if (nC == 0 || nR == 0)
1448 {
1450 return;
1451 }
1452 bIsMatrix = true;
1453 }
1454 else
1455 {
1457 return;
1458 }
1459 break;
1460 default:
1461 {
1463 return;
1464 }
1465 }
1466 const sal_uInt16 nIterationsMax = 20;
1467 sal_uInt16 nItCount = 0;
1468 FormulaError nIterError = FormulaError::NONE;
1469 while (fEps > SCdEpsilon && nItCount < nIterationsMax && nGlobalError == FormulaError::NONE)
1470 { // Newtons method:
1471 KahanSum fNom = 0.0;
1472 KahanSum fDenom = 0.0;
1473 double fCount = 0.0;
1474 if (bIsMatrix)
1475 {
1476 for (SCSIZE j = 0; j < nC && nGlobalError == FormulaError::NONE; j++)
1477 {
1478 for (SCSIZE k = 0; k < nR; k++)
1479 {
1480 if (!pMat->IsValue(j, k))
1481 continue;
1482 fValue = pMat->GetDouble(j, k);
1483 if (nGlobalError != FormulaError::NONE)
1484 break;
1485
1486 fNom += fValue / pow(1.0+x,fCount);
1487 fDenom += -fCount * fValue / pow(1.0+x,fCount+1.0);
1488 fCount++;
1489 }
1490 }
1491 }
1492 else
1493 {
1494 ScValueIterator aValIter(mrContext, aRange, mnSubTotalFlags);
1495 bool bLoop = aValIter.GetFirst(fValue, nIterError);
1496 while (bLoop && nIterError == FormulaError::NONE)
1497 {
1498 fNom += fValue / pow(1.0+x,fCount);
1499 fDenom += -fCount * fValue / pow(1.0+x,fCount+1.0);
1500 fCount++;
1501
1502 bLoop = aValIter.GetNext(fValue, nIterError);
1503 }
1504 SetError(nIterError);
1505 }
1506 double xNew = x - fNom.get() / fDenom.get(); // x(i+1) = x(i)-f(x(i))/f'(x(i))
1507 nItCount++;
1508 fEps = std::abs(xNew - x);
1509 x = xNew;
1510 }
1511 if (fEstimated == 0.0 && std::abs(x) < SCdEpsilon)
1512 x = 0.0; // adjust to zero
1513 if (fEps < SCdEpsilon)
1514 PushDouble(x);
1515 else
1516 PushError( FormulaError::NoConvergence);
1517}
1518
1520{ // range_of_values ; rate_invest ; rate_reinvest
1521 nFuncFmtType = SvNumFormatType::PERCENT;
1522 if ( !MustHaveParamCount( GetByte(), 3 ) )
1523 return;
1524
1525 double fRate1_reinvest = GetDouble() + 1;
1526 double fRate1_invest = GetDouble() + 1;
1527
1528 ScRange aRange;
1529 ScMatrixRef pMat;
1530 SCSIZE nC = 0;
1531 SCSIZE nR = 0;
1532 bool bIsMatrix = false;
1533 switch ( GetStackType() )
1534 {
1535 case svDoubleRef :
1536 PopDoubleRef( aRange );
1537 break;
1538 case svMatrix :
1541 {
1542 pMat = GetMatrix();
1543 if ( pMat )
1544 {
1545 pMat->GetDimensions( nC, nR );
1546 if ( nC == 0 || nR == 0 )
1547 SetError( FormulaError::IllegalArgument );
1548 bIsMatrix = true;
1549 }
1550 else
1551 SetError( FormulaError::IllegalArgument );
1552 }
1553 break;
1554 default :
1555 SetError( FormulaError::IllegalParameter );
1556 break;
1557 }
1558
1559 if ( nGlobalError != FormulaError::NONE )
1561 else
1562 {
1563 KahanSum fNPV_reinvest = 0.0;
1564 double fPow_reinvest = 1.0;
1565 KahanSum fNPV_invest = 0.0;
1566 double fPow_invest = 1.0;
1567 sal_uLong nCount = 0;
1568 bool bHasPosValue = false;
1569 bool bHasNegValue = false;
1570
1571 if ( bIsMatrix )
1572 {
1573 double fX;
1574 for ( SCSIZE j = 0; j < nC; j++ )
1575 {
1576 for ( SCSIZE k = 0; k < nR; ++k )
1577 {
1578 if ( !pMat->IsValue( j, k ) )
1579 continue;
1580 fX = pMat->GetDouble( j, k );
1581 if ( nGlobalError != FormulaError::NONE )
1582 break;
1583
1584 if ( fX > 0.0 )
1585 { // reinvestments
1586 bHasPosValue = true;
1587 fNPV_reinvest += fX * fPow_reinvest;
1588 }
1589 else if ( fX < 0.0 )
1590 { // investments
1591 bHasNegValue = true;
1592 fNPV_invest += fX * fPow_invest;
1593 }
1594 fPow_reinvest /= fRate1_reinvest;
1595 fPow_invest /= fRate1_invest;
1596 nCount++;
1597 }
1598 }
1599 }
1600 else
1601 {
1602 ScValueIterator aValIter( mrContext, aRange, mnSubTotalFlags );
1603 double fCellValue;
1604 FormulaError nIterError = FormulaError::NONE;
1605
1606 bool bLoop = aValIter.GetFirst( fCellValue, nIterError );
1607 while( bLoop )
1608 {
1609 if( fCellValue > 0.0 ) // reinvestments
1610 { // reinvestments
1611 bHasPosValue = true;
1612 fNPV_reinvest += fCellValue * fPow_reinvest;
1613 }
1614 else if( fCellValue < 0.0 ) // investments
1615 { // investments
1616 bHasNegValue = true;
1617 fNPV_invest += fCellValue * fPow_invest;
1618 }
1619 fPow_reinvest /= fRate1_reinvest;
1620 fPow_invest /= fRate1_invest;
1621 nCount++;
1622
1623 bLoop = aValIter.GetNext( fCellValue, nIterError );
1624 }
1625
1626 if ( nIterError != FormulaError::NONE )
1627 SetError( nIterError );
1628 }
1629 if ( !( bHasPosValue && bHasNegValue ) )
1630 SetError( FormulaError::IllegalArgument );
1631
1632 if ( nGlobalError != FormulaError::NONE )
1634 else
1635 {
1636 double fResult = -fNPV_reinvest.get() / fNPV_invest.get();
1637 fResult *= pow( fRate1_reinvest, static_cast<double>( nCount - 1 ) );
1638 fResult = pow( fResult, div( 1.0, (nCount - 1)) );
1639 PushDouble( fResult - 1.0 );
1640 }
1641 }
1642}
1643
1645{ // rate ; period ; total_periods ; invest
1646 if( MustHaveParamCount( GetByte(), 4 ) )
1647 {
1648 double fInvest = GetDouble();
1649 double fTotal = GetDouble();
1650 double fPeriod = GetDouble();
1651 double fRate = GetDouble();
1652
1653 if( nGlobalError != FormulaError::NONE )
1655 else
1656 PushDouble( fInvest * fRate * (fPeriod / fTotal - 1.0) );
1657 }
1658}
1659
1660// financial functions
1661double ScInterpreter::ScGetPV(double fRate, double fNper, double fPmt,
1662 double fFv, bool bPayInAdvance)
1663{
1664 double fPv;
1665 if (fRate == 0.0)
1666 fPv = fFv + fPmt * fNper;
1667 else
1668 {
1669 if (bPayInAdvance)
1670 fPv = (fFv * pow(1.0 + fRate, -fNper))
1671 + (fPmt * (1.0 - pow(1.0 + fRate, -fNper + 1.0)) / fRate)
1672 + fPmt;
1673 else
1674 fPv = (fFv * pow(1.0 + fRate, -fNper))
1675 + (fPmt * (1.0 - pow(1.0 + fRate, -fNper)) / fRate);
1676 }
1677 return -fPv;
1678}
1679
1681{
1682 nFuncFmtType = SvNumFormatType::CURRENCY;
1683 sal_uInt8 nParamCount = GetByte();
1684 if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1685 return;
1686
1687 bool bPayInAdvance = nParamCount == 5 && GetBool();
1688 double fFv = nParamCount >= 4 ? GetDouble() : 0;
1689 double fPmt = GetDouble();
1690 double fNper = GetDouble();
1691 double fRate = GetDouble();
1692 PushDouble(ScGetPV(fRate, fNper, fPmt, fFv, bPayInAdvance));
1693}
1694
1696{
1697 nFuncFmtType = SvNumFormatType::CURRENCY;
1698 if ( MustHaveParamCount( GetByte(), 4 ) )
1699 {
1700 double fPer = GetDouble();
1701 double fLife = GetDouble();
1702 double fSalvage = GetDouble();
1703 double fCost = GetDouble();
1704 double fSyd = ((fCost - fSalvage) * (fLife - fPer + 1.0)) /
1705 ((fLife * (fLife + 1.0)) / 2.0);
1706 PushDouble(fSyd);
1707 }
1708}
1709
1710double ScInterpreter::ScGetDDB(double fCost, double fSalvage, double fLife,
1711 double fPeriod, double fFactor)
1712{
1713 double fDdb, fRate, fOldValue, fNewValue;
1714 fRate = fFactor / fLife;
1715 if (fRate >= 1.0)
1716 {
1717 fRate = 1.0;
1718 fOldValue = fPeriod == 1.0 ? fCost : 0;
1719 }
1720 else
1721 fOldValue = fCost * pow(1.0 - fRate, fPeriod - 1.0);
1722 fNewValue = fCost * pow(1.0 - fRate, fPeriod);
1723
1724 fDdb = fNewValue < fSalvage ? fOldValue - fSalvage : fOldValue - fNewValue;
1725 return fDdb < 0 ? 0 : fDdb;
1726}
1727
1729{
1730 nFuncFmtType = SvNumFormatType::CURRENCY;
1731 sal_uInt8 nParamCount = GetByte();
1732 if ( !MustHaveParamCount( nParamCount, 4, 5 ) )
1733 return;
1734
1735 double fFactor = nParamCount == 5 ? GetDouble() : 2.0;
1736 double fPeriod = GetDouble();
1737 double fLife = GetDouble();
1738 double fSalvage = GetDouble();
1739 double fCost = GetDouble();
1740 if (fCost < 0.0 || fSalvage < 0.0 || fFactor <= 0.0 || fSalvage > fCost
1741 || fPeriod < 1.0 || fPeriod > fLife)
1743 else
1744 PushDouble(ScGetDDB(fCost, fSalvage, fLife, fPeriod, fFactor));
1745}
1746
1748{
1749 nFuncFmtType = SvNumFormatType::CURRENCY;
1750 sal_uInt8 nParamCount = GetByte();
1751 if ( !MustHaveParamCount( nParamCount, 4, 5 ) )
1752 return ;
1753 double fMonths = nParamCount == 4 ? 12.0 : ::rtl::math::approxFloor(GetDouble());
1754 double fPeriod = GetDouble();
1755 double fLife = GetDouble();
1756 double fSalvage = GetDouble();
1757 double fCost = GetDouble();
1758 if (fMonths < 1.0 || fMonths > 12.0 || fLife > 1200.0 || fSalvage < 0.0 ||
1759 fPeriod > (fLife + 1.0) || fSalvage > fCost || fCost <= 0.0 ||
1760 fLife <= 0 || fPeriod <= 0 )
1761 {
1763 return;
1764 }
1765 double fOffRate = 1.0 - pow(fSalvage / fCost, 1.0 / fLife);
1766 fOffRate = ::rtl::math::approxFloor((fOffRate * 1000.0) + 0.5) / 1000.0;
1767 double fFirstOffRate = fCost * fOffRate * fMonths / 12.0;
1768 double fDb = 0.0;
1769 if (::rtl::math::approxFloor(fPeriod) == 1)
1770 fDb = fFirstOffRate;
1771 else
1772 {
1773 KahanSum fSumOffRate = fFirstOffRate;
1774 double fMin = fLife;
1775 if (fMin > fPeriod) fMin = fPeriod;
1776 sal_uInt16 iMax = static_cast<sal_uInt16>(::rtl::math::approxFloor(fMin));
1777 for (sal_uInt16 i = 2; i <= iMax; i++)
1778 {
1779 fDb = -(fSumOffRate - fCost).get() * fOffRate;
1780 fSumOffRate += fDb;
1781 }
1782 if (fPeriod > fLife)
1783 fDb = -(fSumOffRate - fCost).get() * fOffRate * (12.0 - fMonths) / 12.0;
1784 }
1785 PushDouble(fDb);
1786}
1787
1788double ScInterpreter::ScInterVDB(double fCost, double fSalvage, double fLife,
1789 double fLife1, double fPeriod, double fFactor)
1790{
1791 KahanSum fVdb = 0.0;
1792 double fIntEnd = ::rtl::math::approxCeil(fPeriod);
1793 sal_uLong nLoopEnd = static_cast<sal_uLong>(fIntEnd);
1794
1795 double fTerm, fSln = 0; // SLN: Straight-Line Depreciation
1796 double fSalvageValue = fCost - fSalvage;
1797 bool bNowSln = false;
1798
1799 double fDdb;
1800 sal_uLong i;
1801 for ( i = 1; i <= nLoopEnd; i++)
1802 {
1803 if(!bNowSln)
1804 {
1805 fDdb = ScGetDDB(fCost, fSalvage, fLife, static_cast<double>(i), fFactor);
1806 fSln = fSalvageValue/ (fLife1 - static_cast<double>(i-1));
1807
1808 if (fSln > fDdb)
1809 {
1810 fTerm = fSln;
1811 bNowSln = true;
1812 }
1813 else
1814 {
1815 fTerm = fDdb;
1816 fSalvageValue -= fDdb;
1817 }
1818 }
1819 else
1820 {
1821 fTerm = fSln;
1822 }
1823
1824 if ( i == nLoopEnd)
1825 fTerm *= ( fPeriod + 1.0 - fIntEnd );
1826
1827 fVdb += fTerm;
1828 }
1829 return fVdb.get();
1830}
1831
1833{
1834 nFuncFmtType = SvNumFormatType::CURRENCY;
1835 sal_uInt8 nParamCount = GetByte();
1836 if ( !MustHaveParamCount( nParamCount, 5, 7 ) )
1837 return;
1838
1839 KahanSum fVdb = 0.0;
1840 bool bNoSwitch = nParamCount == 7 && GetBool();
1841 double fFactor = nParamCount >= 6 ? GetDouble() : 2.0;
1842 double fEnd = GetDouble();
1843 double fStart = GetDouble();
1844 double fLife = GetDouble();
1845 double fSalvage = GetDouble();
1846 double fCost = GetDouble();
1847 if (fStart < 0.0 || fEnd < fStart || fEnd > fLife || fCost < 0.0
1848 || fSalvage > fCost || fFactor <= 0.0)
1850 else
1851 {
1852 double fIntStart = ::rtl::math::approxFloor(fStart);
1853 double fIntEnd = ::rtl::math::approxCeil(fEnd);
1854 sal_uLong nLoopStart = static_cast<sal_uLong>(fIntStart);
1855 sal_uLong nLoopEnd = static_cast<sal_uLong>(fIntEnd);
1856
1857 if (bNoSwitch)
1858 {
1859 for (sal_uLong i = nLoopStart + 1; i <= nLoopEnd; i++)
1860 {
1861 double fTerm = ScGetDDB(fCost, fSalvage, fLife, static_cast<double>(i), fFactor);
1862
1863 //respect partial period in the Beginning/ End:
1864 if ( i == nLoopStart+1 )
1865 fTerm *= ( std::min( fEnd, fIntStart + 1.0 ) - fStart );
1866 else if ( i == nLoopEnd )
1867 fTerm *= ( fEnd + 1.0 - fIntEnd );
1868
1869 fVdb += fTerm;
1870 }
1871 }
1872 else
1873 {
1874 double fPart = 0.0;
1875 // respect partial period in the Beginning / End:
1876 if ( !::rtl::math::approxEqual( fStart, fIntStart ) ||
1877 !::rtl::math::approxEqual( fEnd, fIntEnd ) )
1878 {
1879 if ( !::rtl::math::approxEqual( fStart, fIntStart ) )
1880 {
1881 // part to be subtracted at the beginning
1882 double fTempIntEnd = fIntStart + 1.0;
1883 double fTempValue = fCost -
1884 ScInterVDB( fCost, fSalvage, fLife, fLife, fIntStart, fFactor );
1885 fPart += ( fStart - fIntStart ) *
1886 ScInterVDB( fTempValue, fSalvage, fLife, fLife - fIntStart,
1887 fTempIntEnd - fIntStart, fFactor);
1888 }
1889 if ( !::rtl::math::approxEqual( fEnd, fIntEnd ) )
1890 {
1891 // part to be subtracted at the end
1892 double fTempIntStart = fIntEnd - 1.0;
1893 double fTempValue = fCost -
1894 ScInterVDB( fCost, fSalvage, fLife, fLife, fTempIntStart, fFactor );
1895 fPart += ( fIntEnd - fEnd ) *
1896 ScInterVDB( fTempValue, fSalvage, fLife, fLife - fTempIntStart,
1897 fIntEnd - fTempIntStart, fFactor);
1898 }
1899 }
1900 // calculate depreciation for whole periods
1901 fCost -= ScInterVDB( fCost, fSalvage, fLife, fLife, fIntStart, fFactor );
1902 fVdb = ScInterVDB( fCost, fSalvage, fLife, fLife - fIntStart,
1903 fIntEnd - fIntStart, fFactor);
1904 fVdb -= fPart;
1905 }
1906 }
1907 PushDouble(fVdb.get());
1908}
1909
1911{
1912 if ( MustHaveParamCount( GetByte(), 3 ) )
1913 {
1914 double fFuture = GetDouble();
1915 double fPresent = GetDouble();
1916 double fRate = GetDouble();
1917 if ( fFuture <= 0.0 || fPresent <= 0.0 || fRate <= 0.0 )
1919 else
1920 PushDouble( std::log( fFuture / fPresent ) / std::log1p( fRate ) );
1921 }
1922}
1923
1925{
1926 nFuncFmtType = SvNumFormatType::CURRENCY;
1927 if ( MustHaveParamCount( GetByte(), 3 ) )
1928 {
1929 double fLife = GetDouble();
1930 double fSalvage = GetDouble();
1931 double fCost = GetDouble();
1932 PushDouble( div( fCost - fSalvage, fLife ) );
1933 }
1934}
1935
1936double ScInterpreter::ScGetPMT(double fRate, double fNper, double fPv,
1937 double fFv, bool bPayInAdvance)
1938{
1939 double fPayment;
1940 if (fRate == 0.0)
1941 fPayment = (fPv + fFv) / fNper;
1942 else
1943 {
1944 if (bPayInAdvance) // payment in advance
1945 fPayment = (fFv + fPv * exp( fNper * ::std::log1p(fRate) ) ) * fRate /
1946 (std::expm1( (fNper + 1) * ::std::log1p(fRate) ) - fRate);
1947 else // payment in arrear
1948 fPayment = (fFv + fPv * exp(fNper * ::std::log1p(fRate) ) ) * fRate /
1949 std::expm1( fNper * ::std::log1p(fRate) );
1950 }
1951 return -fPayment;
1952}
1953
1955{
1956 nFuncFmtType = SvNumFormatType::CURRENCY;
1957 sal_uInt8 nParamCount = GetByte();
1958 if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1959 return;
1960 bool bPayInAdvance = nParamCount == 5 && GetBool();
1961 double fFv = nParamCount >= 4 ? GetDouble() : 0;
1962 double fPv = GetDouble();
1963 double fNper = GetDouble();
1964 double fRate = GetDouble();
1965 PushDouble(ScGetPMT(fRate, fNper, fPv, fFv, bPayInAdvance));
1966}
1967
1969{
1970 nFuncFmtType = SvNumFormatType::PERCENT;
1971 if ( MustHaveParamCount( GetByte(), 3 ) )
1972 {
1973 double fFutureValue = GetDouble();
1974 double fPresentValue = GetDouble();
1975 double fNrOfPeriods = GetDouble();
1976 if ( fNrOfPeriods <= 0.0 || fPresentValue == 0.0 )
1978 else
1979 PushDouble(pow(fFutureValue / fPresentValue, 1.0 / fNrOfPeriods) - 1.0);
1980 }
1981}
1982
1983double ScInterpreter::ScGetFV(double fRate, double fNper, double fPmt,
1984 double fPv, bool bPayInAdvance)
1985{
1986 double fFv;
1987 if (fRate == 0.0)
1988 fFv = fPv + fPmt * fNper;
1989 else
1990 {
1991 double fTerm = pow(1.0 + fRate, fNper);
1992 if (bPayInAdvance)
1993 fFv = fPv * fTerm + fPmt*(1.0 + fRate)*(fTerm - 1.0)/fRate;
1994 else
1995 fFv = fPv * fTerm + fPmt*(fTerm - 1.0)/fRate;
1996 }
1997 return -fFv;
1998}
1999
2001{
2002 nFuncFmtType = SvNumFormatType::CURRENCY;
2003 sal_uInt8 nParamCount = GetByte();
2004 if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
2005 return;
2006 bool bPayInAdvance = nParamCount == 5 && GetBool();
2007 double fPv = nParamCount >= 4 ? GetDouble() : 0;
2008 double fPmt = GetDouble();
2009 double fNper = GetDouble();
2010 double fRate = GetDouble();
2011 PushDouble(ScGetFV(fRate, fNper, fPmt, fPv, bPayInAdvance));
2012}
2013
2015{
2016 sal_uInt8 nParamCount = GetByte();
2017 if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
2018 return;
2019 bool bPayInAdvance = nParamCount == 5 && GetBool();
2020 double fFV = nParamCount >= 4 ? GetDouble() : 0;
2021 double fPV = GetDouble(); // Present Value
2022 double fPmt = GetDouble(); // Payment
2023 double fRate = GetDouble();
2024 // Note that due to the function specification in ODFF1.2 (and Excel) the
2025 // amount to be paid to get from fPV to fFV is fFV_+_fPV.
2026 if ( fPV + fFV == 0.0 )
2027 PushDouble( 0.0 );
2028 else if (fRate == 0.0)
2029 PushDouble(-(fPV + fFV)/fPmt);
2030 else if (bPayInAdvance)
2031 PushDouble(log(-(fRate*fFV-fPmt*(1.0+fRate))/(fRate*fPV+fPmt*(1.0+fRate)))
2032 / std::log1p(fRate));
2033 else
2034 PushDouble(log(-(fRate*fFV-fPmt)/(fRate*fPV+fPmt)) / std::log1p(fRate));
2035}
2036
2037bool ScInterpreter::RateIteration( double fNper, double fPayment, double fPv,
2038 double fFv, bool bPayType, double & fGuess )
2039{
2040 // See also #i15090#
2041 // Newton-Raphson method: x(i+1) = x(i) - f(x(i)) / f'(x(i))
2042 // This solution handles integer and non-integer values of Nper different.
2043 // If ODFF will constraint Nper to integer, the distinction of cases can be
2044 // removed; only the integer-part is needed then.
2045 bool bValid = true, bFound = false;
2046 double fX, fXnew, fTerm, fTermDerivation;
2047 double fGeoSeries, fGeoSeriesDerivation;
2048 const sal_uInt16 nIterationsMax = 150;
2049 sal_uInt16 nCount = 0;
2050 const double fEpsilonSmall = 1.0E-14;
2051 if ( bPayType )
2052 {
2053 // payment at beginning of each period
2054 fFv = fFv - fPayment;
2055 fPv = fPv + fPayment;
2056 }
2057 if (fNper == ::rtl::math::round( fNper ))
2058 { // Nper is an integer value
2059 fX = fGuess;
2060 while (!bFound && nCount < nIterationsMax)
2061 {
2062 double fPowN, fPowNminus1; // for (1.0+fX)^Nper and (1.0+fX)^(Nper-1)
2063 fPowNminus1 = pow( 1.0+fX, fNper-1.0);
2064 fPowN = fPowNminus1 * (1.0+fX);
2065 if (fX == 0.0)
2066 {
2067 fGeoSeries = fNper;
2068 fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
2069 }
2070 else
2071 {
2072 fGeoSeries = (fPowN-1.0)/fX;
2073 fGeoSeriesDerivation = fNper * fPowNminus1 / fX - fGeoSeries / fX;
2074 }
2075 fTerm = fFv + fPv *fPowN+ fPayment * fGeoSeries;
2076 fTermDerivation = fPv * fNper * fPowNminus1 + fPayment * fGeoSeriesDerivation;
2077 if (std::abs(fTerm) < fEpsilonSmall)
2078 bFound = true; // will catch root which is at an extreme
2079 else
2080 {
2081 if (fTermDerivation == 0.0)
2082 fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
2083 else
2084 fXnew = fX - fTerm / fTermDerivation;
2085 nCount++;
2086 // more accuracy not possible in oscillating cases
2087 bFound = (std::abs(fXnew - fX) < SCdEpsilon);
2088 fX = fXnew;
2089 }
2090 }
2091 // Gnumeric returns roots < -1, Excel gives an error in that cases,
2092 // ODFF says nothing about it. Enable the statement, if you want Excel's
2093 // behavior.
2094 //bValid =(fX >=-1.0);
2095 // Update 2013-06-17: Gnumeric (v1.12.2) doesn't return roots <= -1
2096 // anymore.
2097 bValid = (fX > -1.0);
2098 }
2099 else
2100 { // Nper is not an integer value.
2101 fX = (fGuess < -1.0) ? -1.0 : fGuess; // start with a valid fX
2102 while (bValid && !bFound && nCount < nIterationsMax)
2103 {
2104 if (fX == 0.0)
2105 {
2106 fGeoSeries = fNper;
2107 fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
2108 }
2109 else
2110 {
2111 fGeoSeries = (pow( 1.0+fX, fNper) - 1.0) / fX;
2112 fGeoSeriesDerivation = fNper * pow( 1.0+fX, fNper-1.0) / fX - fGeoSeries / fX;
2113 }
2114 fTerm = fFv + fPv *pow(1.0 + fX,fNper)+ fPayment * fGeoSeries;
2115 fTermDerivation = fPv * fNper * pow( 1.0+fX, fNper-1.0) + fPayment * fGeoSeriesDerivation;
2116 if (std::abs(fTerm) < fEpsilonSmall)
2117 bFound = true; // will catch root which is at an extreme
2118 else
2119 {
2120 if (fTermDerivation == 0.0)
2121 fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
2122 else
2123 fXnew = fX - fTerm / fTermDerivation;
2124 nCount++;
2125 // more accuracy not possible in oscillating cases
2126 bFound = (std::abs(fXnew - fX) < SCdEpsilon);
2127 fX = fXnew;
2128 bValid = (fX >= -1.0); // otherwise pow(1.0+fX,fNper) will fail
2129 }
2130 }
2131 }
2132 fGuess = fX; // return approximate root
2133 return bValid && bFound;
2134}
2135
2136// In Calc UI it is the function RATE(Nper;Pmt;Pv;Fv;Type;Guess)
2138{
2139 nFuncFmtType = SvNumFormatType::PERCENT;
2140 sal_uInt8 nParamCount = GetByte();
2141 if ( !MustHaveParamCount( nParamCount, 3, 6 ) )
2142 return;
2143
2144 // defaults for missing arguments, see ODFF spec
2145 double fGuess = nParamCount == 6 ? GetDouble() : 0.1;
2146 bool bDefaultGuess = nParamCount != 6;
2147 bool bPayType = nParamCount >= 5 && GetBool();
2148 double fFv = nParamCount >= 4 ? GetDouble() : 0;
2149 double fPv = GetDouble();
2150 double fPayment = GetDouble();
2151 double fNper = GetDouble();
2152 double fOrigGuess = fGuess;
2153
2154 if (fNper <= 0.0) // constraint from ODFF spec
2155 {
2157 return;
2158 }
2159 bool bValid = RateIteration(fNper, fPayment, fPv, fFv, bPayType, fGuess);
2160
2161 if (!bValid)
2162 {
2163 /* TODO: try also for specified guess values, not only default? As is,
2164 * a specified 0.1 guess may be error result but a default 0.1 guess
2165 * may succeed. On the other hand, using a different guess value than
2166 * the specified one may not be desired, even if that didn't match. */
2167 if (bDefaultGuess)
2168 {
2169 /* TODO: this is rather ugly, instead of looping over different
2170 * guess values and doing a Newton goal seek for each we could
2171 * first insert the values into the RATE equation to obtain a set
2172 * of y values and then do a bisecting goal seek, possibly using
2173 * different algorithms. */
2174 double fX = fOrigGuess;
2175 for (int nStep = 2; nStep <= 10 && !bValid; ++nStep)
2176 {
2177 fGuess = fX * nStep;
2178 bValid = RateIteration( fNper, fPayment, fPv, fFv, bPayType, fGuess);
2179 if (!bValid)
2180 {
2181 fGuess = fX / nStep;
2182 bValid = RateIteration( fNper, fPayment, fPv, fFv, bPayType, fGuess);
2183 }
2184 }
2185 }
2186 if (!bValid)
2187 SetError(FormulaError::NoConvergence);
2188 }
2189 PushDouble(fGuess);
2190}
2191
2192double ScInterpreter::ScGetIpmt(double fRate, double fPer, double fNper, double fPv,
2193 double fFv, bool bPayInAdvance, double& fPmt)
2194{
2195 fPmt = ScGetPMT(fRate, fNper, fPv, fFv, bPayInAdvance); // for PPMT also if fPer == 1
2196 double fIpmt;
2197 nFuncFmtType = SvNumFormatType::CURRENCY;
2198 if (fPer == 1.0)
2199 fIpmt = bPayInAdvance ? 0.0 : -fPv;
2200 else
2201 {
2202 if (bPayInAdvance)
2203 fIpmt = ScGetFV(fRate, fPer-2.0, fPmt, fPv, true) - fPmt;
2204 else
2205 fIpmt = ScGetFV(fRate, fPer-1.0, fPmt, fPv, false);
2206 }
2207 return fIpmt * fRate;
2208}
2209
2211{
2212 nFuncFmtType = SvNumFormatType::CURRENCY;
2213 sal_uInt8 nParamCount = GetByte();
2214 if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
2215 return;
2216 bool bPayInAdvance = nParamCount == 6 && GetBool();
2217 double fFv = nParamCount >= 5 ? GetDouble() : 0;
2218 double fPv = GetDouble();
2219 double fNper = GetDouble();
2220 double fPer = GetDouble();
2221 double fRate = GetDouble();
2222 if (fPer < 1.0 || fPer > fNper)
2224 else
2225 {
2226 double fPmt;
2227 PushDouble(ScGetIpmt(fRate, fPer, fNper, fPv, fFv, bPayInAdvance, fPmt));
2228 }
2229}
2230
2232{
2233 nFuncFmtType = SvNumFormatType::CURRENCY;
2234 sal_uInt8 nParamCount = GetByte();
2235 if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
2236 return;
2237 bool bPayInAdvance = nParamCount == 6 && GetBool();
2238 double fFv = nParamCount >= 5 ? GetDouble() : 0;
2239 double fPv = GetDouble();
2240 double fNper = GetDouble();
2241 double fPer = GetDouble();
2242 double fRate = GetDouble();
2243 if (fPer < 1.0 || fPer > fNper)
2245 else
2246 {
2247 double fPmt;
2248 double fInterestPer = ScGetIpmt(fRate, fPer, fNper, fPv, fFv, bPayInAdvance, fPmt);
2249 PushDouble(fPmt - fInterestPer);
2250 }
2251}
2252
2254{
2255 nFuncFmtType = SvNumFormatType::CURRENCY;
2256 if ( !MustHaveParamCount( GetByte(), 6 ) )
2257 return;
2258
2259 double fFlag = GetDoubleWithDefault( -1.0 );
2260 double fEnd = ::rtl::math::approxFloor(GetDouble());
2261 double fStart = ::rtl::math::approxFloor(GetDouble());
2262 double fPv = GetDouble();
2263 double fNper = GetDouble();
2264 double fRate = GetDouble();
2265 if (fStart < 1.0 || fEnd < fStart || fRate <= 0.0 ||
2266 fEnd > fNper || fNper <= 0.0 || fPv <= 0.0 ||
2267 ( fFlag != 0.0 && fFlag != 1.0 ))
2269 else
2270 {
2271 bool bPayInAdvance = static_cast<bool>(fFlag);
2272 sal_uLong nStart = static_cast<sal_uLong>(fStart);
2273 sal_uLong nEnd = static_cast<sal_uLong>(fEnd) ;
2274 double fPmt = ScGetPMT(fRate, fNper, fPv, 0.0, bPayInAdvance);
2275 KahanSum fIpmt = 0.0;
2276 if (nStart == 1)
2277 {
2278 if (!bPayInAdvance)
2279 fIpmt = -fPv;
2280 nStart++;
2281 }
2282 for (sal_uLong i = nStart; i <= nEnd; i++)
2283 {
2284 if (bPayInAdvance)
2285 fIpmt += ScGetFV(fRate, static_cast<double>(i-2), fPmt, fPv, true) - fPmt;
2286 else
2287 fIpmt += ScGetFV(fRate, static_cast<double>(i-1), fPmt, fPv, false);
2288 }
2289 fIpmt *= fRate;
2290 PushDouble(fIpmt.get());
2291 }
2292}
2293
2295{
2296 nFuncFmtType = SvNumFormatType::CURRENCY;
2297 if ( !MustHaveParamCount( GetByte(), 6 ) )
2298 return;
2299
2300 double fFlag = GetDoubleWithDefault( -1.0 );
2301 double fEnd = ::rtl::math::approxFloor(GetDouble());
2302 double fStart = ::rtl::math::approxFloor(GetDouble());
2303 double fPv = GetDouble();
2304 double fNper = GetDouble();
2305 double fRate = GetDouble();
2306 if (fStart < 1.0 || fEnd < fStart || fRate <= 0.0 ||
2307 fEnd > fNper || fNper <= 0.0 || fPv <= 0.0 ||
2308 ( fFlag != 0.0 && fFlag != 1.0 ))
2310 else
2311 {
2312 bool bPayInAdvance = static_cast<bool>(fFlag);
2313 double fPmt = ScGetPMT(fRate, fNper, fPv, 0.0, bPayInAdvance);
2314 KahanSum fPpmt = 0.0;
2315 sal_uLong nStart = static_cast<sal_uLong>(fStart);
2316 sal_uLong nEnd = static_cast<sal_uLong>(fEnd);
2317 if (nStart == 1)
2318 {
2319 fPpmt = bPayInAdvance ? fPmt : fPmt + fPv * fRate;
2320 nStart++;
2321 }
2322 for (sal_uLong i = nStart; i <= nEnd; i++)
2323 {
2324 if (bPayInAdvance)
2325 fPpmt += fPmt - (ScGetFV(fRate, static_cast<double>(i-2), fPmt, fPv, true) - fPmt) * fRate;
2326 else
2327 fPpmt += fPmt - ScGetFV(fRate, static_cast<double>(i-1), fPmt, fPv, false) * fRate;
2328 }
2329 PushDouble(fPpmt.get());
2330 }
2331}
2332
2334{
2335 nFuncFmtType = SvNumFormatType::PERCENT;
2336 if ( !MustHaveParamCount( GetByte(), 2 ) )
2337 return;
2338
2339 double fPeriods = GetDouble();
2340 double fNominal = GetDouble();
2341 if (fPeriods < 1.0 || fNominal < 0.0)
2343 else if ( fNominal == 0.0 )
2344 PushDouble( 0.0 );
2345 else
2346 {
2347 fPeriods = ::rtl::math::approxFloor(fPeriods);
2348 PushDouble(pow(1.0 + fNominal/fPeriods, fPeriods) - 1.0);
2349 }
2350}
2351
2353{
2354 nFuncFmtType = SvNumFormatType::PERCENT;
2355 if ( MustHaveParamCount( GetByte(), 2 ) )
2356 {
2357 double fPeriods = GetDouble();
2358 double fEffective = GetDouble();
2359 if (fPeriods < 1.0 || fEffective <= 0.0)
2361 else
2362 {
2363 fPeriods = ::rtl::math::approxFloor(fPeriods);
2364 PushDouble( (pow(fEffective + 1.0, 1.0 / fPeriods) - 1.0) * fPeriods );
2365 }
2366 }
2367}
2368
2370{
2371 if ( !MustHaveParamCount( GetByte(), 2 ) )
2372 return;
2373
2374 double fDenom = GetDouble(); // Denominator
2375 if ( fDenom == 0.0 )
2376 {
2377 PushError(FormulaError::DivisionByZero);
2378 return;
2379 }
2380 double fNum = GetDouble(); // Numerator
2381 double fRes = ::rtl::math::approxSub( fNum,
2382 ::rtl::math::approxFloor( fNum / fDenom ) * fDenom );
2383 if ( ( fDenom > 0 && fRes >= 0 && fRes < fDenom ) ||
2384 ( fDenom < 0 && fRes <= 0 && fRes > fDenom ) )
2385 PushDouble( fRes );
2386 else
2387 PushError( FormulaError::NoValue );
2388}
2389
2391{
2394
2395 if (nGlobalError != FormulaError::NONE || !p2nd || !p1st)
2396 {
2398 return;
2399 }
2400
2401 StackVar sv1 = p1st->GetType();
2402 StackVar sv2 = p2nd->GetType();
2403 if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
2404 (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
2405 {
2407 return;
2408 }
2409
2410 const formula::FormulaToken* x1 = p1st.get();
2411 const formula::FormulaToken* x2 = p2nd.get();
2412 if (sv1 == svRefList || sv2 == svRefList)
2413 {
2414 // Now this is a bit nasty but it simplifies things, and having
2415 // intersections with lists isn't too common, if at all...
2416 // Convert a reference to list.
2417 const formula::FormulaToken* xt[2] = { x1, x2 };
2418 StackVar sv[2] = { sv1, sv2 };
2419 // There may only be one reference; the other is necessarily a list
2420 // Ensure converted list proper destruction
2421 std::unique_ptr<formula::FormulaToken> p;
2422 for (size_t i=0; i<2; ++i)
2423 {
2424 if (sv[i] == svSingleRef)
2425 {
2426 ScComplexRefData aRef;
2427 aRef.Ref1 = aRef.Ref2 = *xt[i]->GetSingleRef();
2428 p.reset(new ScRefListToken);
2429 p->GetRefList()->push_back( aRef);
2430 xt[i] = p.get();
2431 }
2432 else if (sv[i] == svDoubleRef)
2433 {
2434 ScComplexRefData aRef = *xt[i]->GetDoubleRef();
2435 p.reset(new ScRefListToken);
2436 p->GetRefList()->push_back( aRef);
2437 xt[i] = p.get();
2438 }
2439 }
2440 x1 = xt[0];
2441 x2 = xt[1];
2442
2443 ScTokenRef xRes = new ScRefListToken;
2444 ScRefList* pRefList = xRes->GetRefList();
2445 for (const auto& rRef1 : *x1->GetRefList())
2446 {
2447 const ScAddress& r11 = rRef1.Ref1.toAbs(mrDoc, aPos);
2448 const ScAddress& r12 = rRef1.Ref2.toAbs(mrDoc, aPos);
2449 for (const auto& rRef2 : *x2->GetRefList())
2450 {
2451 const ScAddress& r21 = rRef2.Ref1.toAbs(mrDoc, aPos);
2452 const ScAddress& r22 = rRef2.Ref2.toAbs(mrDoc, aPos);
2453 SCCOL nCol1 = ::std::max( r11.Col(), r21.Col());
2454 SCROW nRow1 = ::std::max( r11.Row(), r21.Row());
2455 SCTAB nTab1 = ::std::max( r11.Tab(), r21.Tab());
2456 SCCOL nCol2 = ::std::min( r12.Col(), r22.Col());
2457 SCROW nRow2 = ::std::min( r12.Row(), r22.Row());
2458 SCTAB nTab2 = ::std::min( r12.Tab(), r22.Tab());
2459 if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
2460 ; // nothing
2461 else
2462 {
2463 ScComplexRefData aRef;
2464 aRef.InitRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2465 pRefList->push_back( aRef);
2466 }
2467 }
2468 }
2469 size_t n = pRefList->size();
2470 if (!n)
2471 PushError( FormulaError::NoCode);
2472 else if (n == 1)
2473 {
2474 const ScComplexRefData& rRef = (*pRefList)[0];
2475 if (rRef.Ref1 == rRef.Ref2)
2477 else
2479 }
2480 else
2481 PushTokenRef( xRes);
2482 }
2483 else
2484 {
2485 const formula::FormulaToken* pt[2] = { x1, x2 };
2486 StackVar sv[2] = { sv1, sv2 };
2487 SCCOL nC1[2], nC2[2];
2488 SCROW nR1[2], nR2[2];
2489 SCTAB nT1[2], nT2[2];
2490 for (size_t i=0; i<2; ++i)
2491 {
2492 switch (sv[i])
2493 {
2494 case svSingleRef:
2495 case svDoubleRef:
2496 {
2497 {
2498 const ScAddress& r = pt[i]->GetSingleRef()->toAbs(mrDoc, aPos);
2499 nC1[i] = r.Col();
2500 nR1[i] = r.Row();
2501 nT1[i] = r.Tab();
2502 }
2503 if (sv[i] == svDoubleRef)
2504 {
2505 const ScAddress& r = pt[i]->GetSingleRef2()->toAbs(mrDoc, aPos);
2506 nC2[i] = r.Col();
2507 nR2[i] = r.Row();
2508 nT2[i] = r.Tab();
2509 }
2510 else
2511 {
2512 nC2[i] = nC1[i];
2513 nR2[i] = nR1[i];
2514 nT2[i] = nT1[i];
2515 }
2516 }
2517 break;
2518 default:
2519 ; // nothing, prevent compiler warning
2520 }
2521 }
2522 SCCOL nCol1 = ::std::max( nC1[0], nC1[1]);
2523 SCROW nRow1 = ::std::max( nR1[0], nR1[1]);
2524 SCTAB nTab1 = ::std::max( nT1[0], nT1[1]);
2525 SCCOL nCol2 = ::std::min( nC2[0], nC2[1]);
2526 SCROW nRow2 = ::std::min( nR2[0], nR2[1]);
2527 SCTAB nTab2 = ::std::min( nT2[0], nT2[1]);
2528 if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
2529 PushError( FormulaError::NoCode);
2530 else if (nCol2 == nCol1 && nRow2 == nRow1 && nTab2 == nTab1)
2531 PushSingleRef( nCol1, nRow1, nTab1);
2532 else
2533 PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2534 }
2535}
2536
2538{
2541
2542 if (nGlobalError != FormulaError::NONE || !x2 || !x1)
2543 {
2545 return;
2546 }
2547 // We explicitly tell extendRangeReference() to not reuse the token,
2548 // casting const away spares two clones.
2550 mrDoc.GetSheetLimits(), const_cast<FormulaToken&>(*x1), const_cast<FormulaToken&>(*x2), aPos, false);
2551 if (!xRes)
2553 else
2554 PushTokenRef( xRes);
2555}
2556
2558{
2561
2562 if (nGlobalError != FormulaError::NONE || !p2nd || !p1st)
2563 {
2565 return;
2566 }
2567
2568 StackVar sv1 = p1st->GetType();
2569 StackVar sv2 = p2nd->GetType();
2570 if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
2571 (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
2572 {
2574 return;
2575 }
2576
2577 const formula::FormulaToken* x1 = p1st.get();
2578 const formula::FormulaToken* x2 = p2nd.get();
2579
2580 ScTokenRef xRes;
2581 // Append to an existing RefList if there is one.
2582 if (sv1 == svRefList)
2583 {
2584 xRes = x1->Clone();
2585 sv1 = svUnknown; // mark as handled
2586 }
2587 else if (sv2 == svRefList)
2588 {
2589 xRes = x2->Clone();
2590 sv2 = svUnknown; // mark as handled
2591 }
2592 else
2593 xRes = new ScRefListToken;
2594 ScRefList* pRes = xRes->GetRefList();
2595 const formula::FormulaToken* pt[2] = { x1, x2 };
2596 StackVar sv[2] = { sv1, sv2 };
2597 for (size_t i=0; i<2; ++i)
2598 {
2599 if (pt[i] == xRes)
2600 continue;
2601 switch (sv[i])
2602 {
2603 case svSingleRef:
2604 {
2605 ScComplexRefData aRef;
2606 aRef.Ref1 = aRef.Ref2 = *pt[i]->GetSingleRef();
2607 pRes->push_back( aRef);
2608 }
2609 break;
2610 case svDoubleRef:
2611 pRes->push_back( *pt[i]->GetDoubleRef());
2612 break;
2613 case svRefList:
2614 {
2615 const ScRefList* p = pt[i]->GetRefList();
2616 for (const auto& rRef : *p)
2617 {
2618 pRes->push_back( rRef);
2619 }
2620 }
2621 break;
2622 default:
2623 ; // nothing, prevent compiler warning
2624 }
2625 }
2626 ValidateRef( *pRes); // set #REF! if needed
2627 PushTokenRef( xRes);
2628}
2629
2631{
2633 if (xTok)
2634 {
2635 PushTokenRef( xTok);
2636 PushTokenRef( xTok);
2637 }
2638 else
2639 PushError( FormulaError::UnknownStackVariable);
2640}
2641
2643{
2644 sal_uInt8 nParamCount = GetByte();
2645 if (!MustHaveParamCount(nParamCount, 1, 3))
2646 return;
2647
2648 OUString aStyle2; // Style after timer
2649 if (nParamCount >= 3)
2650 aStyle2 = GetString().getString();
2651 tools::Long nTimeOut = 0; // timeout
2652 if (nParamCount >= 2)
2653 nTimeOut = static_cast<tools::Long>(GetDouble()*1000.0);
2654 OUString aStyle1 = GetString().getString(); // Style for immediate
2655
2656 if (nTimeOut < 0)
2657 nTimeOut = 0;
2658
2659 // Execute request to apply style
2660 if ( !mrDoc.IsClipOrUndo() )
2661 {
2663 if (pShell)
2664 {
2665 // Normalize style names right here, making sure that character case is correct,
2666 // and that we only apply anything when there's something to apply
2667 auto pPool = mrDoc.GetStyleSheetPool();
2668 if (!aStyle1.isEmpty())
2669 {
2670 if (auto pNewStyle = pPool->FindAutoStyle(aStyle1))
2671 aStyle1 = pNewStyle->GetName();
2672 else
2673 aStyle1.clear();
2674 }
2675 if (!aStyle2.isEmpty())
2676 {
2677 if (auto pNewStyle = pPool->FindAutoStyle(aStyle2))
2678 aStyle2 = pNewStyle->GetName();
2679 else
2680 aStyle2.clear();
2681 }
2682 // notify object shell directly!
2683 if (!aStyle1.isEmpty() || !aStyle2.isEmpty())
2684 {
2685 const ScStyleSheet* pStyle = mrDoc.GetStyle(aPos.Col(), aPos.Row(), aPos.Tab());
2686
2687 const bool bNotify = !pStyle
2688 || (!aStyle1.isEmpty() && pStyle->GetName() != aStyle1)
2689 || (!aStyle2.isEmpty() && pStyle->GetName() != aStyle2);
2690 if (bNotify)
2691 {
2692 ScRange aRange(aPos);
2693 ScAutoStyleHint aHint(aRange, aStyle1, nTimeOut, aStyle2);
2694 pShell->Broadcast(aHint);
2695 }
2696 }
2697 }
2698 }
2699
2700 PushDouble(0.0);
2701}
2702
2704 std::u16string_view rA, std::u16string_view rT, std::u16string_view rI, sal_uInt8 nM )
2705{
2706 size_t nCount = pLinkMgr->GetLinks().size();
2707 for (size_t i=0; i<nCount; i++ )
2708 {
2709 ::sfx2::SvBaseLink* pBase = pLinkMgr->GetLinks()[i].get();
2710 if (ScDdeLink* pLink = dynamic_cast<ScDdeLink*>(pBase))
2711 {
2712 if ( pLink->GetAppl() == rA &&
2713 pLink->GetTopic() == rT &&
2714 pLink->GetItem() == rI &&
2715 pLink->GetMode() == nM )
2716 return pLink;
2717 }
2718 }
2719
2720 return nullptr;
2721}
2722
2724{
2725 // application, file, scope
2726 // application, Topic, Item
2727
2728 sal_uInt8 nParamCount = GetByte();
2729 if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
2730 return;
2731
2732 sal_uInt8 nMode = SC_DDE_DEFAULT;
2733 if (nParamCount == 4)
2734 {
2735 sal_uInt32 nTmp = GetUInt32();
2736 if (nGlobalError != FormulaError::NONE || nTmp > SAL_MAX_UINT8)
2737 {
2739 return;
2740 }
2741 nMode = static_cast<sal_uInt8>(nTmp);
2742 }
2743 OUString aItem = GetString().getString();
2744 OUString aTopic = GetString().getString();
2745 OUString aAppl = GetString().getString();
2746
2747 if (nMode > SC_DDE_TEXT)
2748 nMode = SC_DDE_DEFAULT;
2749
2750 // temporary documents (ScFunctionAccess) have no DocShell
2751 // and no LinkManager -> abort
2752
2753 //sfx2::LinkManager* pLinkMgr = mrDoc.GetLinkManager();
2754 if (!mpLinkManager)
2755 {
2756 PushNoValue();
2757 return;
2758 }
2759
2760 // Need to reinterpret after loading (build links)
2761 pArr->AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT );
2762
2763 // while the link is not evaluated, idle must be disabled (to avoid circular references)
2764
2765 bool bOldEnabled = mrDoc.IsIdleEnabled();
2766 mrDoc.EnableIdle(false);
2767
2768 // Get/ Create link object
2769
2770 ScDdeLink* pLink = lcl_GetDdeLink( mpLinkManager, aAppl, aTopic, aItem, nMode );
2771
2772 //TODO: Save Dde-links (in addition) more efficient at document !!!!!
2773 // ScDdeLink* pLink = mrDoc.GetDdeLink( aAppl, aTopic, aItem );
2774
2775 bool bWasError = ( pMyFormulaCell && pMyFormulaCell->GetRawError() != FormulaError::NONE );
2776
2777 if (!pLink)
2778 {
2779 pLink = new ScDdeLink( mrDoc, aAppl, aTopic, aItem, nMode );
2780 mpLinkManager->InsertDDELink( pLink, aAppl, aTopic, aItem );
2781 if ( mpLinkManager->GetLinks().size() == 1 ) // the first one?
2782 {
2783 SfxBindings* pBindings = mrDoc.GetViewBindings();
2784 if (pBindings)
2785 pBindings->Invalidate( SID_LINKS ); // Link-Manager enabled
2786 }
2787
2788 //if the document was just loaded, but the ScDdeLink entry was missing, then
2789 //don't update this link until the links are updated in response to the users
2790 //decision
2792 {
2793 //TODO: evaluate asynchron ???
2794 pLink->TryUpdate(); // TryUpdate doesn't call Update multiple times
2795 }
2796
2797 if (pMyFormulaCell)
2798 {
2799 // StartListening after the Update to avoid circular references
2801 }
2802 }
2803 else
2804 {
2805 if (pMyFormulaCell)
2807 }
2808
2809 // If a new Error from Reschedule appears when the link is executed then reset the errorflag
2810
2811
2812 if ( pMyFormulaCell && pMyFormulaCell->GetRawError() != FormulaError::NONE && !bWasError )
2813 pMyFormulaCell->SetErrCode(FormulaError::NONE);
2814
2815 // check the value
2816
2817 const ScMatrix* pLinkMat = pLink->GetResult();
2818 if (pLinkMat)
2819 {
2820 SCSIZE nC, nR;
2821 pLinkMat->GetDimensions(nC, nR);
2822 ScMatrixRef pNewMat = GetNewMat( nC, nR, /*bEmpty*/true);
2823 if (pNewMat)
2824 {
2825 pLinkMat->MatCopy(*pNewMat); // copy
2826 PushMatrix( pNewMat );
2827 }
2828 else
2830 }
2831 else
2832 PushNA();
2833
2834 mrDoc.EnableIdle(bOldEnabled);
2836}
2837
2839{ // Value, Base [, MinLen]
2840 sal_uInt8 nParamCount = GetByte();
2841 if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
2842 return;
2843
2844 static const sal_Unicode pDigits[] = {
2845 '0','1','2','3','4','5','6','7','8','9',
2846 'A','B','C','D','E','F','G','H','I','J','K','L','M',
2847 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
2848 0
2849 };
2850 static const int nDigits = SAL_N_ELEMENTS(pDigits) - 1;
2851 sal_Int32 nMinLen;
2852 if ( nParamCount == 3 )
2853 {
2854 double fLen = ::rtl::math::approxFloor( GetDouble() );
2855 if ( 1.0 <= fLen && fLen < SAL_MAX_UINT16 )
2856 nMinLen = static_cast<sal_Int32>(fLen);
2857 else
2858 nMinLen = fLen == 0.0 ? 1 : 0; // 0 means error
2859 }
2860 else
2861 nMinLen = 1;
2862 double fBase = ::rtl::math::approxFloor( GetDouble() );
2863 double fVal = ::rtl::math::approxFloor( GetDouble() );
2864 double fChars = ((fVal > 0.0 && fBase > 0.0) ?
2865 (ceil( log( fVal ) / log( fBase ) ) + 2.0) :
2866 2.0);
2867 if ( fChars >= SAL_MAX_UINT16 )
2868 nMinLen = 0; // Error
2869
2870 if ( nGlobalError == FormulaError::NONE && nMinLen && 2 <= fBase && fBase <= nDigits && 0 <= fVal )
2871 {
2872 const sal_Int32 nConstBuf = 128;
2873 sal_Unicode aBuf[nConstBuf];
2874 sal_Int32 nBuf = std::max<sal_Int32>( fChars, nMinLen + 1 );
2875 sal_Unicode* pBuf = (nBuf <= nConstBuf ? aBuf : new sal_Unicode[nBuf]);
2876 for ( sal_Int32 j = 0; j < nBuf; ++j )
2877 {
2878 pBuf[j] = '0';
2879 }
2880 sal_Unicode* p = pBuf + nBuf - 1;
2881 *p = 0;
2882 if ( o3tl::convertsToAtMost(fVal, sal_uLong(~0)) )
2883 {
2884 sal_uLong nVal = static_cast<sal_uLong>(fVal);
2885 sal_uLong nBase = static_cast<sal_uLong>(fBase);
2886 while ( nVal && p > pBuf )
2887 {
2888 *--p = pDigits[ nVal % nBase ];
2889 nVal /= nBase;
2890 }
2891 fVal = static_cast<double>(nVal);
2892 }
2893 else
2894 {
2895 bool bDirt = false;
2896 while ( fVal && p > pBuf )
2897 {
2898//TODO: roundoff error starting with numbers greater than 2**48
2899// double fDig = ::rtl::math::approxFloor( fmod( fVal, fBase ) );
2900// a little bit better:
2901 double fInt = ::rtl::math::approxFloor( fVal / fBase );
2902 double fMult = fInt * fBase;
2903#if 0
2904 // =BASIS(1e308;36) => GPF with
2905 // nDig = (size_t) ::rtl::math::approxFloor( fVal - fMult );
2906 // in spite off previous test if fVal >= fMult
2907 double fDebug1 = fVal - fMult;
2908 // fVal := 7,5975311883090e+290
2909 // fMult := 7,5975311883090e+290
2910 // fDebug1 := 1,3848924157003e+275 <- RoundOff-Error
2911 // fVal != fMult, aber: ::rtl::math::approxEqual( fVal, fMult ) == TRUE
2912 double fDebug2 = ::rtl::math::approxSub( fVal, fMult );
2913 // and ::rtl::math::approxSub( fVal, fMult ) == 0
2914 double fDebug3 = ( fInt ? fVal / fInt : 0.0 );
2915
2916 // Actual after strange fDebug1 and fVal < fMult is fDebug2 == fBase, but
2917 // anyway it can't be compared, then bDirt is executed an everything is good...
2918
2919 // prevent compiler warnings
2920 (void)fDebug1; (void)fDebug2; (void)fDebug3;
2921#endif
2922 size_t nDig;
2923 if ( fVal < fMult )
2924 { // something is wrong there
2925 bDirt = true;
2926 nDig = 0;
2927 }
2928 else
2929 {
2930 double fDig = ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal, fMult ) );
2931 if ( bDirt )
2932 {
2933 bDirt = false;
2934 --fDig;
2935 }
2936 if ( fDig <= 0.0 )
2937 nDig = 0;
2938 else if ( fDig >= fBase )
2939 nDig = static_cast<size_t>(fBase) - 1;
2940 else
2941 nDig = static_cast<size_t>(fDig);
2942 }
2943 *--p = pDigits[ nDig ];
2944 fVal = fInt;
2945 }
2946 }
2947 if ( fVal )
2948 PushError( FormulaError::StringOverflow );
2949 else
2950 {
2951 if ( nBuf - (p - pBuf) <= nMinLen )
2952 p = pBuf + nBuf - 1 - nMinLen;
2954 }
2955 if ( pBuf != aBuf )
2956 delete [] pBuf;
2957 }
2958 else
2960}
2961
2963{ // Text, Base
2964 if ( !MustHaveParamCount( GetByte(), 2 ) )
2965 return;
2966
2967 double fBase = ::rtl::math::approxFloor( GetDouble() );
2968 OUString aStr = GetString().getString();
2969 if ( nGlobalError == FormulaError::NONE && 2 <= fBase && fBase <= 36 )
2970 {
2971 double fVal = 0.0;
2972 int nBase = static_cast<int>(fBase);
2973 const sal_Unicode* p = aStr.getStr();
2974 while ( *p == ' ' || *p == '\t' )
2975 p++; // strip leading white space
2976 if ( nBase == 16 )
2977 { // evtl. hex-prefix stripped
2978 if ( *p == 'x' || *p == 'X' )
2979 p++;
2980 else if ( *p == '0' && (*(p+1) == 'x' || *(p+1) == 'X') )
2981 p += 2;
2982 }
2983 while ( *p )
2984 {
2985 int n;
2986 if ( '0' <= *p && *p <= '9' )
2987 n = *p - '0';
2988 else if ( 'A' <= *p && *p <= 'Z' )
2989 n = 10 + (*p - 'A');
2990 else if ( 'a' <= *p && *p <= 'z' )
2991 n = 10 + (*p - 'a');
2992 else
2993 n = nBase;
2994 if ( nBase <= n )
2995 {
2996 if ( *(p+1) == 0 &&
2997 ( (nBase == 2 && (*p == 'b' || *p == 'B'))
2998 ||(nBase == 16 && (*p == 'h' || *p == 'H')) )
2999 )
3000 ; // 101b and F00Dh are ok
3001 else
3002 {
3004 return ;
3005 }
3006 }
3007 else
3008 fVal = fVal * fBase + n;
3009 p++;
3010
3011 }
3012 PushDouble( fVal );
3013 }
3014 else
3016}
3017
3019{ // Value, FromUnit, ToUnit
3020 if ( !MustHaveParamCount( GetByte(), 3 ) )
3021 return;
3022
3023 OUString aToUnit = GetString().getString();
3024 OUString aFromUnit = GetString().getString();
3025 double fVal = GetDouble();
3026 if ( nGlobalError != FormulaError::NONE )
3028 else
3029 {
3030 // first of all search for the given order; if it can't be found then search for the inverse
3031 double fConv;
3032 if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aFromUnit, aToUnit ) )
3033 PushDouble( fVal * fConv );
3034 else if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aToUnit, aFromUnit ) )
3035 PushDouble( fVal / fConv );
3036 else
3037 PushNA();
3038 }
3039}
3040
3042{ // Value [Mode]
3043 sal_uInt8 nParamCount = GetByte();
3044 if( !MustHaveParamCount( nParamCount, 1, 2 ) )
3045 return;
3046
3047 double fMode = (nParamCount == 2) ? ::rtl::math::approxFloor( GetDouble() ) : 0.0;
3048 double fVal = ::rtl::math::approxFloor( GetDouble() );
3049 if( nGlobalError != FormulaError::NONE )
3051 else if( (fMode >= 0.0) && (fMode < 5.0) && (fVal >= 0.0) && (fVal < 4000.0) )
3052 {
3053 static const sal_Unicode pChars[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
3054 static const sal_uInt16 pValues[] = { 1000, 500, 100, 50, 10, 5, 1 };
3055 static const sal_uInt16 nMaxIndex = sal_uInt16(SAL_N_ELEMENTS(pValues) - 1);
3056
3057 OUStringBuffer aRoman;
3058 sal_uInt16 nVal = static_cast<sal_uInt16>(fVal);
3059 sal_uInt16 nMode = static_cast<sal_uInt16>(fMode);
3060
3061 for( sal_uInt16 i = 0; i <= nMaxIndex / 2; i++ )
3062 {
3063 sal_uInt16 nIndex = 2 * i;
3064 sal_uInt16 nDigit = nVal / pValues[ nIndex ];
3065
3066 if( (nDigit % 5) == 4 )
3067 {
3068 // assert can't happen with nVal<4000 precondition
3069 assert( ((nDigit == 4) ? (nIndex >= 1) : (nIndex >= 2)));
3070
3071 sal_uInt16 nIndex2 = (nDigit == 4) ? nIndex - 1 : nIndex - 2;
3072 sal_uInt16 nSteps = 0;
3073 while( (nSteps < nMode) && (nIndex < nMaxIndex) )
3074 {
3075 nSteps++;
3076 if( pValues[ nIndex2 ] - pValues[ nIndex + 1 ] <= nVal )
3077 nIndex++;
3078 else
3079 nSteps = nMode;
3080 }
3081 aRoman.append( OUStringChar(pChars[ nIndex ]) + OUStringChar(pChars[ nIndex2 ]) );
3082 nVal = sal::static_int_cast<sal_uInt16>( nVal + pValues[ nIndex ] );
3083 nVal = sal::static_int_cast<sal_uInt16>( nVal - pValues[ nIndex2 ] );
3084 }
3085 else
3086 {
3087 if( nDigit > 4 )
3088 {
3089 // assert can't happen with nVal<4000 precondition
3090 assert( nIndex >= 1 );
3091 aRoman.append( pChars[ nIndex - 1 ] );
3092 }
3093 sal_Int32 nPad = nDigit % 5;
3094 if (nPad)
3095 {
3096 comphelper::string::padToLength(aRoman, aRoman.getLength() + nPad,
3097 pChars[nIndex]);
3098 }
3099 nVal %= pValues[ nIndex ];
3100 }
3101 }
3102
3103 PushString( aRoman.makeStringAndClear() );
3104 }
3105 else
3107}
3108
3109static bool lcl_GetArabicValue( sal_Unicode cChar, sal_uInt16& rnValue, bool& rbIsDec )
3110{
3111 switch( cChar )
3112 {
3113 case 'M': rnValue = 1000; rbIsDec = true; break;
3114 case 'D': rnValue = 500; rbIsDec = false; break;
3115 case 'C': rnValue = 100; rbIsDec = true; break;
3116 case 'L': rnValue = 50; rbIsDec = false; break;
3117 case 'X': rnValue = 10; rbIsDec = true; break;
3118 case 'V': rnValue = 5; rbIsDec = false; break;
3119 case 'I': rnValue = 1; rbIsDec = true; break;
3120 default: return false;
3121 }
3122 return true;
3123}
3124
3126{
3127 OUString aRoman = GetString().getString();
3128 if( nGlobalError != FormulaError::NONE )
3130 else
3131 {
3132 aRoman = aRoman.toAsciiUpperCase();
3133
3134 sal_uInt16 nValue = 0;
3135 sal_uInt16 nValidRest = 3999;
3136 sal_Int32 nCharIndex = 0;
3137 sal_Int32 nCharCount = aRoman.getLength();
3138 bool bValid = true;
3139
3140 while( bValid && (nCharIndex < nCharCount) )
3141 {
3142 sal_uInt16 nDigit1 = 0;
3143 sal_uInt16 nDigit2 = 0;
3144 bool bIsDec1 = false;
3145 bValid = lcl_GetArabicValue( aRoman[nCharIndex], nDigit1, bIsDec1 );
3146 if( bValid && (nCharIndex + 1 < nCharCount) )
3147 {
3148 bool bIsDec2 = false;
3149 bValid = lcl_GetArabicValue( aRoman[nCharIndex + 1], nDigit2, bIsDec2 );
3150 }
3151 if( bValid )
3152 {
3153 if( nDigit1 >= nDigit2 )
3154 {
3155 nValue = sal::static_int_cast<sal_uInt16>( nValue + nDigit1 );
3156 nValidRest %= (nDigit1 * (bIsDec1 ? 5 : 2));
3157 bValid = (nValidRest >= nDigit1);
3158 if( bValid )
3159 nValidRest = sal::static_int_cast<sal_uInt16>( nValidRest - nDigit1 );
3160 nCharIndex++;
3161 }
3162 else if( nDigit1 * 2 != nDigit2 )
3163 {
3164 sal_uInt16 nDiff = nDigit2 - nDigit1;
3165 nValue = sal::static_int_cast<sal_uInt16>( nValue + nDiff );
3166 bValid = (nValidRest >= nDiff);
3167 if( bValid )
3168 nValidRest = nDigit1 - 1;
3169 nCharIndex += 2;
3170 }
3171 else
3172 bValid = false;
3173 }
3174 }
3175 if( bValid )
3176 PushInt( nValue );
3177 else
3179 }
3180}
3181
3183{
3184 sal_uInt8 nParamCount = GetByte();
3185 if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
3186 return;
3187
3188 double fVal = 0.0;
3190 ScMatValType nResultType = ScMatValType::String;
3191
3192 if ( nParamCount == 2 )
3193 {
3194 switch ( GetStackType() )
3195 {
3196 case svDouble:
3197 fVal = GetDouble();
3198 nResultType = ScMatValType::Value;
3199 break;
3200 case svString:
3201 aStr = GetString();
3202 break;
3203 case svSingleRef:
3204 case svDoubleRef:
3205 {
3206 ScAddress aAdr;
3207 if ( !PopDoubleRefOrSingleRef( aAdr ) )
3208 break;
3209
3210 ScRefCellValue aCell(mrDoc, aAdr);
3211 if (aCell.hasEmptyValue())
3212 nResultType = ScMatValType::Empty;
3213 else
3214 {
3215 FormulaError nErr = GetCellErrCode(aCell);
3216 if (nErr != FormulaError::NONE)
3217 SetError( nErr);
3218 else if (aCell.hasNumeric())
3219 {
3220 fVal = GetCellValue(aAdr, aCell);
3221 nResultType = ScMatValType::Value;
3222 }
3223 else
3224 GetCellString(aStr, aCell);
3225 }
3226 }
3227 break;
3228 case svMatrix:
3229 nResultType = GetDoubleOrStringFromMatrix( fVal, aStr);
3230 break;
3231 case svMissing:
3232 case svEmptyCell:
3233 Pop();
3234 // mimic xcl
3235 fVal = 0.0;
3236 nResultType = ScMatValType::Value;
3237 break;
3238 default:
3239 PopError();
3240 SetError( FormulaError::IllegalArgument);
3241 }
3242 }
3244 ScMatrixRef pResMat = GetNewMat( 1, 2);
3245 if (nGlobalError != FormulaError::NONE)
3246 {
3248 nResultType = ScMatValType::Value;
3249 }
3250 if (nParamCount == 2 || nGlobalError != FormulaError::NONE)
3251 {
3252 if (ScMatrix::IsValueType( nResultType))
3253 pResMat->PutDouble( fVal, 0);
3254 else if (ScMatrix::IsRealStringType( nResultType))
3255 pResMat->PutString(aStr, 0);
3256 else // EmptyType, EmptyPathType, mimic xcl
3257 pResMat->PutDouble( 0.0, 0 );
3258 }
3259 else
3260 pResMat->PutString(aUrl, 0);
3261 pResMat->PutString(aUrl, 1);
3262 bMatrixFormula = true;
3263 PushMatrix(pResMat);
3264}
3265
3270static bool lclConvertMoney( std::u16string_view aSearchUnit, double& rfRate, int& rnDec )
3271{
3272 struct ConvertInfo
3273 {
3274 const char* pCurrText;
3275 double fRate;
3276 int nDec;
3277 };
3278 static const ConvertInfo aConvertTable[] = {
3279 { "EUR", 1.0, 2 },
3280 { "ATS", 13.7603, 2 },
3281 { "BEF", 40.3399, 0 },
3282 { "DEM", 1.95583, 2 },
3283 { "ESP", 166.386, 0 },
3284 { "FIM", 5.94573, 2 },
3285 { "FRF", 6.55957, 2 },
3286 { "IEP", 0.787564, 2 },
3287 { "ITL", 1936.27, 0 },
3288 { "LUF", 40.3399, 0 },
3289 { "NLG", 2.20371, 2 },
3290 { "PTE", 200.482, 2 },
3291 { "GRD", 340.750, 2 },
3292 { "SIT", 239.640, 2 },
3293 { "MTL", 0.429300, 2 },
3294 { "CYP", 0.585274, 2 },
3295 { "SKK", 30.1260, 2 },
3296 { "EEK", 15.6466, 2 },
3297 { "LVL", 0.702804, 2 },
3298 { "LTL", 3.45280, 2 },
3299 { "HRK", 7.53450, 2 }
3300 };
3301
3302 for (const auto & i : aConvertTable)
3303 if ( o3tl::equalsIgnoreAsciiCase( aSearchUnit, i.pCurrText ) )
3304 {
3305 rfRate = i.fRate;
3306 rnDec = i.nDec;
3307 return true;
3308 }
3309 return false;
3310}
3311
3313{ //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]]
3314 sal_uInt8 nParamCount = GetByte();
3315 if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
3316 return;
3317
3318 double fPrecision = 0.0;
3319 if ( nParamCount == 5 )
3320 {
3321 fPrecision = ::rtl::math::approxFloor(GetDouble());
3322 if ( fPrecision < 3 )
3323 {
3325 return;
3326 }
3327 }
3328
3329 bool bFullPrecision = nParamCount >= 4 && GetBool();
3330 OUString aToUnit = GetString().getString();
3331 OUString aFromUnit = GetString().getString();
3332 double fVal = GetDouble();
3333 if ( nGlobalError != FormulaError::NONE )
3335 else
3336 {
3337 double fFromRate;
3338 double fToRate;
3339 int nFromDec;
3340 int nToDec;
3341 if ( lclConvertMoney( aFromUnit, fFromRate, nFromDec )
3342 && lclConvertMoney( aToUnit, fToRate, nToDec ) )
3343 {
3344 double fRes;
3345 if ( aFromUnit.equalsIgnoreAsciiCase( aToUnit ) )
3346 fRes = fVal;
3347 else
3348 {
3349 if ( aFromUnit.equalsIgnoreAsciiCase( "EUR" ) )
3350 fRes = fVal * fToRate;
3351 else
3352 {
3353 double fIntermediate = fVal / fFromRate;
3354 if ( fPrecision )
3355 fIntermediate = ::rtl::math::round( fIntermediate,
3356 static_cast<int>(fPrecision) );
3357 fRes = fIntermediate * fToRate;
3358 }
3359 if ( !bFullPrecision )
3360 fRes = ::rtl::math::round( fRes, nToDec );
3361 }
3362 PushDouble( fRes );
3363 }
3364 else
3366 }
3367}
3368
3369// BAHTTEXT
3370#define UTF8_TH_0 "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214"
3371#define UTF8_TH_1 "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207"
3372#define UTF8_TH_2 "\340\270\252\340\270\255\340\270\207"
3373#define UTF8_TH_3 "\340\270\252\340\270\262\340\270\241"
3374#define UTF8_TH_4 "\340\270\252\340\270\265\340\271\210"
3375#define UTF8_TH_5 "\340\270\253\340\271\211\340\270\262"
3376#define UTF8_TH_6 "\340\270\253\340\270\201"
3377#define UTF8_TH_7 "\340\271\200\340\270\210\340\271\207\340\270\224"
3378#define UTF8_TH_8 "\340\271\201\340\270\233\340\270\224"
3379#define UTF8_TH_9 "\340\271\200\340\270\201\340\271\211\340\270\262"
3380#define UTF8_TH_10 "\340\270\252\340\270\264\340\270\232"
3381#define UTF8_TH_11 "\340\271\200\340\270\255\340\271\207\340\270\224"
3382#define UTF8_TH_20 "\340\270\242\340\270\265\340\271\210"
3383#define UTF8_TH_1E2 "\340\270\243\340\271\211\340\270\255\340\270\242"
3384#define UTF8_TH_1E3 "\340\270\236\340\270\261\340\270\231"
3385#define UTF8_TH_1E4 "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231"
3386#define UTF8_TH_1E5 "\340\271\201\340\270\252\340\270\231"
3387#define UTF8_TH_1E6 "\340\270\245\340\271\211\340\270\262\340\270\231"
3388#define UTF8_TH_DOT0 "\340\270\226\340\271\211\340\270\247\340\270\231"
3389#define UTF8_TH_BAHT "\340\270\232\340\270\262\340\270\227"
3390#define UTF8_TH_SATANG "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214"
3391#define UTF8_TH_MINUS "\340\270\245\340\270\232"
3392
3393// local functions
3394namespace {
3395
3396void lclSplitBlock( double& rfInt, sal_Int32& rnBlock, double fValue, double fSize )
3397{
3398 rnBlock = static_cast< sal_Int32 >( modf( (fValue + 0.1) / fSize, &rfInt ) * fSize + 0.1 );
3399}
3400
3402void lclAppendDigit( OStringBuffer& rText, sal_Int32 nDigit )
3403{
3404 switch( nDigit )
3405 {
3406 case 0: rText.append( UTF8_TH_0 ); break;
3407 case 1: rText.append( UTF8_TH_1 ); break;
3408 case 2: rText.append( UTF8_TH_2 ); break;
3409 case 3: rText.append( UTF8_TH_3 ); break;
3410 case 4: rText.append( UTF8_TH_4 ); break;
3411 case 5: rText.append( UTF8_TH_5 ); break;
3412 case 6: rText.append( UTF8_TH_6 ); break;
3413 case 7: rText.append( UTF8_TH_7 ); break;
3414 case 8: rText.append( UTF8_TH_8 ); break;
3415 case 9: rText.append( UTF8_TH_9 ); break;
3416 default: OSL_FAIL( "lclAppendDigit - illegal digit" );
3417 }
3418}
3419
3424void lclAppendPow10( OStringBuffer& rText, sal_Int32 nDigit, sal_Int32 nPow10 )
3425{
3426 OSL_ENSURE( (1 <= nDigit) && (nDigit <= 9), "lclAppendPow10 - illegal digit" );
3427 lclAppendDigit( rText, nDigit );
3428 switch( nPow10 )
3429 {
3430 case 2: rText.append( UTF8_TH_1E2 ); break;
3431 case 3: rText.append( UTF8_TH_1E3 ); break;
3432 case 4: rText.append( UTF8_TH_1E4 ); break;
3433 case 5: rText.append( UTF8_TH_1E5 ); break;
3434 default: OSL_FAIL( "lclAppendPow10 - illegal power" );
3435 }
3436}
3437
3439void lclAppendBlock( OStringBuffer& rText, sal_Int32 nValue )
3440{
3441 OSL_ENSURE( (1 <= nValue) && (nValue <= 999999), "lclAppendBlock - illegal value" );
3442 if( nValue >= 100000 )
3443 {
3444 lclAppendPow10( rText, nValue / 100000, 5 );
3445 nValue %= 100000;
3446 }
3447 if( nValue >= 10000 )
3448 {
3449 lclAppendPow10( rText, nValue / 10000, 4 );
3450 nValue %= 10000;
3451 }
3452 if( nValue >= 1000 )
3453 {
3454 lclAppendPow10( rText, nValue / 1000, 3 );
3455 nValue %= 1000;
3456 }
3457 if( nValue >= 100 )
3458 {
3459 lclAppendPow10( rText, nValue / 100, 2 );
3460 nValue %= 100;
3461 }
3462 if( nValue <= 0 )
3463 return;
3464
3465 sal_Int32 nTen = nValue / 10;
3466 sal_Int32 nOne = nValue % 10;
3467 if( nTen >= 1 )
3468 {
3469 if( nTen >= 3 )
3470 lclAppendDigit( rText, nTen );
3471 else if( nTen == 2 )
3472 rText.append( UTF8_TH_20 );
3473 rText.append( UTF8_TH_10 );
3474 }
3475 if( (nTen > 0) && (nOne == 1) )
3476 rText.append( UTF8_TH_11 );
3477 else if( nOne > 0 )
3478 lclAppendDigit( rText, nOne );
3479}
3480
3481} // namespace
3482
3484{
3485 sal_uInt8 nParamCount = GetByte();
3486 if ( !MustHaveParamCount( nParamCount, 1 ) )
3487 return;
3488
3489 double fValue = GetDouble();
3490 if( nGlobalError != FormulaError::NONE )
3491 {
3493 return;
3494 }
3495
3496 // sign
3497 bool bMinus = fValue < 0.0;
3498 fValue = std::abs( fValue );
3499
3500 // round to 2 digits after decimal point, fValue contains Satang as integer
3501 fValue = ::rtl::math::approxFloor( fValue * 100.0 + 0.5 );
3502
3503 // split Baht and Satang
3504 double fBaht = 0.0;
3505 sal_Int32 nSatang = 0;
3506 lclSplitBlock( fBaht, nSatang, fValue, 100.0 );
3507
3508 OStringBuffer aText;
3509
3510 // generate text for Baht value
3511 if( fBaht == 0.0 )
3512 {
3513 if( nSatang == 0 )
3514 aText.append( UTF8_TH_0 );
3515 }
3516 else while( fBaht > 0.0 )
3517 {
3518 OStringBuffer aBlock;
3519 sal_Int32 nBlock = 0;
3520 lclSplitBlock( fBaht, nBlock, fBaht, 1.0e6 );
3521 if( nBlock > 0 )
3522 lclAppendBlock( aBlock, nBlock );
3523 // add leading "million", if there will come more blocks
3524 if( fBaht > 0.0 )
3525 aBlock.insert( 0, UTF8_TH_1E6 );
3526
3527 aText.insert(0, aBlock);
3528 }
3529 if (!aText.isEmpty())
3530 aText.append( UTF8_TH_BAHT );
3531
3532 // generate text for Satang value
3533 if( nSatang == 0 )
3534 {
3535 aText.append( UTF8_TH_DOT0 );
3536 }
3537 else
3538 {
3539 lclAppendBlock( aText, nSatang );
3540 aText.append( UTF8_TH_SATANG );
3541 }
3542
3543 // add the minus sign
3544 if( bMinus )
3545 aText.insert( 0, UTF8_TH_MINUS );
3546
3547 PushString( OStringToOUString(aText, RTL_TEXTENCODING_UTF8) );
3548}
3549
3551{
3552 sal_uInt8 nParamCount = GetByte();
3553
3554 if (!MustHaveParamCountMin(nParamCount, 2) || (nParamCount % 2) == 1)
3555 {
3556 PushError(FormulaError::NoRef);
3557 return;
3558 }
3559
3560 bool bOldSyntax = false;
3561 if (nParamCount == 2)
3562 {
3563 // if the first parameter is a ref, assume old syntax
3564 StackVar eFirstType = GetStackType(2);
3565 if (eFirstType == svSingleRef || eFirstType == svDoubleRef)
3566 bOldSyntax = true;
3567 }
3568
3569 std::vector<sheet::DataPilotFieldFilter> aFilters;
3570 OUString aDataFieldName;
3571 ScRange aBlock;
3572
3573 if (bOldSyntax)
3574 {
3575 aDataFieldName = GetString().getString();
3576
3577 switch (GetStackType())
3578 {
3579 case svDoubleRef :
3580 PopDoubleRef(aBlock);
3581 break;
3582 case svSingleRef :
3583 {
3584 ScAddress aAddr;
3585 PopSingleRef(aAddr);
3586 aBlock = aAddr;
3587 }
3588 break;
3589 default:
3590 PushError(FormulaError::NoRef);
3591 return;
3592 }
3593 }
3594 else
3595 {
3596 // Standard syntax: separate name/value pairs
3597
3598 sal_uInt16 nFilterCount = nParamCount / 2 - 1;
3599 aFilters.resize(nFilterCount);
3600
3601 sal_uInt16 i = nFilterCount;
3602 while (i-- > 0)
3603 {
3604 /* TODO: also, in case of numeric the entire filter match should
3605 * not be on a (even if locale independent) formatted string down
3606 * below in pDPObj->GetPivotData(). */
3607
3608 bool bEvaluateFormatIndex;
3609 switch (GetRawStackType())
3610 {
3611 case svSingleRef:
3612 case svDoubleRef:
3613 bEvaluateFormatIndex = true;
3614 break;
3615 default:
3616 bEvaluateFormatIndex = false;
3617 }
3618
3619 double fDouble;
3620 svl::SharedString aSharedString;
3621 bool bDouble = GetDoubleOrString( fDouble, aSharedString);
3622 if (nGlobalError != FormulaError::NONE)
3623 {
3625 return;
3626 }
3627
3628 if (bDouble)
3629 {
3630 sal_uInt32 nNumFormat;
3631 if (bEvaluateFormatIndex && nCurFmtIndex)
3632 nNumFormat = nCurFmtIndex;
3633 else
3634 {
3635 if (nCurFmtType == SvNumFormatType::UNDEFINED)
3636 nNumFormat = 0;
3637 else
3639 }
3640 const Color* pColor;
3641 pFormatter->GetOutputString( fDouble, nNumFormat, aFilters[i].MatchValueName, &pColor);
3643 fDouble, *pFormatter, nNumFormat);
3644 }
3645 else
3646 {
3647 aFilters[i].MatchValueName = aSharedString.getString();
3648
3649 // Parse possible number from MatchValueName and format
3650 // locale independent as MatchValue.
3651 sal_uInt32 nNumFormat = 0;
3652 double fValue;
3653 if (pFormatter->IsNumberFormat( aFilters[i].MatchValueName, nNumFormat, fValue))
3655 fValue, *pFormatter, nNumFormat);
3656 else
3657 aFilters[i].MatchValue = aFilters[i].MatchValueName;
3658 }
3659
3660 aFilters[i].FieldName = GetString().getString();
3661 }
3662
3663 switch (GetStackType())
3664 {
3665 case svDoubleRef :
3666 PopDoubleRef(aBlock);
3667 break;
3668 case svSingleRef :
3669 {
3670 ScAddress aAddr;
3671 PopSingleRef(aAddr);
3672 aBlock = aAddr;
3673 }
3674 break;
3675 default:
3676 PushError(FormulaError::NoRef);
3677 return;
3678 }
3679
3680 aDataFieldName = GetString().getString(); // First parameter is data field name.
3681 }
3682
3683 // Early bail-out, don't grind through data pilot cache and all.
3684 if (nGlobalError != FormulaError::NONE)
3685 {
3687 return;
3688 }
3689
3690 // NOTE : MS Excel docs claim to use the 'most recent' which is not
3691 // exactly the same as what we do in ScDocument::GetDPAtBlock
3692 // However we do need to use GetDPABlock
3693 ScDPObject* pDPObj = mrDoc.GetDPAtBlock(aBlock);
3694 if (!pDPObj)
3695 {
3696 PushError(FormulaError::NoRef);
3697 return;
3698 }
3699
3700 if (bOldSyntax)
3701 {
3702 OUString aFilterStr = aDataFieldName;
3703 std::vector<sal_Int16> aFilterFuncs;
3704 if (!pDPObj->ParseFilters(aDataFieldName, aFilters, aFilterFuncs, aFilterStr))
3705 {
3706 PushError(FormulaError::NoRef);
3707 return;
3708 }
3709
3710 // TODO : For now, we ignore filter functions since we couldn't find a
3711 // live example of how they are supposed to be used. We'll support
3712 // this again once we come across a real-world example.
3713 }
3714
3715 double fVal = pDPObj->GetPivotData(aDataFieldName, aFilters);
3716 if (std::isnan(fVal))
3717 {
3718 PushError(FormulaError::NoRef);
3719 return;
3720 }
3721 PushDouble(fVal);
3722}
3723
3724/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const PropertyValue * pValues
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
sal_uInt16 GetWeekOfYear(DayOfWeek eStartDay=MONDAY, sal_Int16 nMinimumNumberOfDaysInWeek=4) const
void AddDays(sal_Int32 nAddDays)
bool IsValidAndGregorian() const
sal_Int16 GetYear() const
sal_uInt16 GetDay() const
bool IsLeapYear() const
void SetMonth(sal_uInt16 nNewMonth)
void SetYear(sal_Int16 nNewYear)
void Normalize()
static sal_Int32 DateToDays(sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear)
DayOfWeek GetDayOfWeek() const
void SetDay(sal_uInt16 nNewDay)
sal_uInt16 GetMonth() const
This class provides LO with Kahan summation algorithm About this algorithm: https://en....
Definition: kahan.hxx:26
double get() const
Returns the final sum.
Definition: kahan.hxx:211
SCTAB Tab() const
Definition: address.hxx:283
SCROW Row() const
Definition: address.hxx:274
SCCOL Col() const
Definition: address.hxx:279
move ScAutoStyleHint to a different file?
Definition: hints.hxx:100
static OUString GetLocaleIndependentFormattedString(double fValue, SvNumberFormatter &rFormatter, sal_uInt32 nNumFormat)
Definition: dpcache.cxx:1192
bool ParseFilters(OUString &rDataFieldName, std::vector< css::sheet::DataPilotFieldFilter > &rFilters, std::vector< sal_Int16 > &rFilterFuncs, std::u16string_view rFilterList)
Definition: dpobject.cxx:1726
double GetPivotData(const OUString &rDataFieldName, std::vector< css::sheet::DataPilotFieldFilter > &rFilters)
Definition: dpobject.cxx:1370
ScSheetLimits & GetSheetLimits() const
Definition: document.hxx:898
bool IsIdleEnabled() const
Definition: document.hxx:2207
ScDPObject * GetDPAtBlock(const ScRange &rBlock) const
Definition: documen3.cxx:391
const ScStyleSheet * GetStyle(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:4868
SfxBindings * GetViewBindings()
Definition: documen8.cxx:1183
bool HasLinkFormulaNeedingCheck() const
Definition: document.hxx:2213
bool IsClipOrUndo() const
Definition: document.hxx:1592
void EnableIdle(bool bDo)
Definition: document.hxx:2208
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1083
SC_DLLPUBLIC ScStyleSheetPool * GetStyleSheetPool() const
Definition: document.cxx:6055
void SetErrCode(FormulaError n)
FormulaError GetRawError() const
static SC_DLLPUBLIC LanguageType eLnge
Definition: global.hxx:560
static ScUnitConverter * GetUnitConverter()
Definition: global.cxx:685
Row-wise value iterator.
Definition: dociter.hxx:334
bool GetNext(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:1297
formula::FormulaConstTokenRef PopToken()
Definition: interpr4.cxx:766
sal_uInt32 nCurFmtIndex
Definition: interpre.hxx:202
void SetError(FormulaError nError)
Definition: interpre.hxx:1008
bool bMatrixFormula
Definition: interpre.hxx:211
double GetDateSerial(sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, bool bStrict)
Obtain the date serial number for a given date.
Definition: interpr2.cxx:61
svl::SharedString GetString()
Definition: interpr4.cxx:2334
static double ScGetPV(double fRate, double fNper, double fPmt, double fFv, bool bPayInAdvance)
Definition: interpr2.cxx:1661
void ScGetDiffDate()
Definition: interpr2.cxx:662
void ScRoman()
Definition: interpr2.cxx:3041
void ScGetIsoWeekOfYear()
Definition: interpr2.cxx:294
static bool RateIteration(double fNper, double fPayment, double fPv, double fFv, bool bPayType, double &fGuess)
Definition: interpr2.cxx:2037
void ScFloor_Precise()
Definition: interpr2.cxx:1237
void ScGetPivotData()
Definition: interpr2.cxx:3550
void ScISPMT()
Definition: interpr2.cxx:1644
FormulaError GetWeekendAndHolidayMasks(const sal_uInt8 nParamCount, const sal_uInt32 nNullDate, ::std::vector< double > &rSortArray, bool bWeekendMask[7])
Definition: interpr2.cxx:344
void ScGetDateDif()
Definition: interpr2.cxx:763
void ScPlusMinus()
Definition: interpr2.cxx:934
bool MustHaveParamCount(short nAct, short nMust)
Definition: interpre.hxx:1048
void ScGetHour()
Definition: interpr2.cxx:161
bool MustHaveParamCountMin(short nAct, short nMin)
Definition: interpre.hxx:1070
ScAddress aPos
Definition: interpre.hxx:183
ScDocument & mrDoc
Definition: interpre.hxx:186
static FormulaError GetCellErrCode(const ScRefCellValue &rCell)
Definition: interpr4.cxx:158
SubtotalFlags mnSubTotalFlags
Definition: interpre.hxx:208
bool GetBool()
Definition: interpre.hxx:434
void PushIllegalParameter()
Definition: interpr4.cxx:1938
bool GetDoubleOrString(double &rValue, svl::SharedString &rString)
returns TRUE if double (or error, check nGlobalError), else FALSE
Definition: interpr4.cxx:2274
FormulaError nGlobalError
Definition: interpre.hxx:198
void PushIllegalArgument()
Definition: interpr4.cxx:1943
sal_Int16 GetInt16()
if GetDouble() not within int16 limits sets nGlobalError and returns SAL_MAX_INT16
Definition: interpr4.cxx:2229
void ScInt()
Definition: interpr2.cxx:950
void ScRoundDown()
Definition: interpr2.cxx:1028
void ScCeil_Precise()
Definition: interpr2.cxx:1146
void PushDoubleRef(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2)
Definition: interpr4.cxx:1846
static void RoundSignificant(double fX, double fDigits, double &fRes)
Definition: interpr2.cxx:1038
void ScGetDiffDate360()
Definition: interpr2.cxx:672
void ScGetActDate()
Definition: interpr2.cxx:101
formula::StackVar GetRawStackType()
Raw stack type without default replacements.
Definition: interpr4.cxx:1963
ScInterpreterContext & mrContext
Definition: interpre.hxx:185
double ScGetIpmt(double fRate, double fPer, double fNper, double fPv, double fFv, bool bPayInAdvance, double &fPmt)
Definition: interpr2.cxx:2192
void ScRound()
Definition: interpr2.cxx:1023
void ScGetDate()
Definition: interpr2.cxx:629
SvNumFormatType nFuncFmtType
Definition: interpre.hxx:204
void ScLog10()
Definition: interpr2.cxx:1311
sal_uInt32 GetUInt32()
if GetDouble() not within uint32 limits sets nGlobalError and returns SAL_MAX_UINT32
Definition: interpr4.cxx:2258
void ScEasterSunday()
Definition: interpr2.cxx:304
void ScGetWeekOfYear()
Definition: interpr2.cxx:248
void GetCellString(svl::SharedString &rStr, ScRefCellValue &rCell)
Definition: interpr4.cxx:245
void ScCumPrinc()
Definition: interpr2.cxx:2294
bool PopDoubleRefOrSingleRef(ScAddress &rAdr)
Definition: interpr4.cxx:1342
void ValidateRef(const ScSingleRefData &rRef)
Definition: interpr4.cxx:841
void PushError(FormulaError nError)
Definition: interpr4.cxx:1927
sal_uInt8 GetByte() const
Definition: interpre.hxx:416
void ScGetActTime()
Definition: interpr2.cxx:109
FormulaError GetWeekendAndHolidayMasks_MS(const sal_uInt8 nParamCount, const sal_uInt32 nNullDate, ::std::vector< double > &rSortArray, bool bWeekendMask[7], bool bWorkdayFunction)
Definition: interpr2.cxx:384
void ScUnionFunc()
Definition: interpr2.cxx:2557
void ScEffect()
Definition: interpr2.cxx:2333
void ScWeeknumOOo()
Definition: interpr2.cxx:236
ScMatrixRef GetNewMat(SCSIZE nC, SCSIZE nR, bool bEmpty=false)
Definition: interpr5.cxx:284
static double ScGetPMT(double fRate, double fNper, double fPv, double fFv, bool bPayInAdvance)
Definition: interpr2.cxx:1936
ScMatValType GetDoubleOrStringFromMatrix(double &rDouble, svl::SharedString &rString)
Definition: interpr4.cxx:2435
double GetDouble()
Definition: interpr4.cxx:2097
void ScGetTimeValue()
Definition: interpr2.cxx:912
void ScGetMin()
Definition: interpr2.cxx:142
static double ScGetDDB(double fCost, double fSalvage, double fLife, double fPeriod, double fFactor)
Definition: interpr2.cxx:1710
void ScGetDayOfWeek()
Definition: interpr2.cxx:189
void PushDouble(double nVal)
Definition: interpr4.cxx:1801
void ScGetDay()
Definition: interpr2.cxx:135
void ScNominal()
Definition: interpr2.cxx:2352
void ScHyperLink()
Definition: interpr2.cxx:3182
void PopSingleRef(ScAddress &)
Definition: interpr4.cxx:907
void ScStyle()
Definition: interpr2.cxx:2642
void ReverseStack(sal_uInt8 nParamCount)
Definition: interpr4.cxx:2009
ScTokenArray * pArr
Definition: interpre.hxx:184
SvNumberFormatter * pFormatter
Definition: interpre.hxx:193
void ScDecimal()
Definition: interpr2.cxx:2962
void ScRangeFunc()
Definition: interpr2.cxx:2537
static double div(const double &fNumerator, const double &fDenominator)
Fail safe division, returning a FormulaError::DivisionByZero coded into a double if denominator is 0....
Definition: interpre.hxx:1155
ScMatrixRef GetMatrix()
Definition: interpr5.cxx:464
static sal_Int16 GetDayOfWeek(sal_Int32 n)
Definition: interpre.hxx:1160
void ScGetDateValue()
Definition: interpr2.cxx:169
void ScGetYear()
Definition: interpr2.cxx:121
void ScGetTime()
Definition: interpr2.cxx:646
static double ScInterVDB(double fCost, double fSalvage, double fLife, double fLife1, double fPeriod, double fFactor)
Definition: interpr2.cxx:1788
sfx2::LinkManager * mpLinkManager
Definition: interpre.hxx:187
void ScGetSec()
Definition: interpr2.cxx:150
void ScWorkday_MS()
Definition: interpr2.cxx:557
void PopDoubleRef(ScRange &rRange, short &rParam, size_t &rRefInList)
If formula::StackVar formula::svDoubleRef pop ScDoubleRefToken and return values of ScComplexRefData.
Definition: interpr4.cxx:1044
void ScArabic()
Definition: interpr2.cxx:3125
void PushTokenRef(const formula::FormulaConstTokenRef &)
Pushes the token or substitutes with formula::FormulaErrorToken in case nGlobalError is set and the t...
Definition: interpr4.cxx:667
void PushMatrix(const sc::RangeMatrix &rMat)
Definition: interpr4.cxx:1902
void GetNumberSequenceArray(sal_uInt8 nParamCount, ::std::vector< double > &rArray, bool bConvertTextInArray)
Definition: interpr3.cxx:3960
static double ScGetFV(double fRate, double fNper, double fPmt, double fPv, bool bPayInAdvance)
Definition: interpr2.cxx:1983
void ScPDuration()
Definition: interpr2.cxx:1910
void ScCeil(bool bODFF)
tdf69552 ODFF1.2 function CEILING and Excel function CEILING.MATH In essence, the difference between ...
Definition: interpr2.cxx:1088
void ScGetMonth()
Definition: interpr2.cxx:128
void PopError()
Definition: interpr4.cxx:754
ScFormulaCell * pMyFormulaCell
Definition: interpre.hxx:192
void ScEuroConvert()
Definition: interpr2.cxx:3312
void ScCumIpmt()
Definition: interpr2.cxx:2253
double GetCellValue(const ScAddress &, ScRefCellValue &rCell)
Definition: interpr4.cxx:178
void PushTempToken(formula::FormulaToken *)
Does substitute with formula::FormulaErrorToken in case nGlobalError is set and the token passed is n...
Definition: interpr4.cxx:618
void ScConvertOOo()
Definition: interpr2.cxx:3018
void ScCeil_MS()
Definition: interpr2.cxx:1128
void PushSingleRef(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: interpr4.cxx:1836
void ScAbs()
Definition: interpr2.cxx:945
void ScNetWorkdays(bool bOOXML_Version)
Definition: interpr2.cxx:501
void PushNoValue()
Definition: interpr4.cxx:1953
void ScArcTan2()
Definition: interpr2.cxx:1278
void GetSortArray(sal_uInt8 nParamCount, ::std::vector< double > &rSortArray, ::std::vector< tools::Long > *pIndexOrder, bool bConvertTextInArray, bool bAllowEmptyArray)
Definition: interpr3.cxx:4143
double GetDoubleWithDefault(double nDefault)
Definition: interpr4.cxx:2178
void ScFloor(bool bODFF)
tdf69552 ODFF1.2 function FLOOR and Excel function FLOOR.MATH In essence, the difference between the ...
Definition: interpr2.cxx:1176
bool IsMissing() const
Definition: interpr4.cxx:1958
void ScRoundSignificant()
Definition: interpr2.cxx:1058
sal_Int32 GetInt32()
if GetDouble() not within int32 limits sets nGlobalError and returns SAL_MAX_INT32
Definition: interpr4.cxx:2215
formula::StackVar GetStackType()
Stack type with replacement of defaults, e.g. svMissing and formula::svEmptyCell will result in formu...
Definition: interpr4.cxx:1978
void ScFloor_MS()
Definition: interpr2.cxx:1216
void PushInt(int nVal)
Definition: interpr4.cxx:1808
SvNumFormatType nCurFmtType
Definition: interpre.hxx:205
void ScRoundUp()
Definition: interpr2.cxx:1033
void PushString(const OUString &rStr)
Definition: interpr4.cxx:1825
void RoundNumber(rtl_math_RoundingMode eMode)
Definition: interpr2.cxx:955
void PushStringBuffer(const sal_Unicode *pString)
Definition: interpr4.cxx:1814
void ScBahtText()
Definition: interpr2.cxx:3483
void ScIntersect()
Definition: interpr2.cxx:2390
void ScCurrent()
Definition: interpr2.cxx:2630
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:101
void MatCopy(const ScMatrix &mRes) const
Definition: scmatrix.cxx:3313
static bool IsValueType(ScMatValType nType)
Value or boolean.
Definition: scmatrix.hxx:167
static bool IsRealStringType(ScMatValType nType)
String, but not empty or empty path or any other type.
Definition: scmatrix.hxx:187
void GetDimensions(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:3143
virtual const ScRefList * GetRefList() const override
Definition: token.cxx:656
bool GetFirst(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:270
bool GetNext(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:294
void Invalidate(sal_uInt16 nId)
const OUString & GetName() const
sal_uInt32 GetStandardFormat(SvNumFormatType eType, LanguageType eLnge=LANGUAGE_DONTKNOW)
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, const Color **ppColor, bool bUseStarFormat=false)
const Date & GetNullDate() const
SvNumFormatType GetType(sal_uInt32 nFIndex) const
sal_uInt16 ExpandTwoDigitYear(sal_uInt16 nYear) const
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
bool StartListening(SvtBroadcaster &rBroadcaster)
void AddRecalcMode(ScRecalcMode nBits)
virtual const ScSingleRefData * GetSingleRef() const
virtual const std::vector< ScComplexRefData > * GetRefList() const
virtual FormulaToken * Clone() const
virtual const ScComplexRefData * GetDoubleRef() const
void InsertDDELink(SvBaseLink *, const OUString &rServer, std::u16string_view rTopic, std::u16string_view rItem)
const SvBaseLinks & GetLinks() const
const OUString & getString() const
bool isEmpty() const
sal_Int32 getLength() const
static const sal_Int64 nanoSecPerDay
sal_uInt16 GetSec() const
static void GetClock(double fTimeInDays, sal_uInt16 &nHour, sal_uInt16 &nMinute, sal_uInt16 &nSecond, double &fFractionOfSecond, int nFractionDecimals)
sal_uInt16 GetMin() const
static const sal_Int64 minutePerDay
static const sal_Int64 secondPerMinute
static const sal_Int64 hourPerDay
sal_uInt16 GetHour() const
sal_uInt32 GetNanoSec() const
static const sal_Int64 secondPerHour
static const sal_Int64 secondPerDay
int nCount
DayOfWeek
SATURDAY
TUESDAY
WEDNESDAY
FRIDAY
THURSDAY
MONDAY
SUNDAY
const sal_uInt8 SC_DDE_TEXT
Definition: document.hxx:303
const sal_uInt8 SC_DDE_DEFAULT
Definition: document.hxx:301
float x
FormulaError
double CreateDoubleError(FormulaError nErr)
DocumentType eType
sal_Int16 nValue
#define DATE_TIME_FACTOR
Definition: globalnames.hxx:21
#define UTF8_TH_1E4
Definition: interpr2.cxx:3385
#define UTF8_TH_1E3
Definition: interpr2.cxx:3384
static bool lclConvertMoney(std::u16string_view aSearchUnit, double &rfRate, int &rnDec)
Resources at the website of the European Commission: http://ec.europa.eu/economy_finance/euro/adoptio...
Definition: interpr2.cxx:3270
#define UTF8_TH_DOT0
Definition: interpr2.cxx:3388
#define UTF8_TH_1E6
Definition: interpr2.cxx:3387
#define UTF8_TH_10
Definition: interpr2.cxx:3380
#define UTF8_TH_2
Definition: interpr2.cxx:3372
#define UTF8_TH_SATANG
Definition: interpr2.cxx:3390
#define UTF8_TH_3
Definition: interpr2.cxx:3373
#define UTF8_TH_MINUS
Definition: interpr2.cxx:3391
static bool lcl_GetArabicValue(sal_Unicode cChar, sal_uInt16 &rnValue, bool &rbIsDec)
Definition: interpr2.cxx:3109
#define UTF8_TH_1E2
Definition: interpr2.cxx:3383
#define UTF8_TH_BAHT
Definition: interpr2.cxx:3389
#define UTF8_TH_11
Definition: interpr2.cxx:3381
#define UTF8_TH_5
Definition: interpr2.cxx:3375
#define UTF8_TH_8
Definition: interpr2.cxx:3378
#define UTF8_TH_6
Definition: interpr2.cxx:3376
#define UTF8_TH_1
Definition: interpr2.cxx:3371
#define UTF8_TH_0
Definition: interpr2.cxx:3370
#define UTF8_TH_7
Definition: interpr2.cxx:3377
#define UTF8_TH_9
Definition: interpr2.cxx:3379
static ScDdeLink * lcl_GetDdeLink(const sfx2::LinkManager *pLinkMgr, std::u16string_view rA, std::u16string_view rT, std::u16string_view rI, sal_uInt8 nM)
Definition: interpr2.cxx:2703
#define UTF8_TH_1E5
Definition: interpr2.cxx:3386
#define UTF8_TH_4
Definition: interpr2.cxx:3374
#define SCdEpsilon
Definition: interpr2.cxx:57
#define UTF8_TH_20
Definition: interpr2.cxx:3382
sal_Int32 nIndex
Mode eMode
void * p
sal_Int64 n
sal_Int32 nRef
SvBaseLink * pLink
#define SAL_N_ELEMENTS(arr)
aStr
aBuf
OStringBuffer & padToLength(OStringBuffer &rBuffer, sal_Int32 nLength, char cFill='\0')
::boost::intrusive_ptr< const FormulaToken > FormulaConstTokenRef
::boost::intrusive_ptr< FormulaToken > FormulaTokenRef
StackVar
svMissing
svExternalDoubleRef
svUnknown
svDouble
svDoubleRef
svExternalSingleRef
svString
svRefList
svMatrix
svEmptyCell
svSingleRef
int i
constexpr sal_Int64 md(U i, U)
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
constexpr std::enable_if_t< std::is_floating_point_v< F > &&std::is_integral_v< I >, bool > convertsToAtMost(F value, I max)
log
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
M
long Long
const char GetValue[]
#define N
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
sal_uIntPtr sal_uLong
Complex reference (a range) into the sheet.
Definition: refdata.hxx:123
void InitRange(const ScRange &rRange)
Definition: refdata.hxx:130
ScSingleRefData Ref2
Definition: refdata.hxx:125
ScSingleRefData Ref1
Definition: refdata.hxx:124
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
bool hasEmptyValue()
Definition: cellvalue.cxx:672
bool hasNumeric() const
Definition: cellvalue.cxx:619
FormulaTokenRef extendRangeReference(ScSheetLimits &rLimits, FormulaToken &rTok1, FormulaToken &rTok2, const ScAddress &rPos, bool bReuseDoubleRef)
If rTok1 and rTok2 both are SingleRef or DoubleRef tokens, extend/merge ranges as needed for ocRange.
Definition: token.cxx:504
::std::vector< ScComplexRefData > ScRefList
Definition: token.hxx:37
#define SAL_MAX_UINT8
unsigned char sal_uInt8
#define SAL_MAX_UINT16
sal_uInt16 sal_Unicode
#define SAL_MAX_UINT32
sal_Int16 SCTAB
Definition: types.hxx:22
ScMatValType
Definition: types.hxx:31
sal_Int16 SCCOL
Definition: types.hxx:21
::boost::intrusive_ptr< ScMatrix > ScMatrixRef
Definition: types.hxx:25
::boost::intrusive_ptr< formula::FormulaToken > ScTokenRef
Definition: types.hxx:29
sal_Int32 SCROW
Definition: types.hxx:17
#define C
Definition: xlformula.cxx:66
SvNumFormatType