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