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