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