xref: /AOO41X/main/scaddins/source/analysis/analysis.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
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 <string.h>
31 
32 #include <tools/resmgr.hxx>
33 #include <tools/rcid.h>
34 #include "analysis.hrc"
35 #include "bessel.hxx"
36 
37 #define ADDIN_SERVICE               "com.sun.star.sheet.AddIn"
38 #define MY_SERVICE                  "com.sun.star.sheet.addin.Analysis"
39 #define MY_IMPLNAME                 "com.sun.star.sheet.addin.AnalysisImpl"
40 
41 using namespace                 ::rtl;
42 using namespace                 ::com::sun::star;
43 
44 //------------------------------------------------------------------
45 //
46 //  entry points for service registration / instantiation
47 //
48 //------------------------------------------------------------------
49 
50 extern "C" {
51 
52 
53 void SAL_CALL component_getImplementationEnvironment( const sal_Char** ppEnvTypeName, uno_Environment** /*ppEnv*/ )
54 {
55     *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
56 }
57 
58 void* SAL_CALL component_getFactory( const sal_Char* pImplName, void* pServiceManager, void* /*pRegistryKey*/ )
59 {
60     void*                                   pRet = 0;
61 
62     if( pServiceManager && STRING::createFromAscii( pImplName ) == AnalysisAddIn::getImplementationName_Static() )
63     {
64         REF( lang::XSingleServiceFactory )  xFactory( cppu::createOneInstanceFactory(
65                 reinterpret_cast< lang::XMultiServiceFactory* >( pServiceManager ),
66                 AnalysisAddIn::getImplementationName_Static(),
67                 AnalysisAddIn_CreateInstance,
68                 AnalysisAddIn::getSupportedServiceNames_Static() ) );
69 
70         if( xFactory.is() )
71         {
72             xFactory->acquire();
73             pRet = xFactory.get();
74         }
75     }
76 
77     return pRet;
78 }
79 
80 
81 }   // extern C
82 
83 
84 
85 
86 //------------------------------------------------------------------------
87 //
88 //  "normal" service implementation
89 //
90 //------------------------------------------------------------------------
91 
92 
93 ResMgr& AnalysisAddIn::GetResMgr( void ) THROWDEF_RTE
94 {
95     if( !pResMgr )
96     {
97         InitData();     // try to get resource manager
98 
99         if( !pResMgr )
100             THROW_RTE;
101     }
102 
103     return *pResMgr;
104 }
105 
106 
107 STRING AnalysisAddIn::GetDisplFuncStr( sal_uInt16 nFuncNum ) THROWDEF_RTE
108 {
109     return String( AnalysisRscStrLoader( RID_ANALYSIS_FUNCTION_NAMES, nFuncNum, GetResMgr() ).GetString() );
110 }
111 
112 
113 class AnalysisResourcePublisher : public Resource
114 {
115 public:
116                     AnalysisResourcePublisher( const AnalysisResId& rId ) : Resource( rId ) {}
117     sal_Bool            IsAvailableRes( const ResId& rId ) const { return Resource::IsAvailableRes( rId ); }
118     void            FreeResource() { Resource::FreeResource(); }
119 };
120 
121 
122 class AnalysisFuncRes : public Resource
123 {
124 public:
125     AnalysisFuncRes( ResId& rRes, ResMgr& rResMgr, sal_uInt16 nInd, STRING& rRet );
126 };
127 
128 
129 AnalysisFuncRes::AnalysisFuncRes( ResId& rRes, ResMgr& rResMgr, sal_uInt16 nInd, STRING& rRet ) : Resource( rRes )
130 {
131     rRet = String( AnalysisResId( nInd, rResMgr ) );
132 
133     FreeResource();
134 }
135 
136 
137 STRING AnalysisAddIn::GetFuncDescrStr( sal_uInt16 nResId, sal_uInt16 nStrIndex ) THROWDEF_RTE
138 {
139     STRING                      aRet;
140     AnalysisResourcePublisher   aResPubl( AnalysisResId( RID_ANALYSIS_FUNCTION_DESCRIPTIONS, GetResMgr() ) );
141     AnalysisResId               aRes( nResId, GetResMgr() );
142     aRes.SetRT( RSC_RESOURCE );
143     if( aResPubl.IsAvailableRes( aRes ) )
144     {
145         AnalysisFuncRes         aSubRes( aRes, GetResMgr(), nStrIndex, aRet );
146     }
147 
148     aResPubl.FreeResource();
149 
150     return aRet;
151 }
152 
153 
154 void AnalysisAddIn::InitData( void )
155 {
156     if( pResMgr )
157         delete pResMgr;
158 
159     OString             aModName( "analysis" );
160     pResMgr = ResMgr::CreateResMgr( ( const sal_Char* ) aModName,
161                                         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 
809 double SAL_CALL AnalysisAddIn::getRandbetween( double fMin, double fMax ) THROWDEF_RTE_IAE
810 {
811     fMin = ::rtl::math::round( fMin, 0, rtl_math_RoundingMode_Up );
812     fMax = ::rtl::math::round( fMax, 0, rtl_math_RoundingMode_Up );
813     if( fMin > fMax )
814         THROW_IAE;
815 
816     // fMax -> range
817     double fRet = fMax - fMin + 1.0;
818     fRet *= rand();
819     fRet /= (RAND_MAX + 1.0);
820     fRet += fMin;
821     fRet = floor( fRet );   // simple floor is sufficient here
822     RETURN_FINITE( fRet );
823 }
824 
825 
826 double SAL_CALL AnalysisAddIn::getGcd( constREFXPS& xOpt, const SEQSEQ( double )& aVLst, const SEQ( uno::Any )& aOptVLst ) THROWDEF_RTE_IAE
827 {
828     ScaDoubleListGT0 aValList;
829 
830     aValList.Append( aVLst );
831     aValList.Append( aAnyConv, xOpt, aOptVLst );
832 
833     if( aValList.Count() == 0 )
834         return 0.0;
835 
836     const double*   p = aValList.First();
837     double          f = *p;
838 
839     p = aValList.Next();
840 
841     while( p )
842     {
843         f = GetGcd( *p, f );
844         p = aValList.Next();
845     }
846 
847     RETURN_FINITE( f );
848 }
849 
850 
851 double SAL_CALL AnalysisAddIn::getLcm( constREFXPS& xOpt, const SEQSEQ( double )& aVLst, const SEQ( uno::Any )& aOptVLst ) THROWDEF_RTE_IAE
852 {
853     ScaDoubleListGE0 aValList;
854 
855     aValList.Append( aVLst );
856     aValList.Append( aAnyConv, xOpt, aOptVLst );
857 
858     if( aValList.Count() == 0 )
859         return 0.0;
860 
861     const double*   p = aValList.First();
862     double          f = *p;
863 
864     if( f == 0.0 )
865         return f;
866 
867     p = aValList.Next();
868 
869     while( p )
870     {
871         double      fTmp = *p;
872         if( f == 0.0 )
873             return f;
874         else
875             f = fTmp * f / GetGcd( fTmp, f );
876         p = aValList.Next();
877     }
878 
879     RETURN_FINITE( f );
880 }
881 
882 
883 double SAL_CALL AnalysisAddIn::getBesseli( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE
884 {
885     double fRet = sca::analysis::BesselI( fNum, nOrder );
886     RETURN_FINITE( fRet );
887 }
888 
889 
890 double SAL_CALL AnalysisAddIn::getBesselj( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE
891 {
892     double fRet = sca::analysis::BesselJ( fNum, nOrder );
893     RETURN_FINITE( fRet );
894 }
895 
896 
897 double SAL_CALL AnalysisAddIn::getBesselk( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE
898 {
899     if( nOrder < 0 || fNum <= 0.0 )
900         THROW_IAE;
901 
902     double fRet = sca::analysis::BesselK( fNum, nOrder );
903     RETURN_FINITE( fRet );
904 }
905 
906 
907 double SAL_CALL AnalysisAddIn::getBessely( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE
908 {
909     if( nOrder < 0 || fNum <= 0.0 )
910         THROW_IAE;
911 
912 //  return yn( nOrder, fNum );
913     double fRet = sca::analysis::BesselY( fNum, nOrder );
914     RETURN_FINITE( fRet );
915 }
916 
917 
918 const double    SCA_MAX2        = 511.0;            // min. val for binary numbers (9 bits + sign)
919 const double    SCA_MIN2        = -SCA_MAX2-1.0;    // min. val for binary numbers (9 bits + sign)
920 const double    SCA_MAX8        = 536870911.0;      // max. val for octal numbers (29 bits + sign)
921 const double    SCA_MIN8        = -SCA_MAX8-1.0;    // min. val for octal numbers (29 bits + sign)
922 const double    SCA_MAX16       = 549755813888.0;   // max. val for hexadecimal numbers (39 bits + sign)
923 const double    SCA_MIN16       = -SCA_MAX16-1.0;   // min. val for hexadecimal numbers (39 bits + sign)
924 const sal_Int32 SCA_MAXPLACES   = 10;               // max. number of places
925 
926 
927 STRING SAL_CALL AnalysisAddIn::getBin2Oct( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
928 {
929     double fVal = ConvertToDec( aNum, 2, SCA_MAXPLACES );
930     sal_Int32 nPlaces = 0;
931     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
932     return ConvertFromDec( fVal, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
933 }
934 
935 
936 double SAL_CALL AnalysisAddIn::getBin2Dec( const STRING& aNum ) THROWDEF_RTE_IAE
937 {
938     double fRet = ConvertToDec( aNum, 2, SCA_MAXPLACES );
939     RETURN_FINITE( fRet );
940 }
941 
942 
943 STRING SAL_CALL AnalysisAddIn::getBin2Hex( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
944 {
945     double fVal = ConvertToDec( aNum, 2, SCA_MAXPLACES );
946     sal_Int32 nPlaces = 0;
947     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
948     return ConvertFromDec( fVal, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
949 }
950 
951 
952 STRING SAL_CALL AnalysisAddIn::getOct2Bin( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
953 {
954     double fVal = ConvertToDec( aNum, 8, SCA_MAXPLACES );
955     sal_Int32 nPlaces = 0;
956     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
957     return ConvertFromDec( fVal, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
958 }
959 
960 
961 double SAL_CALL AnalysisAddIn::getOct2Dec( const STRING& aNum ) THROWDEF_RTE_IAE
962 {
963     double fRet = ConvertToDec( aNum, 8, SCA_MAXPLACES );
964     RETURN_FINITE( fRet );
965 }
966 
967 
968 STRING SAL_CALL AnalysisAddIn::getOct2Hex( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
969 {
970     double fVal = ConvertToDec( aNum, 8, SCA_MAXPLACES );
971     sal_Int32 nPlaces = 0;
972     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
973     return ConvertFromDec( fVal, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
974 }
975 
976 
977 STRING SAL_CALL AnalysisAddIn::getDec2Bin( constREFXPS& xOpt, sal_Int32 nNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
978 {
979     sal_Int32 nPlaces = 0;
980     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
981     return ConvertFromDec( nNum, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
982 }
983 
984 
985 STRING SAL_CALL AnalysisAddIn::getDec2Oct( constREFXPS& xOpt, sal_Int32 nNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
986 {
987     sal_Int32 nPlaces = 0;
988     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
989     return ConvertFromDec( nNum, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
990 }
991 
992 
993 STRING SAL_CALL AnalysisAddIn::getDec2Hex( constREFXPS& xOpt, double fNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
994 {
995     sal_Int32 nPlaces = 0;
996     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
997     return ConvertFromDec( fNum, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
998 }
999 
1000 
1001 STRING SAL_CALL AnalysisAddIn::getHex2Bin( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
1002 {
1003     double fVal = ConvertToDec( aNum, 16, SCA_MAXPLACES );
1004     sal_Int32 nPlaces = 0;
1005     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
1006     return ConvertFromDec( fVal, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
1007 }
1008 
1009 
1010 double SAL_CALL AnalysisAddIn::getHex2Dec( const STRING& aNum ) THROWDEF_RTE_IAE
1011 {
1012     double fRet = ConvertToDec( aNum, 16, SCA_MAXPLACES );
1013     RETURN_FINITE( fRet );
1014 }
1015 
1016 
1017 STRING SAL_CALL AnalysisAddIn::getHex2Oct( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
1018 {
1019     double fVal = ConvertToDec( aNum, 16, SCA_MAXPLACES );
1020     sal_Int32 nPlaces = 0;
1021     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
1022     return ConvertFromDec( fVal, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
1023 }
1024 
1025 
1026 sal_Int32 SAL_CALL AnalysisAddIn::getDelta( constREFXPS& xOpt, double fNum1, const ANY& rNum2 ) THROWDEF_RTE_IAE
1027 {
1028     return fNum1 == aAnyConv.getDouble( xOpt, rNum2, 0.0 );
1029 }
1030 
1031 
1032 double SAL_CALL AnalysisAddIn::getErf( constREFXPS& xOpt, double fLL, const ANY& rUL ) THROWDEF_RTE_IAE
1033 {
1034     double fUL, fRet;
1035     sal_Bool bContainsValue = aAnyConv.getDouble( fUL, xOpt, rUL );
1036 
1037     fRet = bContainsValue ? (Erf( fUL ) - Erf( fLL )) : Erf( fLL );
1038     RETURN_FINITE( fRet );
1039 }
1040 
1041 
1042 double SAL_CALL AnalysisAddIn::getErfc( double f ) THROWDEF_RTE_IAE
1043 {
1044     double fRet = Erfc( f );
1045     RETURN_FINITE( fRet );
1046 }
1047 
1048 
1049 sal_Int32 SAL_CALL AnalysisAddIn::getGestep( constREFXPS& xOpt, double fNum, const ANY& rStep ) THROWDEF_RTE_IAE
1050 {
1051     return fNum >= aAnyConv.getDouble( xOpt, rStep, 0.0 );
1052 }
1053 
1054 
1055 double SAL_CALL AnalysisAddIn::getFactdouble( sal_Int32 nNum ) THROWDEF_RTE_IAE
1056 {
1057     double fRet = FactDouble( nNum );
1058     RETURN_FINITE( fRet );
1059 }
1060 
1061 
1062 double SAL_CALL AnalysisAddIn::getImabs( const STRING& aNum ) THROWDEF_RTE_IAE
1063 {
1064     double fRet = Complex( aNum ).Abs();
1065     RETURN_FINITE( fRet );
1066 }
1067 
1068 
1069 double SAL_CALL AnalysisAddIn::getImaginary( const STRING& aNum ) THROWDEF_RTE_IAE
1070 {
1071     double fRet = Complex( aNum ).Imag();
1072     RETURN_FINITE( fRet );
1073 }
1074 
1075 
1076 STRING SAL_CALL AnalysisAddIn::getImpower( const STRING& aNum, double f ) THROWDEF_RTE_IAE
1077 {
1078     Complex     z( aNum );
1079 
1080     z.Power( f );
1081 
1082     return z.GetString();
1083 }
1084 
1085 
1086 double SAL_CALL AnalysisAddIn::getImargument( const STRING& aNum ) THROWDEF_RTE_IAE
1087 {
1088     double fRet = Complex( aNum ).Arg();
1089     RETURN_FINITE( fRet );
1090 }
1091 
1092 
1093 STRING SAL_CALL AnalysisAddIn::getImcos( const STRING& aNum ) THROWDEF_RTE_IAE
1094 {
1095     Complex     z( aNum );
1096 
1097     z.Cos();
1098 
1099     return z.GetString();
1100 }
1101 
1102 
1103 STRING SAL_CALL AnalysisAddIn::getImdiv( const STRING& aDivid, const STRING& aDivis ) THROWDEF_RTE_IAE
1104 {
1105     Complex     z( aDivid );
1106 
1107     z.Div( Complex( aDivis ) );
1108 
1109     return z.GetString();
1110 }
1111 
1112 
1113 STRING SAL_CALL AnalysisAddIn::getImexp( const STRING& aNum ) THROWDEF_RTE_IAE
1114 {
1115     Complex     z( aNum );
1116 
1117     z.Exp();
1118 
1119     return z.GetString();
1120 }
1121 
1122 
1123 STRING SAL_CALL AnalysisAddIn::getImconjugate( const STRING& aNum ) THROWDEF_RTE_IAE
1124 {
1125     Complex     z( aNum );
1126 
1127     z.Conjugate();
1128 
1129     return z.GetString();
1130 }
1131 
1132 
1133 STRING SAL_CALL AnalysisAddIn::getImln( const STRING& aNum ) THROWDEF_RTE_IAE
1134 {
1135     Complex     z( aNum );
1136 
1137     z.Ln();
1138 
1139     return z.GetString();
1140 }
1141 
1142 
1143 STRING SAL_CALL AnalysisAddIn::getImlog10( const STRING& aNum ) THROWDEF_RTE_IAE
1144 {
1145     Complex     z( aNum );
1146 
1147     z.Log10();
1148 
1149     return z.GetString();
1150 }
1151 
1152 
1153 STRING SAL_CALL AnalysisAddIn::getImlog2( const STRING& aNum ) THROWDEF_RTE_IAE
1154 {
1155     Complex     z( aNum );
1156 
1157     z.Log2();
1158 
1159     return z.GetString();
1160 }
1161 
1162 
1163 STRING SAL_CALL AnalysisAddIn::getImproduct( constREFXPS&, const SEQSEQ( STRING )& aNum1, const SEQ( uno::Any )& aNL ) THROWDEF_RTE_IAE
1164 {
1165     ComplexList     z_list;
1166 
1167     z_list.Append( aNum1, AH_IgnoreEmpty );
1168     z_list.Append( aNL, AH_IgnoreEmpty );
1169 
1170     const Complex*  p = z_list.First();
1171 
1172     if( !p )
1173         return Complex( 0 ).GetString();
1174 
1175     Complex         z( *p );
1176 
1177     for( p = z_list.Next() ; p ; p = z_list.Next() )
1178         z.Mult( *p );
1179 
1180     return z.GetString();
1181 }
1182 
1183 
1184 double SAL_CALL AnalysisAddIn::getImreal( const STRING& aNum ) THROWDEF_RTE_IAE
1185 {
1186     double fRet = Complex( aNum ).Real();
1187     RETURN_FINITE( fRet );
1188 }
1189 
1190 
1191 STRING SAL_CALL AnalysisAddIn::getImsin( const STRING& aNum ) THROWDEF_RTE_IAE
1192 {
1193     Complex     z( aNum );
1194 
1195     z.Sin();
1196 
1197     return z.GetString();
1198 }
1199 
1200 
1201 STRING SAL_CALL AnalysisAddIn::getImsub( const STRING& aNum1, const STRING& aNum2 ) THROWDEF_RTE_IAE
1202 {
1203     Complex     z( aNum1 );
1204 
1205     z.Sub( Complex( aNum2 ) );
1206 
1207     return z.GetString();
1208 }
1209 
1210 
1211 STRING SAL_CALL AnalysisAddIn::getImsum( constREFXPS&, const SEQSEQ( STRING )& aNum1, const SEQ( CSS::uno::Any )& aFollowingPars ) THROWDEF_RTE_IAE
1212 {
1213     ComplexList     z_list;
1214 
1215     z_list.Append( aNum1, AH_IgnoreEmpty );
1216     z_list.Append( aFollowingPars, AH_IgnoreEmpty );
1217 
1218     const Complex*  p = z_list.First();
1219 
1220     if( !p )
1221         return Complex( 0 ).GetString();
1222 
1223     Complex         z( *p );
1224 
1225     for( p = z_list.Next() ; p ; p = z_list.Next() )
1226         z.Add( *p );
1227 
1228     return z.GetString();
1229 }
1230 
1231 
1232 STRING SAL_CALL AnalysisAddIn::getImsqrt( const STRING& aNum ) THROWDEF_RTE_IAE
1233 {
1234     Complex     z( aNum );
1235 
1236 //  z.Power( 0.5 );
1237     z.Sqrt();
1238 
1239     return z.GetString();
1240 }
1241 
1242 
1243 STRING SAL_CALL AnalysisAddIn::getComplex( double fR, double fI, const ANY& rSuff ) THROWDEF_RTE_IAE
1244 {
1245     sal_Bool    bi;
1246 
1247     switch( rSuff.getValueTypeClass() )
1248     {
1249         case uno::TypeClass_VOID:
1250             bi = sal_True;
1251             break;
1252         case uno::TypeClass_STRING:
1253             {
1254             const STRING*   pSuff = ( const STRING* ) rSuff.getValue();
1255             bi = pSuff->compareToAscii( "i" ) == 0 || pSuff->getLength() == 0;
1256             if( !bi && pSuff->compareToAscii( "j" ) != 0 )
1257                 THROW_IAE;
1258             }
1259             break;
1260         default:
1261             THROW_IAE;
1262     }
1263 
1264     return Complex( fR, fI, bi ? 'i' : 'j' ).GetString();
1265 }
1266 
1267 
1268 double SAL_CALL AnalysisAddIn::getConvert( double f, const STRING& aFU, const STRING& aTU ) THROWDEF_RTE_IAE
1269 {
1270     if( !pCDL )
1271         pCDL = new ConvertDataList();
1272 
1273     double fRet = pCDL->Convert( f, aFU, aTU );
1274     RETURN_FINITE( fRet );
1275 }
1276 
1277 
1278