1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "analysis.hxx" 29 30 #include <cppuhelper/factory.hxx> 31 #include <osl/diagnose.h> 32 #include <rtl/ustrbuf.hxx> 33 #include <rtl/math.hxx> 34 #include <string.h> 35 36 #include <tools/resmgr.hxx> 37 #include <tools/rcid.h> 38 #include "analysis.hrc" 39 #include "bessel.hxx" 40 41 #define ADDIN_SERVICE "com.sun.star.sheet.AddIn" 42 #define MY_SERVICE "com.sun.star.sheet.addin.Analysis" 43 #define MY_IMPLNAME "com.sun.star.sheet.addin.AnalysisImpl" 44 45 using namespace ::rtl; 46 using namespace ::com::sun::star; 47 48 //------------------------------------------------------------------ 49 // 50 // entry points for service registration / instantiation 51 // 52 //------------------------------------------------------------------ 53 54 extern "C" { 55 56 57 void SAL_CALL component_getImplementationEnvironment( const sal_Char** ppEnvTypeName, uno_Environment** /*ppEnv*/ ) 58 { 59 *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; 60 } 61 62 void* SAL_CALL component_getFactory( const sal_Char* pImplName, void* pServiceManager, void* /*pRegistryKey*/ ) 63 { 64 void* pRet = 0; 65 66 if( pServiceManager && STRING::createFromAscii( pImplName ) == AnalysisAddIn::getImplementationName_Static() ) 67 { 68 REF( lang::XSingleServiceFactory ) xFactory( cppu::createOneInstanceFactory( 69 reinterpret_cast< lang::XMultiServiceFactory* >( pServiceManager ), 70 AnalysisAddIn::getImplementationName_Static(), 71 AnalysisAddIn_CreateInstance, 72 AnalysisAddIn::getSupportedServiceNames_Static() ) ); 73 74 if( xFactory.is() ) 75 { 76 xFactory->acquire(); 77 pRet = xFactory.get(); 78 } 79 } 80 81 return pRet; 82 } 83 84 85 } // extern C 86 87 88 89 90 //------------------------------------------------------------------------ 91 // 92 // "normal" service implementation 93 // 94 //------------------------------------------------------------------------ 95 96 97 ResMgr& AnalysisAddIn::GetResMgr( void ) THROWDEF_RTE 98 { 99 if( !pResMgr ) 100 { 101 InitData(); // try to get resource manager 102 103 if( !pResMgr ) 104 THROW_RTE; 105 } 106 107 return *pResMgr; 108 } 109 110 111 STRING AnalysisAddIn::GetDisplFuncStr( sal_uInt16 nFuncNum ) THROWDEF_RTE 112 { 113 return String( AnalysisRscStrLoader( RID_ANALYSIS_FUNCTION_NAMES, nFuncNum, GetResMgr() ).GetString() ); 114 } 115 116 117 class AnalysisResourcePublisher : public Resource 118 { 119 public: 120 AnalysisResourcePublisher( const AnalysisResId& rId ) : Resource( rId ) {} 121 sal_Bool IsAvailableRes( const ResId& rId ) const { return Resource::IsAvailableRes( rId ); } 122 void FreeResource() { Resource::FreeResource(); } 123 }; 124 125 126 class AnalysisFuncRes : public Resource 127 { 128 public: 129 AnalysisFuncRes( ResId& rRes, ResMgr& rResMgr, sal_uInt16 nInd, STRING& rRet ); 130 }; 131 132 133 AnalysisFuncRes::AnalysisFuncRes( ResId& rRes, ResMgr& rResMgr, sal_uInt16 nInd, STRING& rRet ) : Resource( rRes ) 134 { 135 rRet = String( AnalysisResId( nInd, rResMgr ) ); 136 137 FreeResource(); 138 } 139 140 141 STRING AnalysisAddIn::GetFuncDescrStr( sal_uInt16 nResId, sal_uInt16 nStrIndex ) THROWDEF_RTE 142 { 143 STRING aRet; 144 AnalysisResourcePublisher aResPubl( AnalysisResId( RID_ANALYSIS_FUNCTION_DESCRIPTIONS, GetResMgr() ) ); 145 AnalysisResId aRes( nResId, GetResMgr() ); 146 aRes.SetRT( RSC_RESOURCE ); 147 if( aResPubl.IsAvailableRes( aRes ) ) 148 { 149 AnalysisFuncRes aSubRes( aRes, GetResMgr(), nStrIndex, aRet ); 150 } 151 152 aResPubl.FreeResource(); 153 154 return aRet; 155 } 156 157 158 void AnalysisAddIn::InitData( void ) 159 { 160 if( pResMgr ) 161 delete pResMgr; 162 163 OString aModName( "analysis" ); 164 pResMgr = ResMgr::CreateResMgr( ( const sal_Char* ) aModName, 165 aFuncLoc ); 166 167 if( pFD ) 168 delete pFD; 169 170 if( pResMgr ) 171 pFD = new FuncDataList( *pResMgr ); 172 else 173 pFD = NULL; 174 175 if( pDefLocales ) 176 { 177 delete pDefLocales; 178 pDefLocales = NULL; 179 } 180 } 181 182 183 AnalysisAddIn::AnalysisAddIn( const uno::Reference< lang::XMultiServiceFactory >& xServiceFact ) : 184 pDefLocales( NULL ), 185 pFD( NULL ), 186 pFactDoubles( NULL ), 187 pCDL( NULL ), 188 pResMgr( NULL ), 189 aAnyConv( xServiceFact ) 190 { 191 } 192 193 194 AnalysisAddIn::~AnalysisAddIn() 195 { 196 if( pFD ) 197 delete pFD; 198 199 if( pFactDoubles ) 200 delete[] pFactDoubles; 201 202 if( pCDL ) 203 delete pCDL; 204 205 // if( pResMgr ) no delete, because _all_ resource managers are deleted _before_ this dtor is called 206 // delete pResMgr; 207 208 if( pDefLocales ) 209 delete[] pDefLocales; 210 } 211 212 213 sal_Int32 AnalysisAddIn::getDateMode( 214 const uno::Reference< beans::XPropertySet >& xPropSet, 215 const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException ) 216 { 217 sal_Int32 nMode = aAnyConv.getInt32( xPropSet, rAny, 0 ); 218 if( (nMode < 0) || (nMode > 4) ) 219 throw lang::IllegalArgumentException(); 220 return nMode; 221 } 222 223 224 225 //----------------------------------------------------------------------------- 226 227 228 #define MAXFACTDOUBLE 300 229 230 double AnalysisAddIn::FactDouble( sal_Int32 nNum ) THROWDEF_RTE_IAE 231 { 232 if( nNum < 0 || nNum > MAXFACTDOUBLE ) 233 THROW_IAE; 234 235 if( !pFactDoubles ) 236 { 237 pFactDoubles = new double[ MAXFACTDOUBLE + 1 ]; 238 239 pFactDoubles[ 0 ] = 1.0; // by default 240 241 double fOdd = 1.0; 242 double fEven = 2.0; 243 244 pFactDoubles[ 1 ] = fOdd; 245 pFactDoubles[ 2 ] = fEven; 246 247 sal_Bool bOdd = sal_True; 248 249 for( sal_uInt16 nCnt = 3 ; nCnt <= MAXFACTDOUBLE ; nCnt++ ) 250 { 251 if( bOdd ) 252 { 253 fOdd *= nCnt; 254 pFactDoubles[ nCnt ] = fOdd; 255 } 256 else 257 { 258 fEven *= nCnt; 259 pFactDoubles[ nCnt ] = fEven; 260 } 261 262 bOdd = !bOdd; 263 264 } 265 } 266 267 return pFactDoubles[ nNum ]; 268 } 269 270 271 STRING AnalysisAddIn::getImplementationName_Static() 272 { 273 return STRFROMASCII( MY_IMPLNAME ); 274 } 275 276 277 SEQ( STRING ) AnalysisAddIn::getSupportedServiceNames_Static() 278 { 279 SEQ( STRING ) aRet(2); 280 STRING* pArray = aRet.getArray(); 281 pArray[0] = STRFROMASCII( ADDIN_SERVICE ); 282 pArray[1] = STRFROMASCII( MY_SERVICE ); 283 return aRet; 284 } 285 286 287 REF( uno::XInterface ) SAL_CALL AnalysisAddIn_CreateInstance( 288 const uno::Reference< lang::XMultiServiceFactory >& xServiceFact ) 289 { 290 static uno::Reference< uno::XInterface > xInst = (cppu::OWeakObject*) new AnalysisAddIn( xServiceFact ); 291 return xInst; 292 } 293 294 295 // XServiceName 296 297 STRING SAL_CALL AnalysisAddIn::getServiceName() THROWDEF_RTE 298 { 299 // name of specific AddIn service 300 return STRFROMASCII( MY_SERVICE ); 301 } 302 303 304 // XServiceInfo 305 306 STRING SAL_CALL AnalysisAddIn::getImplementationName() THROWDEF_RTE 307 { 308 return getImplementationName_Static(); 309 } 310 311 312 sal_Bool SAL_CALL AnalysisAddIn::supportsService( const STRING& aName ) THROWDEF_RTE 313 { 314 return aName.compareToAscii( ADDIN_SERVICE ) == 0 || aName.compareToAscii( MY_SERVICE ) == 0; 315 } 316 317 318 SEQ( STRING ) SAL_CALL AnalysisAddIn::getSupportedServiceNames() THROWDEF_RTE 319 { 320 return getSupportedServiceNames_Static(); 321 } 322 323 324 // XLocalizable 325 326 void SAL_CALL AnalysisAddIn::setLocale( const lang::Locale& eLocale ) THROWDEF_RTE 327 { 328 aFuncLoc = eLocale; 329 330 InitData(); // change of locale invalidates resources! 331 } 332 333 lang::Locale SAL_CALL AnalysisAddIn::getLocale() THROWDEF_RTE 334 { 335 return aFuncLoc; 336 } 337 338 339 // XAddIn 340 341 STRING SAL_CALL AnalysisAddIn::getProgrammaticFuntionName( const STRING& ) THROWDEF_RTE 342 { 343 // not used by calc 344 // (but should be implemented for other uses of the AddIn service) 345 346 return STRING(); 347 } 348 349 350 STRING SAL_CALL AnalysisAddIn::getDisplayFunctionName( const STRING& aProgrammaticName ) THROWDEF_RTE 351 { 352 STRING aRet; 353 354 const FuncData* p = pFD->Get( aProgrammaticName ); 355 if( p ) 356 { 357 aRet = GetDisplFuncStr( p->GetUINameID() ); 358 if( p->IsDouble() ) 359 aRet += STRFROMANSI( "_ADD" ); 360 } 361 else 362 { 363 aRet = STRFROMANSI( "UNKNOWNFUNC_" ); 364 aRet += aProgrammaticName; 365 } 366 367 return aRet; 368 } 369 370 371 STRING SAL_CALL AnalysisAddIn::getFunctionDescription( const STRING& aProgrammaticName ) THROWDEF_RTE 372 { 373 STRING aRet; 374 375 const FuncData* p = pFD->Get( aProgrammaticName ); 376 if( p ) 377 aRet = GetFuncDescrStr( p->GetDescrID(), 1 ); 378 379 return aRet; 380 } 381 382 383 STRING SAL_CALL AnalysisAddIn::getDisplayArgumentName( const STRING& aName, sal_Int32 nArg ) THROWDEF_RTE 384 { 385 STRING aRet; 386 387 const FuncData* p = pFD->Get( aName ); 388 if( p && nArg <= 0xFFFF ) 389 { 390 sal_uInt16 nStr = p->GetStrIndex( sal_uInt16( nArg ) ); 391 if( nStr /*&& nStr < 4*/ ) 392 aRet = GetFuncDescrStr( p->GetDescrID(), nStr ); 393 else 394 aRet = STRFROMANSI( "internal" ); 395 } 396 397 return aRet; 398 } 399 400 401 STRING SAL_CALL AnalysisAddIn::getArgumentDescription( const STRING& aName, sal_Int32 nArg ) THROWDEF_RTE 402 { 403 STRING aRet; 404 405 const FuncData* p = pFD->Get( aName ); 406 if( p && nArg <= 0xFFFF ) 407 { 408 sal_uInt16 nStr = p->GetStrIndex( sal_uInt16( nArg ) ); 409 if( nStr /*&& nStr < 4*/ ) 410 aRet = GetFuncDescrStr( p->GetDescrID(), nStr + 1 ); 411 else 412 aRet = STRFROMANSI( "for internal use only" ); 413 } 414 415 return aRet; 416 } 417 418 419 static const char* pDefCatName = "Add-In"; 420 421 422 STRING SAL_CALL AnalysisAddIn::getProgrammaticCategoryName( const STRING& aName ) THROWDEF_RTE 423 { 424 // return non-translated strings 425 // return STRFROMASCII( "Add-In" ); 426 const FuncData* p = pFD->Get( aName ); 427 STRING aRet; 428 if( p ) 429 { 430 const sal_Char* pStr; 431 432 switch( p->GetCategory() ) 433 { 434 case FDCat_DateTime: pStr = "Date&Time"; break; 435 case FDCat_Finance: pStr = "Financial"; break; 436 case FDCat_Inf: pStr = "Information"; break; 437 case FDCat_Math: pStr = "Mathematical"; break; 438 case FDCat_Tech: pStr = "Technical"; break; 439 default: 440 pStr = pDefCatName; break; 441 } 442 443 aRet = STRFROMASCII( pStr ); 444 } 445 else 446 aRet = STRFROMASCII( pDefCatName ); 447 448 return aRet; 449 } 450 451 452 STRING SAL_CALL AnalysisAddIn::getDisplayCategoryName( const STRING& aProgrammaticFunctionName ) THROWDEF_RTE 453 { 454 // return translated strings, not used for predefined categories 455 // return STRFROMASCII( "Add-In" ); 456 const FuncData* p = pFD->Get( aProgrammaticFunctionName ); 457 STRING aRet; 458 if( p ) 459 { 460 const sal_Char* pStr; 461 462 switch( p->GetCategory() ) 463 { 464 case FDCat_DateTime: pStr = "Date&Time"; break; 465 case FDCat_Finance: pStr = "Financial"; break; 466 case FDCat_Inf: pStr = "Information"; break; 467 case FDCat_Math: pStr = "Mathematical"; break; 468 case FDCat_Tech: pStr = "Technical"; break; 469 default: 470 pStr = pDefCatName; break; 471 } 472 473 aRet = STRFROMASCII( pStr ); 474 } 475 else 476 aRet = STRFROMASCII( pDefCatName ); 477 478 return aRet; 479 } 480 481 482 static const sal_Char* pLang[] = { "de", "en" }; 483 static const sal_Char* pCoun[] = { "DE", "US" }; 484 static const sal_uInt32 nNumOfLoc = sizeof( pLang ) / sizeof( sal_Char* ); 485 486 487 void AnalysisAddIn::InitDefLocales( void ) 488 { 489 pDefLocales = new CSS::lang::Locale[ nNumOfLoc ]; 490 491 for( sal_uInt32 n = 0 ; n < nNumOfLoc ; n++ ) 492 { 493 pDefLocales[ n ].Language = STRING::createFromAscii( pLang[ n ] ); 494 pDefLocales[ n ].Country = STRING::createFromAscii( pCoun[ n ] ); 495 } 496 } 497 498 499 inline const CSS::lang::Locale& AnalysisAddIn::GetLocale( sal_uInt32 nInd ) 500 { 501 if( !pDefLocales ) 502 InitDefLocales(); 503 504 if( nInd < sizeof( pLang ) ) 505 return pDefLocales[ nInd ]; 506 else 507 return aFuncLoc; 508 } 509 510 511 SEQofLocName SAL_CALL AnalysisAddIn::getCompatibilityNames( const STRING& aProgrammaticName ) THROWDEF_RTE 512 { 513 const FuncData* p = pFD->Get( aProgrammaticName ); 514 515 if( !p ) 516 return SEQofLocName( 0 ); 517 518 const StringList& r = p->GetCompNameList(); 519 sal_uInt32 nCount = r.Count(); 520 521 SEQofLocName aRet( nCount ); 522 523 CSS::sheet::LocalizedName* pArray = aRet.getArray(); 524 525 for( sal_uInt32 n = 0 ; n < nCount ; n++ ) 526 { 527 pArray[ n ] = CSS::sheet::LocalizedName( GetLocale( n ), *r.Get( n ) ); 528 } 529 530 return aRet; 531 } 532 533 534 // XAnalysis 535 536 /*double SAL_CALL AnalysisAddIn::get_Test( constREFXPS&, 537 sal_Int32 nMode, double f1, double f2, double f3 ) THROWDEF_RTE 538 { 539 return _Test( nMode, f1, f2, f3 ); 540 }*/ 541 542 543 /** 544 * Workday 545 */ 546 547 sal_Int32 SAL_CALL AnalysisAddIn::getWorkday( constREFXPS& xOptions, 548 sal_Int32 nDate, sal_Int32 nDays, const ANY& aHDay ) THROWDEF_RTE_IAE 549 { 550 if( !nDays ) 551 return nDate; 552 553 sal_Int32 nNullDate = GetNullDate( xOptions ); 554 555 SortedIndividualInt32List aSrtLst; 556 557 aSrtLst.InsertHolidayList( aAnyConv, xOptions, aHDay, nNullDate, sal_False ); 558 559 sal_Int32 nActDate = nDate + nNullDate; 560 561 if( nDays > 0 ) 562 { 563 if( GetDayOfWeek( nActDate ) == 5 ) 564 // when starting on Saturday, assuming we're starting on Sunday to get the jump over the weekend 565 nActDate++; 566 567 while( nDays ) 568 { 569 nActDate++; 570 571 if( GetDayOfWeek( nActDate ) < 5 ) 572 { 573 if( !aSrtLst.Find( nActDate ) ) 574 nDays--; 575 } 576 else 577 nActDate++; // jump over weekend 578 } 579 } 580 else 581 { 582 if( GetDayOfWeek( nActDate ) == 6 ) 583 // when starting on Sunday, assuming we're starting on Saturday to get the jump over the weekend 584 nActDate--; 585 586 while( nDays ) 587 { 588 nActDate--; 589 590 if( GetDayOfWeek( nActDate ) < 5 ) 591 { 592 if( !aSrtLst.Find( nActDate ) ) 593 nDays++; 594 } 595 else 596 nActDate--; // jump over weekend 597 } 598 } 599 600 return nActDate - nNullDate; 601 } 602 603 604 /** 605 * Yearfrac 606 */ 607 608 double SAL_CALL AnalysisAddIn::getYearfrac( constREFXPS& xOpt, 609 sal_Int32 nStartDate, sal_Int32 nEndDate, const ANY& rMode ) THROWDEF_RTE_IAE 610 { 611 double fRet = GetYearFrac( xOpt, nStartDate, nEndDate, getDateMode( xOpt, rMode ) ); 612 RETURN_FINITE( fRet ); 613 } 614 615 616 sal_Int32 SAL_CALL AnalysisAddIn::getEdate( constREFXPS& xOpt, sal_Int32 nStartDate, sal_Int32 nMonths ) THROWDEF_RTE_IAE 617 { 618 sal_Int32 nNullDate = GetNullDate( xOpt ); 619 ScaDate aDate( nNullDate, nStartDate, 5 ); 620 aDate.addMonths( nMonths ); 621 return aDate.getDate( nNullDate ); 622 } 623 624 625 sal_Int32 SAL_CALL AnalysisAddIn::getWeeknum( constREFXPS& xOpt, sal_Int32 nDate, sal_Int32 nMode ) THROWDEF_RTE_IAE 626 { 627 nDate += GetNullDate( xOpt ); 628 629 sal_uInt16 nDay, nMonth, nYear; 630 DaysToDate( nDate, nDay, nMonth, nYear ); 631 632 sal_Int32 nFirstInYear = DateToDays( 1, 1, nYear ); 633 sal_uInt16 nFirstDayInYear = GetDayOfWeek( nFirstInYear ); 634 635 return ( nDate - nFirstInYear + ( ( nMode == 1 )? ( nFirstDayInYear + 1 ) % 7 : nFirstDayInYear ) ) / 7 + 1; 636 } 637 638 639 sal_Int32 SAL_CALL AnalysisAddIn::getEomonth( constREFXPS& xOpt, sal_Int32 nDate, sal_Int32 nMonths ) THROWDEF_RTE_IAE 640 { 641 sal_Int32 nNullDate = GetNullDate( xOpt ); 642 nDate += nNullDate; 643 sal_uInt16 nDay, nMonth, nYear; 644 DaysToDate( nDate, nDay, nMonth, nYear ); 645 646 sal_Int32 nNewMonth = nMonth + nMonths; 647 648 if( nNewMonth > 12 ) 649 { 650 nYear = sal::static_int_cast<sal_uInt16>( nYear + ( nNewMonth / 12 ) ); 651 nNewMonth %= 12; 652 } 653 else if( nNewMonth < 1 ) 654 { 655 nNewMonth = -nNewMonth; 656 nYear = sal::static_int_cast<sal_uInt16>( nYear - ( nNewMonth / 12 ) ); 657 nYear--; 658 nNewMonth %= 12; 659 nNewMonth = 12 - nNewMonth; 660 } 661 662 return DateToDays( DaysInMonth( sal_uInt16( nNewMonth ), nYear ), sal_uInt16( nNewMonth ), nYear ) - nNullDate; 663 } 664 665 666 sal_Int32 SAL_CALL AnalysisAddIn::getNetworkdays( constREFXPS& xOpt, 667 sal_Int32 nStartDate, sal_Int32 nEndDate, const ANY& aHDay ) THROWDEF_RTE_IAE 668 { 669 sal_Int32 nNullDate = GetNullDate( xOpt ); 670 671 SortedIndividualInt32List aSrtLst; 672 673 aSrtLst.InsertHolidayList( aAnyConv, xOpt, aHDay, nNullDate, sal_False ); 674 675 sal_Int32 nActDate = nStartDate + nNullDate; 676 sal_Int32 nStopDate = nEndDate + nNullDate; 677 sal_Int32 nCnt = 0; 678 679 if( nActDate <= nStopDate ) 680 { 681 while( nActDate <= nStopDate ) 682 { 683 if( GetDayOfWeek( nActDate ) < 5 && !aSrtLst.Find( nActDate ) ) 684 nCnt++; 685 686 nActDate++; 687 } 688 } 689 else 690 { 691 while( nActDate >= nStopDate ) 692 { 693 if( GetDayOfWeek( nActDate ) < 5 && !aSrtLst.Find( nActDate ) ) 694 nCnt--; 695 696 nActDate--; 697 } 698 } 699 700 return nCnt; 701 } 702 703 704 sal_Int32 SAL_CALL AnalysisAddIn::getIseven( sal_Int32 nVal ) THROWDEF_RTE_IAE 705 { 706 return ( nVal & 0x00000001 )? 0 : 1; 707 } 708 709 710 sal_Int32 SAL_CALL AnalysisAddIn::getIsodd( sal_Int32 nVal ) THROWDEF_RTE_IAE 711 { 712 return ( nVal & 0x00000001 )? 1 : 0; 713 } 714 715 double SAL_CALL 716 AnalysisAddIn::getMultinomial( constREFXPS& xOpt, const SEQSEQ( sal_Int32 )& aVLst, 717 const SEQ( uno::Any )& aOptVLst ) THROWDEF_RTE_IAE 718 { 719 ScaDoubleListGE0 aValList; 720 721 aValList.Append( aVLst ); 722 aValList.Append( aAnyConv, xOpt, aOptVLst ); 723 724 if( aValList.Count() == 0 ) 725 return 0.0; 726 727 sal_Int32 nZ = 0; 728 double fN = 1.0; 729 730 for( const double *p = aValList.First(); p; p = aValList.Next() ) 731 { 732 double fInt = (*p >= 0.0) ? rtl::math::approxFloor( *p ) : rtl::math::approxCeil( *p ); 733 if ( fInt < 0.0 || fInt > 170.0 ) 734 THROW_IAE; 735 sal_Int32 n = static_cast< sal_Int32 >( fInt ); 736 if( n > 0 ) 737 { 738 nZ += n; 739 fN *= Fak( n ); 740 } 741 } 742 743 if( nZ > 170 ) 744 THROW_IAE; 745 746 double fRet = Fak( nZ ) / fN; 747 RETURN_FINITE( fRet ); 748 } 749 750 751 double SAL_CALL AnalysisAddIn::getSeriessum( double fX, double fN, double fM, const SEQSEQ( double )& aCoeffList ) THROWDEF_RTE_IAE 752 { 753 double fRet = 0.0; 754 755 // #i32269# 0^0 is undefined, Excel returns #NUM! error 756 if( fX == 0.0 && fN == 0 ) 757 THROW_RTE; 758 759 if( fX != 0.0 ) 760 { 761 sal_Int32 n1, n2; 762 sal_Int32 nE1 = aCoeffList.getLength(); 763 sal_Int32 nE2; 764 //sal_Int32 nZ = 0; 765 766 for( n1 = 0 ; n1 < nE1 ; n1++ ) 767 { 768 const SEQ( double )& rList = aCoeffList[ n1 ]; 769 nE2 = rList.getLength(); 770 const double* pList = rList.getConstArray(); 771 772 for( n2 = 0 ; n2 < nE2 ; n2++ ) 773 { 774 fRet += pList[ n2 ] * pow( fX, fN ); 775 776 fN += fM; 777 } 778 } 779 } 780 781 RETURN_FINITE( fRet ); 782 } 783 784 785 double SAL_CALL AnalysisAddIn::getQuotient( double fNum, double fDenom ) THROWDEF_RTE_IAE 786 { 787 double fRet; 788 if( (fNum < 0) != (fDenom < 0) ) 789 fRet = ::rtl::math::approxCeil( fNum / fDenom ); 790 else 791 fRet = ::rtl::math::approxFloor( fNum / fDenom ); 792 RETURN_FINITE( fRet ); 793 } 794 795 796 double SAL_CALL AnalysisAddIn::getMround( double fNum, double fMult ) THROWDEF_RTE_IAE 797 { 798 if( fMult == 0.0 ) 799 return fMult; 800 801 double fRet = fMult * ::rtl::math::round( fNum / fMult ); 802 RETURN_FINITE( fRet ); 803 } 804 805 806 double SAL_CALL AnalysisAddIn::getSqrtpi( double fNum ) THROWDEF_RTE_IAE 807 { 808 double fRet = sqrt( fNum * PI ); 809 RETURN_FINITE( fRet ); 810 } 811 812 813 double SAL_CALL AnalysisAddIn::getRandbetween( double fMin, double fMax ) THROWDEF_RTE_IAE 814 { 815 fMin = ::rtl::math::round( fMin, 0, rtl_math_RoundingMode_Up ); 816 fMax = ::rtl::math::round( fMax, 0, rtl_math_RoundingMode_Up ); 817 if( fMin > fMax ) 818 THROW_IAE; 819 820 // fMax -> range 821 double fRet = fMax - fMin + 1.0; 822 fRet *= rand(); 823 fRet /= (RAND_MAX + 1.0); 824 fRet += fMin; 825 fRet = floor( fRet ); // simple floor is sufficient here 826 RETURN_FINITE( fRet ); 827 } 828 829 830 double SAL_CALL AnalysisAddIn::getGcd( constREFXPS& xOpt, const SEQSEQ( double )& aVLst, const SEQ( uno::Any )& aOptVLst ) THROWDEF_RTE_IAE 831 { 832 ScaDoubleListGT0 aValList; 833 834 aValList.Append( aVLst ); 835 aValList.Append( aAnyConv, xOpt, aOptVLst ); 836 837 if( aValList.Count() == 0 ) 838 return 0.0; 839 840 const double* p = aValList.First(); 841 double f = *p; 842 843 p = aValList.Next(); 844 845 while( p ) 846 { 847 f = GetGcd( *p, f ); 848 p = aValList.Next(); 849 } 850 851 RETURN_FINITE( f ); 852 } 853 854 855 double SAL_CALL AnalysisAddIn::getLcm( constREFXPS& xOpt, const SEQSEQ( double )& aVLst, const SEQ( uno::Any )& aOptVLst ) THROWDEF_RTE_IAE 856 { 857 ScaDoubleListGE0 aValList; 858 859 aValList.Append( aVLst ); 860 aValList.Append( aAnyConv, xOpt, aOptVLst ); 861 862 if( aValList.Count() == 0 ) 863 return 0.0; 864 865 const double* p = aValList.First(); 866 double f = *p; 867 868 if( f == 0.0 ) 869 return f; 870 871 p = aValList.Next(); 872 873 while( p ) 874 { 875 double fTmp = *p; 876 if( f == 0.0 ) 877 return f; 878 else 879 f = fTmp * f / GetGcd( fTmp, f ); 880 p = aValList.Next(); 881 } 882 883 RETURN_FINITE( f ); 884 } 885 886 887 double SAL_CALL AnalysisAddIn::getBesseli( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE 888 { 889 double fRet = sca::analysis::BesselI( fNum, nOrder ); 890 RETURN_FINITE( fRet ); 891 } 892 893 894 double SAL_CALL AnalysisAddIn::getBesselj( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE 895 { 896 double fRet = sca::analysis::BesselJ( fNum, nOrder ); 897 RETURN_FINITE( fRet ); 898 } 899 900 901 double SAL_CALL AnalysisAddIn::getBesselk( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE 902 { 903 if( nOrder < 0 || fNum <= 0.0 ) 904 THROW_IAE; 905 906 double fRet = sca::analysis::BesselK( fNum, nOrder ); 907 RETURN_FINITE( fRet ); 908 } 909 910 911 double SAL_CALL AnalysisAddIn::getBessely( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE 912 { 913 if( nOrder < 0 || fNum <= 0.0 ) 914 THROW_IAE; 915 916 // return yn( nOrder, fNum ); 917 double fRet = sca::analysis::BesselY( fNum, nOrder ); 918 RETURN_FINITE( fRet ); 919 } 920 921 922 const double SCA_MAX2 = 511.0; // min. val for binary numbers (9 bits + sign) 923 const double SCA_MIN2 = -SCA_MAX2-1.0; // min. val for binary numbers (9 bits + sign) 924 const double SCA_MAX8 = 536870911.0; // max. val for octal numbers (29 bits + sign) 925 const double SCA_MIN8 = -SCA_MAX8-1.0; // min. val for octal numbers (29 bits + sign) 926 const double SCA_MAX16 = 549755813888.0; // max. val for hexadecimal numbers (39 bits + sign) 927 const double SCA_MIN16 = -SCA_MAX16-1.0; // min. val for hexadecimal numbers (39 bits + sign) 928 const sal_Int32 SCA_MAXPLACES = 10; // max. number of places 929 930 931 STRING SAL_CALL AnalysisAddIn::getBin2Oct( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE 932 { 933 double fVal = ConvertToDec( aNum, 2, SCA_MAXPLACES ); 934 sal_Int32 nPlaces = 0; 935 sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces ); 936 return ConvertFromDec( fVal, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces ); 937 } 938 939 940 double SAL_CALL AnalysisAddIn::getBin2Dec( const STRING& aNum ) THROWDEF_RTE_IAE 941 { 942 double fRet = ConvertToDec( aNum, 2, SCA_MAXPLACES ); 943 RETURN_FINITE( fRet ); 944 } 945 946 947 STRING SAL_CALL AnalysisAddIn::getBin2Hex( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE 948 { 949 double fVal = ConvertToDec( aNum, 2, SCA_MAXPLACES ); 950 sal_Int32 nPlaces = 0; 951 sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces ); 952 return ConvertFromDec( fVal, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces ); 953 } 954 955 956 STRING SAL_CALL AnalysisAddIn::getOct2Bin( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE 957 { 958 double fVal = ConvertToDec( aNum, 8, SCA_MAXPLACES ); 959 sal_Int32 nPlaces = 0; 960 sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces ); 961 return ConvertFromDec( fVal, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces ); 962 } 963 964 965 double SAL_CALL AnalysisAddIn::getOct2Dec( const STRING& aNum ) THROWDEF_RTE_IAE 966 { 967 double fRet = ConvertToDec( aNum, 8, SCA_MAXPLACES ); 968 RETURN_FINITE( fRet ); 969 } 970 971 972 STRING SAL_CALL AnalysisAddIn::getOct2Hex( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE 973 { 974 double fVal = ConvertToDec( aNum, 8, SCA_MAXPLACES ); 975 sal_Int32 nPlaces = 0; 976 sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces ); 977 return ConvertFromDec( fVal, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces ); 978 } 979 980 981 STRING SAL_CALL AnalysisAddIn::getDec2Bin( constREFXPS& xOpt, sal_Int32 nNum, const ANY& rPlaces ) THROWDEF_RTE_IAE 982 { 983 sal_Int32 nPlaces = 0; 984 sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces ); 985 return ConvertFromDec( nNum, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces ); 986 } 987 988 989 STRING SAL_CALL AnalysisAddIn::getDec2Oct( constREFXPS& xOpt, sal_Int32 nNum, const ANY& rPlaces ) THROWDEF_RTE_IAE 990 { 991 sal_Int32 nPlaces = 0; 992 sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces ); 993 return ConvertFromDec( nNum, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces ); 994 } 995 996 997 STRING SAL_CALL AnalysisAddIn::getDec2Hex( constREFXPS& xOpt, double fNum, const ANY& rPlaces ) THROWDEF_RTE_IAE 998 { 999 sal_Int32 nPlaces = 0; 1000 sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces ); 1001 return ConvertFromDec( fNum, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces ); 1002 } 1003 1004 1005 STRING SAL_CALL AnalysisAddIn::getHex2Bin( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE 1006 { 1007 double fVal = ConvertToDec( aNum, 16, SCA_MAXPLACES ); 1008 sal_Int32 nPlaces = 0; 1009 sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces ); 1010 return ConvertFromDec( fVal, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces ); 1011 } 1012 1013 1014 double SAL_CALL AnalysisAddIn::getHex2Dec( const STRING& aNum ) THROWDEF_RTE_IAE 1015 { 1016 double fRet = ConvertToDec( aNum, 16, SCA_MAXPLACES ); 1017 RETURN_FINITE( fRet ); 1018 } 1019 1020 1021 STRING SAL_CALL AnalysisAddIn::getHex2Oct( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE 1022 { 1023 double fVal = ConvertToDec( aNum, 16, SCA_MAXPLACES ); 1024 sal_Int32 nPlaces = 0; 1025 sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces ); 1026 return ConvertFromDec( fVal, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces ); 1027 } 1028 1029 1030 sal_Int32 SAL_CALL AnalysisAddIn::getDelta( constREFXPS& xOpt, double fNum1, const ANY& rNum2 ) THROWDEF_RTE_IAE 1031 { 1032 return fNum1 == aAnyConv.getDouble( xOpt, rNum2, 0.0 ); 1033 } 1034 1035 1036 double SAL_CALL AnalysisAddIn::getErf( constREFXPS& xOpt, double fLL, const ANY& rUL ) THROWDEF_RTE_IAE 1037 { 1038 double fUL, fRet; 1039 sal_Bool bContainsValue = aAnyConv.getDouble( fUL, xOpt, rUL ); 1040 1041 fRet = bContainsValue ? (Erf( fUL ) - Erf( fLL )) : Erf( fLL ); 1042 RETURN_FINITE( fRet ); 1043 } 1044 1045 1046 double SAL_CALL AnalysisAddIn::getErfc( double f ) THROWDEF_RTE_IAE 1047 { 1048 double fRet = Erfc( f ); 1049 RETURN_FINITE( fRet ); 1050 } 1051 1052 1053 sal_Int32 SAL_CALL AnalysisAddIn::getGestep( constREFXPS& xOpt, double fNum, const ANY& rStep ) THROWDEF_RTE_IAE 1054 { 1055 return fNum >= aAnyConv.getDouble( xOpt, rStep, 0.0 ); 1056 } 1057 1058 1059 double SAL_CALL AnalysisAddIn::getFactdouble( sal_Int32 nNum ) THROWDEF_RTE_IAE 1060 { 1061 double fRet = FactDouble( nNum ); 1062 RETURN_FINITE( fRet ); 1063 } 1064 1065 1066 double SAL_CALL AnalysisAddIn::getImabs( const STRING& aNum ) THROWDEF_RTE_IAE 1067 { 1068 double fRet = Complex( aNum ).Abs(); 1069 RETURN_FINITE( fRet ); 1070 } 1071 1072 1073 double SAL_CALL AnalysisAddIn::getImaginary( const STRING& aNum ) THROWDEF_RTE_IAE 1074 { 1075 double fRet = Complex( aNum ).Imag(); 1076 RETURN_FINITE( fRet ); 1077 } 1078 1079 1080 STRING SAL_CALL AnalysisAddIn::getImpower( const STRING& aNum, double f ) THROWDEF_RTE_IAE 1081 { 1082 Complex z( aNum ); 1083 1084 z.Power( f ); 1085 1086 return z.GetString(); 1087 } 1088 1089 1090 double SAL_CALL AnalysisAddIn::getImargument( const STRING& aNum ) THROWDEF_RTE_IAE 1091 { 1092 double fRet = Complex( aNum ).Arg(); 1093 RETURN_FINITE( fRet ); 1094 } 1095 1096 1097 STRING SAL_CALL AnalysisAddIn::getImcos( const STRING& aNum ) THROWDEF_RTE_IAE 1098 { 1099 Complex z( aNum ); 1100 1101 z.Cos(); 1102 1103 return z.GetString(); 1104 } 1105 1106 1107 STRING SAL_CALL AnalysisAddIn::getImdiv( const STRING& aDivid, const STRING& aDivis ) THROWDEF_RTE_IAE 1108 { 1109 Complex z( aDivid ); 1110 1111 z.Div( Complex( aDivis ) ); 1112 1113 return z.GetString(); 1114 } 1115 1116 1117 STRING SAL_CALL AnalysisAddIn::getImexp( const STRING& aNum ) THROWDEF_RTE_IAE 1118 { 1119 Complex z( aNum ); 1120 1121 z.Exp(); 1122 1123 return z.GetString(); 1124 } 1125 1126 1127 STRING SAL_CALL AnalysisAddIn::getImconjugate( const STRING& aNum ) THROWDEF_RTE_IAE 1128 { 1129 Complex z( aNum ); 1130 1131 z.Conjugate(); 1132 1133 return z.GetString(); 1134 } 1135 1136 1137 STRING SAL_CALL AnalysisAddIn::getImln( const STRING& aNum ) THROWDEF_RTE_IAE 1138 { 1139 Complex z( aNum ); 1140 1141 z.Ln(); 1142 1143 return z.GetString(); 1144 } 1145 1146 1147 STRING SAL_CALL AnalysisAddIn::getImlog10( const STRING& aNum ) THROWDEF_RTE_IAE 1148 { 1149 Complex z( aNum ); 1150 1151 z.Log10(); 1152 1153 return z.GetString(); 1154 } 1155 1156 1157 STRING SAL_CALL AnalysisAddIn::getImlog2( const STRING& aNum ) THROWDEF_RTE_IAE 1158 { 1159 Complex z( aNum ); 1160 1161 z.Log2(); 1162 1163 return z.GetString(); 1164 } 1165 1166 1167 STRING SAL_CALL AnalysisAddIn::getImproduct( constREFXPS&, const SEQSEQ( STRING )& aNum1, const SEQ( uno::Any )& aNL ) THROWDEF_RTE_IAE 1168 { 1169 ComplexList z_list; 1170 1171 z_list.Append( aNum1, AH_IgnoreEmpty ); 1172 z_list.Append( aNL, AH_IgnoreEmpty ); 1173 1174 const Complex* p = z_list.First(); 1175 1176 if( !p ) 1177 return Complex( 0 ).GetString(); 1178 1179 Complex z( *p ); 1180 1181 for( p = z_list.Next() ; p ; p = z_list.Next() ) 1182 z.Mult( *p ); 1183 1184 return z.GetString(); 1185 } 1186 1187 1188 double SAL_CALL AnalysisAddIn::getImreal( const STRING& aNum ) THROWDEF_RTE_IAE 1189 { 1190 double fRet = Complex( aNum ).Real(); 1191 RETURN_FINITE( fRet ); 1192 } 1193 1194 1195 STRING SAL_CALL AnalysisAddIn::getImsin( const STRING& aNum ) THROWDEF_RTE_IAE 1196 { 1197 Complex z( aNum ); 1198 1199 z.Sin(); 1200 1201 return z.GetString(); 1202 } 1203 1204 1205 STRING SAL_CALL AnalysisAddIn::getImsub( const STRING& aNum1, const STRING& aNum2 ) THROWDEF_RTE_IAE 1206 { 1207 Complex z( aNum1 ); 1208 1209 z.Sub( Complex( aNum2 ) ); 1210 1211 return z.GetString(); 1212 } 1213 1214 1215 STRING SAL_CALL AnalysisAddIn::getImsum( constREFXPS&, const SEQSEQ( STRING )& aNum1, const SEQ( CSS::uno::Any )& aFollowingPars ) THROWDEF_RTE_IAE 1216 { 1217 ComplexList z_list; 1218 1219 z_list.Append( aNum1, AH_IgnoreEmpty ); 1220 z_list.Append( aFollowingPars, AH_IgnoreEmpty ); 1221 1222 const Complex* p = z_list.First(); 1223 1224 if( !p ) 1225 return Complex( 0 ).GetString(); 1226 1227 Complex z( *p ); 1228 1229 for( p = z_list.Next() ; p ; p = z_list.Next() ) 1230 z.Add( *p ); 1231 1232 return z.GetString(); 1233 } 1234 1235 1236 STRING SAL_CALL AnalysisAddIn::getImsqrt( const STRING& aNum ) THROWDEF_RTE_IAE 1237 { 1238 Complex z( aNum ); 1239 1240 // z.Power( 0.5 ); 1241 z.Sqrt(); 1242 1243 return z.GetString(); 1244 } 1245 1246 1247 STRING SAL_CALL AnalysisAddIn::getComplex( double fR, double fI, const ANY& rSuff ) THROWDEF_RTE_IAE 1248 { 1249 sal_Bool bi; 1250 1251 switch( rSuff.getValueTypeClass() ) 1252 { 1253 case uno::TypeClass_VOID: 1254 bi = sal_True; 1255 break; 1256 case uno::TypeClass_STRING: 1257 { 1258 const STRING* pSuff = ( const STRING* ) rSuff.getValue(); 1259 bi = pSuff->compareToAscii( "i" ) == 0 || pSuff->getLength() == 0; 1260 if( !bi && pSuff->compareToAscii( "j" ) != 0 ) 1261 THROW_IAE; 1262 } 1263 break; 1264 default: 1265 THROW_IAE; 1266 } 1267 1268 return Complex( fR, fI, bi ? 'i' : 'j' ).GetString(); 1269 } 1270 1271 1272 double SAL_CALL AnalysisAddIn::getConvert( double f, const STRING& aFU, const STRING& aTU ) THROWDEF_RTE_IAE 1273 { 1274 if( !pCDL ) 1275 pCDL = new ConvertDataList(); 1276 1277 double fRet = pCDL->Convert( f, aFU, aTU ); 1278 RETURN_FINITE( fRet ); 1279 } 1280 1281 1282