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