xref: /trunk/main/scaddins/source/analysis/analysis.cxx (revision 30acf5e801d38c3701bf451b42e514ce81855b4c)
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