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