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