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::getImtan( const STRING& aNum ) THROWDEF_RTE_IAE
1244 {
1245     Complex     z( aNum );
1246 
1247     z.Tan();
1248 
1249     return z.GetString();
1250 }
1251 
1252 
1253 STRING SAL_CALL AnalysisAddIn::getImsec( const STRING& aNum ) THROWDEF_RTE_IAE
1254 {
1255     Complex     z( aNum );
1256 
1257     z.Sec();
1258 
1259     return z.GetString();
1260 }
1261 
1262 
1263 STRING SAL_CALL AnalysisAddIn::getImcsc( const STRING& aNum ) THROWDEF_RTE_IAE
1264 {
1265     Complex     z( aNum );
1266 
1267     z.Csc();
1268 
1269     return z.GetString();
1270 }
1271 
1272 
1273 STRING SAL_CALL AnalysisAddIn::getImcot( const STRING& aNum ) THROWDEF_RTE_IAE
1274 {
1275     Complex     z( aNum );
1276 
1277     z.Cot();
1278 
1279     return z.GetString();
1280 }
1281 
1282 
1283 STRING SAL_CALL AnalysisAddIn::getImsinh( const STRING& aNum ) THROWDEF_RTE_IAE
1284 {
1285     Complex     z( aNum );
1286 
1287     z.Sinh();
1288 
1289     return z.GetString();
1290 }
1291 
1292 
1293 STRING SAL_CALL AnalysisAddIn::getImcosh( const STRING& aNum ) THROWDEF_RTE_IAE
1294 {
1295     Complex     z( aNum );
1296 
1297     z.Cosh();
1298 
1299     return z.GetString();
1300 }
1301 
1302 
1303 STRING SAL_CALL AnalysisAddIn::getImsech( const STRING& aNum ) THROWDEF_RTE_IAE
1304 {
1305     Complex     z( aNum );
1306 
1307     z.Sech();
1308 
1309     return z.GetString();
1310 }
1311 
1312 
1313 STRING SAL_CALL AnalysisAddIn::getImcsch( const STRING& aNum ) THROWDEF_RTE_IAE
1314 {
1315     Complex     z( aNum );
1316 
1317     z.Csch();
1318 
1319     return z.GetString();
1320 }
1321 
1322 
1323 STRING SAL_CALL AnalysisAddIn::getComplex( double fR, double fI, const ANY& rSuff ) THROWDEF_RTE_IAE
1324 {
1325 	sal_Bool	bi;
1326 
1327 	switch( rSuff.getValueTypeClass() )
1328 	{
1329 		case uno::TypeClass_VOID:
1330 			bi = sal_True;
1331 			break;
1332 		case uno::TypeClass_STRING:
1333 			{
1334 			const STRING*	pSuff = ( const STRING* ) rSuff.getValue();
1335 			bi = pSuff->compareToAscii( "i" ) == 0 || pSuff->getLength() == 0;
1336 			if( !bi && pSuff->compareToAscii( "j" ) != 0 )
1337 				THROW_IAE;
1338 			}
1339 			break;
1340 		default:
1341 			THROW_IAE;
1342 	}
1343 
1344 	return Complex( fR, fI, bi ? 'i' : 'j' ).GetString();
1345 }
1346 
1347 
1348 double SAL_CALL AnalysisAddIn::getConvert( double f, const STRING& aFU, const STRING& aTU ) THROWDEF_RTE_IAE
1349 {
1350 	if( !pCDL )
1351 		pCDL = new ConvertDataList();
1352 
1353     double fRet = pCDL->Convert( f, aFU, aTU );
1354     RETURN_FINITE( fRet );
1355 }
1356 
1357 
1358