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