1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include "analysisdefs.hxx"
21 #include "analysis.hxx"
22 #include "bessel.hxx"
23 #include <cppuhelper/factory.hxx>
24 #include <comphelper/processfactory.hxx>
25 #include <comphelper/random.hxx>
26 #include <cppuhelper/supportsservice.hxx>
27 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
28 #include <o3tl/any.hxx>
29 #include <rtl/math.hxx>
30 #include <sal/macros.h>
31 #include <unotools/resmgr.hxx>
32 #include <i18nlangtag/languagetag.hxx>
33 #include <algorithm>
34 #include <cmath>
35 #include <float.h>
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 ::com::sun::star;
42 using namespace sca::analysis;
43 using namespace std;
44
analysis_component_getFactory(const sal_Char * pImplName,void * pServiceManager,void *)45 extern "C" SAL_DLLPUBLIC_EXPORT void* analysis_component_getFactory(
46 const sal_Char* pImplName, void* pServiceManager, void* /*pRegistryKey*/ )
47 {
48 void* pRet = nullptr;
49
50 if( pServiceManager && OUString::createFromAscii( pImplName ) == AnalysisAddIn::getImplementationName_Static() )
51 {
52 uno::Reference< lang::XSingleServiceFactory > xFactory( cppu::createOneInstanceFactory(
53 static_cast< lang::XMultiServiceFactory* >( pServiceManager ),
54 AnalysisAddIn::getImplementationName_Static(),
55 AnalysisAddIn_CreateInstance,
56 AnalysisAddIn::getSupportedServiceNames_Static() ) );
57
58 if( xFactory.is() )
59 {
60 xFactory->acquire();
61 pRet = xFactory.get();
62 }
63 }
64
65 return pRet;
66 }
67
GetFuncDescrStr(const char ** pResId,sal_uInt16 nStrIndex)68 OUString AnalysisAddIn::GetFuncDescrStr(const char** pResId, sal_uInt16 nStrIndex)
69 {
70 return AnalysisResId(pResId[nStrIndex - 1]);
71 }
72
InitData()73 void AnalysisAddIn::InitData()
74 {
75 aResLocale = Translate::Create("sca", LanguageTag(aFuncLoc));
76
77 pFD.reset(new FuncDataList);
78 InitFuncDataList(*pFD);
79
80 pDefLocales.reset();
81 }
82
AnalysisAddIn(const uno::Reference<uno::XComponentContext> & xContext)83 AnalysisAddIn::AnalysisAddIn( const uno::Reference< uno::XComponentContext >& xContext ) :
84 aAnyConv( xContext )
85 {
86 }
87
~AnalysisAddIn()88 AnalysisAddIn::~AnalysisAddIn()
89 {
90 }
91
getDateMode(const uno::Reference<beans::XPropertySet> & xPropSet,const uno::Any & rAny)92 sal_Int32 AnalysisAddIn::getDateMode(
93 const uno::Reference< beans::XPropertySet >& xPropSet,
94 const uno::Any& rAny )
95 {
96 sal_Int32 nMode = aAnyConv.getInt32( xPropSet, rAny, 0 );
97 if( (nMode < 0) || (nMode > 4) )
98 throw lang::IllegalArgumentException();
99 return nMode;
100 }
101
102 #define MAXFACTDOUBLE 300
103
FactDouble(sal_Int32 nNum)104 double AnalysisAddIn::FactDouble( sal_Int32 nNum )
105 {
106 if( nNum < 0 || nNum > MAXFACTDOUBLE )
107 throw lang::IllegalArgumentException();
108
109 if( !pFactDoubles )
110 {
111 pFactDoubles.reset( new double[ MAXFACTDOUBLE + 1 ] );
112
113 pFactDoubles[ 0 ] = 1.0; // by default
114
115 double fOdd = 1.0;
116 double fEven = 2.0;
117
118 pFactDoubles[ 1 ] = fOdd;
119 pFactDoubles[ 2 ] = fEven;
120
121 bool bOdd = true;
122
123 for( sal_uInt16 nCnt = 3 ; nCnt <= MAXFACTDOUBLE ; nCnt++ )
124 {
125 if( bOdd )
126 {
127 fOdd *= nCnt;
128 pFactDoubles[ nCnt ] = fOdd;
129 }
130 else
131 {
132 fEven *= nCnt;
133 pFactDoubles[ nCnt ] = fEven;
134 }
135
136 bOdd = !bOdd;
137
138 }
139 }
140
141 return pFactDoubles[ nNum ];
142 }
143
getImplementationName_Static()144 OUString AnalysisAddIn::getImplementationName_Static()
145 {
146 return MY_IMPLNAME;
147 }
148
getSupportedServiceNames_Static()149 uno::Sequence< OUString > AnalysisAddIn::getSupportedServiceNames_Static()
150 {
151 return { ADDIN_SERVICE, MY_SERVICE };
152 }
153
AnalysisAddIn_CreateInstance(const uno::Reference<lang::XMultiServiceFactory> & xServiceFact)154 uno::Reference< uno::XInterface > AnalysisAddIn_CreateInstance(
155 const uno::Reference< lang::XMultiServiceFactory >& xServiceFact )
156 {
157 return static_cast<cppu::OWeakObject*>(new AnalysisAddIn( comphelper::getComponentContext(xServiceFact) ));
158 }
159
160 // XServiceName
getServiceName()161 OUString SAL_CALL AnalysisAddIn::getServiceName()
162 {
163 // name of specific AddIn service
164 return MY_SERVICE;
165 }
166
167 // XServiceInfo
getImplementationName()168 OUString SAL_CALL AnalysisAddIn::getImplementationName()
169 {
170 return getImplementationName_Static();
171 }
172
supportsService(const OUString & aName)173 sal_Bool SAL_CALL AnalysisAddIn::supportsService( const OUString& aName )
174 {
175 return cppu::supportsService(this, aName);
176 }
177
getSupportedServiceNames()178 uno::Sequence< OUString > SAL_CALL AnalysisAddIn::getSupportedServiceNames()
179 {
180 return getSupportedServiceNames_Static();
181 }
182
183 // XLocalizable
setLocale(const lang::Locale & eLocale)184 void SAL_CALL AnalysisAddIn::setLocale( const lang::Locale& eLocale )
185 {
186 aFuncLoc = eLocale;
187
188 InitData(); // change of locale invalidates resources!
189 }
190
getLocale()191 lang::Locale SAL_CALL AnalysisAddIn::getLocale()
192 {
193 return aFuncLoc;
194 }
195
196 // XAddIn
getProgrammaticFuntionName(const OUString &)197 OUString SAL_CALL AnalysisAddIn::getProgrammaticFuntionName( const OUString& )
198 {
199 // not used by calc
200 // (but should be implemented for other uses of the AddIn service)
201
202 return OUString();
203 }
204
getDisplayFunctionName(const OUString & aProgrammaticName)205 OUString SAL_CALL AnalysisAddIn::getDisplayFunctionName( const OUString& aProgrammaticName )
206 {
207 OUString aRet;
208
209 auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aProgrammaticName ) );
210 if( it != pFD->end() )
211 {
212 aRet = AnalysisResId(it->GetUINameID());
213 if( it->IsDouble() )
214 {
215 const OUString& rSuffix = it->GetSuffix();
216 if (!rSuffix.isEmpty())
217 aRet += rSuffix;
218 else
219 aRet += "_ADD";
220 }
221 }
222 else
223 {
224 aRet = "UNKNOWNFUNC_" + aProgrammaticName;
225 }
226
227 return aRet;
228 }
229
getFunctionDescription(const OUString & aProgrammaticName)230 OUString SAL_CALL AnalysisAddIn::getFunctionDescription( const OUString& aProgrammaticName )
231 {
232 OUString aRet;
233
234 auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aProgrammaticName ) );
235 if( it != pFD->end() )
236 aRet = GetFuncDescrStr( it->GetDescrID(), 1 );
237
238 return aRet;
239 }
240
getDisplayArgumentName(const OUString & aName,sal_Int32 nArg)241 OUString SAL_CALL AnalysisAddIn::getDisplayArgumentName( const OUString& aName, sal_Int32 nArg )
242 {
243 OUString aRet;
244
245 auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aName ) );
246 if( it != pFD->end() && nArg <= 0xFFFF )
247 {
248 sal_uInt16 nStr = it->GetStrIndex( sal_uInt16( nArg ) );
249 if( nStr )
250 aRet = GetFuncDescrStr( it->GetDescrID(), nStr );
251 else
252 aRet = "internal";
253 }
254
255 return aRet;
256 }
257
getArgumentDescription(const OUString & aName,sal_Int32 nArg)258 OUString SAL_CALL AnalysisAddIn::getArgumentDescription( const OUString& aName, sal_Int32 nArg )
259 {
260 OUString aRet;
261
262 auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aName ) );
263 if( it != pFD->end() && nArg <= 0xFFFF )
264 {
265 sal_uInt16 nStr = it->GetStrIndex( sal_uInt16( nArg ) );
266 if( nStr )
267 aRet = GetFuncDescrStr( it->GetDescrID(), nStr + 1 );
268 else
269 aRet = "for internal use only";
270 }
271
272 return aRet;
273 }
274
275 static const char pDefCatName[] = "Add-In";
276
getProgrammaticCategoryName(const OUString & aName)277 OUString SAL_CALL AnalysisAddIn::getProgrammaticCategoryName( const OUString& aName )
278 {
279 // return non-translated strings
280 // return OUString( "Add-In" );
281 auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aName ) );
282 OUString aRet;
283 if( it != pFD->end() )
284 {
285 switch( it->GetCategory() )
286 {
287 case FDCategory::DateTime: aRet = "Date&Time"; break;
288 case FDCategory::Finance: aRet = "Financial"; break;
289 case FDCategory::Inf: aRet = "Information"; break;
290 case FDCategory::Math: aRet = "Mathematical"; break;
291 case FDCategory::Tech: aRet = "Technical"; break;
292 }
293 }
294 else
295 aRet = pDefCatName;
296
297 return aRet;
298 }
299
getDisplayCategoryName(const OUString & aProgrammaticFunctionName)300 OUString SAL_CALL AnalysisAddIn::getDisplayCategoryName( const OUString& aProgrammaticFunctionName )
301 {
302 // return translated strings, not used for predefined categories
303 auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aProgrammaticFunctionName ) );
304 OUString aRet;
305 if( it != pFD->end() )
306 {
307 switch( it->GetCategory() )
308 {
309 case FDCategory::DateTime: aRet = "Date&Time"; break;
310 case FDCategory::Finance: aRet = "Financial"; break;
311 case FDCategory::Inf: aRet = "Information"; break;
312 case FDCategory::Math: aRet = "Mathematical"; break;
313 case FDCategory::Tech: aRet = "Technical"; break;
314 }
315 }
316 else
317 aRet = pDefCatName;
318
319 return aRet;
320 }
321
322 static const sal_Char* pLang[] = { "de", "en" };
323 static const sal_Char* pCoun[] = { "DE", "US" };
324 static const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS(pLang);
325
InitDefLocales()326 void AnalysisAddIn::InitDefLocales()
327 {
328 pDefLocales.reset( new lang::Locale[ nNumOfLoc ] );
329
330 for( sal_uInt32 n = 0 ; n < nNumOfLoc ; n++ )
331 {
332 pDefLocales[ n ].Language = OUString::createFromAscii( pLang[ n ] );
333 pDefLocales[ n ].Country = OUString::createFromAscii( pCoun[ n ] );
334 }
335 }
336
GetLocale(sal_uInt32 nInd)337 inline const lang::Locale& AnalysisAddIn::GetLocale( sal_uInt32 nInd )
338 {
339 if( !pDefLocales )
340 InitDefLocales();
341
342 if( nInd < sizeof( pLang ) )
343 return pDefLocales[ nInd ];
344 else
345 return aFuncLoc;
346 }
347
getCompatibilityNames(const OUString & aProgrammaticName)348 uno::Sequence< sheet::LocalizedName > SAL_CALL AnalysisAddIn::getCompatibilityNames( const OUString& aProgrammaticName )
349 {
350 auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aProgrammaticName ) );
351 if( it == pFD->end() )
352 return uno::Sequence< sheet::LocalizedName >( 0 );
353
354 const std::vector<OUString>& r = it->GetCompNameList();
355 sal_uInt32 nCount = r.size();
356
357 uno::Sequence< sheet::LocalizedName > aRet( nCount );
358
359 sheet::LocalizedName* pArray = aRet.getArray();
360
361 for( sal_uInt32 n = 0 ; n < nCount ; n++ )
362 {
363 pArray[ n ] = sheet::LocalizedName( GetLocale( n ), r[n] );
364 }
365
366 return aRet;
367 }
368
369 // XAnalysis
370 /** Workday */
getWorkday(const uno::Reference<beans::XPropertySet> & xOptions,sal_Int32 nDate,sal_Int32 nDays,const uno::Any & aHDay)371 sal_Int32 SAL_CALL AnalysisAddIn::getWorkday( const uno::Reference< beans::XPropertySet >& xOptions,
372 sal_Int32 nDate, sal_Int32 nDays, const uno::Any& aHDay )
373 {
374 if( !nDays )
375 return nDate;
376
377 sal_Int32 nNullDate = GetNullDate( xOptions );
378
379 SortedIndividualInt32List aSrtLst;
380
381 aSrtLst.InsertHolidayList( aAnyConv, xOptions, aHDay, nNullDate );
382
383 sal_Int32 nActDate = nDate + nNullDate;
384
385 if( nDays > 0 )
386 {
387 if( GetDayOfWeek( nActDate ) == 5 )
388 // when starting on Saturday, assuming we're starting on Sunday to get the jump over the weekend
389 nActDate++;
390
391 while( nDays )
392 {
393 nActDate++;
394
395 if( GetDayOfWeek( nActDate ) < 5 )
396 {
397 if( !aSrtLst.Find( nActDate ) )
398 nDays--;
399 }
400 else
401 nActDate++; // jump over weekend
402 }
403 }
404 else
405 {
406 if( GetDayOfWeek( nActDate ) == 6 )
407 // when starting on Sunday, assuming we're starting on Saturday to get the jump over the weekend
408 nActDate--;
409
410 while( nDays )
411 {
412 nActDate--;
413
414 if( GetDayOfWeek( nActDate ) < 5 )
415 {
416 if( !aSrtLst.Find( nActDate ) )
417 nDays++;
418 }
419 else
420 nActDate--; // jump over weekend
421 }
422 }
423
424 return nActDate - nNullDate;
425 }
426
427 /** Yearfrac */
getYearfrac(const uno::Reference<beans::XPropertySet> & xOpt,sal_Int32 nStartDate,sal_Int32 nEndDate,const uno::Any & rMode)428 double SAL_CALL AnalysisAddIn::getYearfrac( const uno::Reference< beans::XPropertySet >& xOpt,
429 sal_Int32 nStartDate, sal_Int32 nEndDate, const uno::Any& rMode )
430 {
431 double fRet = GetYearFrac( xOpt, nStartDate, nEndDate, getDateMode( xOpt, rMode ) );
432 RETURN_FINITE( fRet );
433 }
434
getEdate(const uno::Reference<beans::XPropertySet> & xOpt,sal_Int32 nStartDate,sal_Int32 nMonths)435 sal_Int32 SAL_CALL AnalysisAddIn::getEdate( const uno::Reference< beans::XPropertySet >& xOpt, sal_Int32 nStartDate, sal_Int32 nMonths )
436 {
437 sal_Int32 nNullDate = GetNullDate( xOpt );
438 ScaDate aDate( nNullDate, nStartDate, 5 );
439 aDate.addMonths( nMonths );
440 return aDate.getDate( nNullDate );
441 }
442
getWeeknum(const uno::Reference<beans::XPropertySet> & xOpt,sal_Int32 nDate,sal_Int32 nMode)443 sal_Int32 SAL_CALL AnalysisAddIn::getWeeknum( const uno::Reference< beans::XPropertySet >& xOpt, sal_Int32 nDate, sal_Int32 nMode )
444 {
445 nDate += GetNullDate( xOpt );
446
447 sal_uInt16 nDay, nMonth, nYear;
448 DaysToDate( nDate, nDay, nMonth, nYear );
449
450 sal_Int32 nFirstInYear = DateToDays( 1, 1, nYear );
451 sal_uInt16 nFirstDayInYear = GetDayOfWeek( nFirstInYear );
452
453 return ( nDate - nFirstInYear + ( ( nMode == 1 )? ( nFirstDayInYear + 1 ) % 7 : nFirstDayInYear ) ) / 7 + 1;
454 }
455
getEomonth(const uno::Reference<beans::XPropertySet> & xOpt,sal_Int32 nDate,sal_Int32 nMonths)456 sal_Int32 SAL_CALL AnalysisAddIn::getEomonth( const uno::Reference< beans::XPropertySet >& xOpt, sal_Int32 nDate, sal_Int32 nMonths )
457 {
458 sal_Int32 nNullDate = GetNullDate( xOpt );
459 nDate += nNullDate;
460 sal_uInt16 nDay, nMonth, nYear;
461 DaysToDate( nDate, nDay, nMonth, nYear );
462
463 sal_Int32 nNewMonth = nMonth + nMonths;
464
465 if( nNewMonth > 12 )
466 {
467 nYear = sal::static_int_cast<sal_uInt16>( nYear + ( nNewMonth / 12 ) );
468 nNewMonth %= 12;
469 }
470 else if( nNewMonth < 1 )
471 {
472 nNewMonth = -nNewMonth;
473 nYear = sal::static_int_cast<sal_uInt16>( nYear - ( nNewMonth / 12 ) );
474 nYear--;
475 nNewMonth %= 12;
476 nNewMonth = 12 - nNewMonth;
477 }
478
479 return DateToDays( DaysInMonth( sal_uInt16( nNewMonth ), nYear ), sal_uInt16( nNewMonth ), nYear ) - nNullDate;
480 }
481
getNetworkdays(const uno::Reference<beans::XPropertySet> & xOpt,sal_Int32 nStartDate,sal_Int32 nEndDate,const uno::Any & aHDay)482 sal_Int32 SAL_CALL AnalysisAddIn::getNetworkdays( const uno::Reference< beans::XPropertySet >& xOpt,
483 sal_Int32 nStartDate, sal_Int32 nEndDate, const uno::Any& aHDay )
484 {
485 sal_Int32 nNullDate = GetNullDate( xOpt );
486
487 SortedIndividualInt32List aSrtLst;
488
489 aSrtLst.InsertHolidayList( aAnyConv, xOpt, aHDay, nNullDate );
490
491 sal_Int32 nActDate = nStartDate + nNullDate;
492 sal_Int32 nStopDate = nEndDate + nNullDate;
493 sal_Int32 nCnt = 0;
494
495 if( nActDate <= nStopDate )
496 {
497 while( nActDate <= nStopDate )
498 {
499 if( GetDayOfWeek( nActDate ) < 5 && !aSrtLst.Find( nActDate ) )
500 nCnt++;
501
502 nActDate++;
503 }
504 }
505 else
506 {
507 while( nActDate >= nStopDate )
508 {
509 if( GetDayOfWeek( nActDate ) < 5 && !aSrtLst.Find( nActDate ) )
510 nCnt--;
511
512 nActDate--;
513 }
514 }
515
516 return nCnt;
517 }
518
getIseven(sal_Int32 nVal)519 sal_Int32 SAL_CALL AnalysisAddIn::getIseven( sal_Int32 nVal )
520 {
521 return ( nVal & 0x00000001 )? 0 : 1;
522 }
523
getIsodd(sal_Int32 nVal)524 sal_Int32 SAL_CALL AnalysisAddIn::getIsodd( sal_Int32 nVal )
525 {
526 return ( nVal & 0x00000001 )? 1 : 0;
527 }
528
529 double SAL_CALL
getMultinomial(const uno::Reference<beans::XPropertySet> & xOpt,const uno::Sequence<uno::Sequence<sal_Int32>> & aVLst,const uno::Sequence<uno::Any> & aOptVLst)530 AnalysisAddIn::getMultinomial( const uno::Reference< beans::XPropertySet >& xOpt, const uno::Sequence< uno::Sequence< sal_Int32 > >& aVLst,
531 const uno::Sequence< uno::Any >& aOptVLst )
532 {
533 ScaDoubleListGE0 aValList;
534
535 aValList.Append( aVLst );
536 aValList.Append( aAnyConv, xOpt, aOptVLst );
537
538 if( aValList.Count() == 0 )
539 return 0.0;
540
541 double nZ = 0;
542 double fRet = 1.0;
543
544 for( sal_uInt32 i = 0; i < aValList.Count(); ++i )
545 {
546 const double d = aValList.Get(i);
547 double n = (d >= 0.0) ? rtl::math::approxFloor( d ) : rtl::math::approxCeil( d );
548 if ( n < 0.0 )
549 throw lang::IllegalArgumentException();
550
551 if( n > 0.0 )
552 {
553 nZ += n;
554 fRet *= BinomialCoefficient(nZ, n);
555 }
556 }
557 RETURN_FINITE( fRet );
558 }
559
getSeriessum(double fX,double fN,double fM,const uno::Sequence<uno::Sequence<double>> & aCoeffList)560 double SAL_CALL AnalysisAddIn::getSeriessum( double fX, double fN, double fM, const uno::Sequence< uno::Sequence< double > >& aCoeffList )
561 {
562 double fRet = 0.0;
563
564 // #i32269# 0^0 is undefined, Excel returns #NUM! error
565 if( fX == 0.0 && fN == 0 )
566 throw uno::RuntimeException();
567
568 if( fX != 0.0 )
569 {
570 for( const uno::Sequence< double >& rList : aCoeffList )
571 {
572 for( const double fCoef : rList )
573 {
574 fRet += fCoef * pow( fX, fN );
575
576 fN += fM;
577 }
578 }
579 }
580
581 RETURN_FINITE( fRet );
582 }
583
getQuotient(double fNum,double fDenom)584 double SAL_CALL AnalysisAddIn::getQuotient( double fNum, double fDenom )
585 {
586 double fRet;
587 if( (fNum < 0) != (fDenom < 0) )
588 fRet = ::rtl::math::approxCeil( fNum / fDenom );
589 else
590 fRet = ::rtl::math::approxFloor( fNum / fDenom );
591 RETURN_FINITE( fRet );
592 }
593
getMround(double fNum,double fMult)594 double SAL_CALL AnalysisAddIn::getMround( double fNum, double fMult )
595 {
596 if( fMult == 0.0 )
597 return fMult;
598
599 double fRet = fMult * ::rtl::math::round( fNum / fMult );
600 RETURN_FINITE( fRet );
601 }
602
getSqrtpi(double fNum)603 double SAL_CALL AnalysisAddIn::getSqrtpi( double fNum )
604 {
605 double fRet = sqrt( fNum * PI );
606 RETURN_FINITE( fRet );
607 }
608
getRandbetween(double fMin,double fMax)609 double SAL_CALL AnalysisAddIn::getRandbetween( double fMin, double fMax )
610 {
611 fMin = ::rtl::math::round( fMin, 0, rtl_math_RoundingMode_Up );
612 fMax = ::rtl::math::round( fMax, 0, rtl_math_RoundingMode_Up );
613 if( fMin > fMax )
614 throw lang::IllegalArgumentException();
615
616 double fRet = floor(comphelper::rng::uniform_real_distribution(fMin, nextafter(fMax+1, -DBL_MAX)));
617 RETURN_FINITE( fRet );
618 }
619
getGcd(const uno::Reference<beans::XPropertySet> & xOpt,const uno::Sequence<uno::Sequence<double>> & aVLst,const uno::Sequence<uno::Any> & aOptVLst)620 double SAL_CALL AnalysisAddIn::getGcd( const uno::Reference< beans::XPropertySet >& xOpt, const uno::Sequence< uno::Sequence< double > >& aVLst, const uno::Sequence< uno::Any >& aOptVLst )
621 {
622 ScaDoubleListGT0 aValList;
623
624 aValList.Append( aVLst );
625 aValList.Append( aAnyConv, xOpt, aOptVLst );
626
627 if( aValList.Count() == 0 )
628 return 0.0;
629
630 double f = aValList.Get(0);
631 for( sal_uInt32 i = 1; i < aValList.Count(); ++i )
632 {
633 f = GetGcd( aValList.Get(i), f );
634 }
635
636 RETURN_FINITE( f );
637 }
638
getLcm(const uno::Reference<beans::XPropertySet> & xOpt,const uno::Sequence<uno::Sequence<double>> & aVLst,const uno::Sequence<uno::Any> & aOptVLst)639 double SAL_CALL AnalysisAddIn::getLcm( const uno::Reference< beans::XPropertySet >& xOpt, const uno::Sequence< uno::Sequence< double > >& aVLst, const uno::Sequence< uno::Any >& aOptVLst )
640 {
641 ScaDoubleListGE0 aValList;
642
643 aValList.Append( aVLst );
644 aValList.Append( aAnyConv, xOpt, aOptVLst );
645
646 if( aValList.Count() == 0 )
647 return 0.0;
648
649 double f = rtl::math::approxFloor( aValList.Get(0) );
650 if( f < 0.0 )
651 throw lang::IllegalArgumentException();
652
653 if( f == 0.0 )
654 return f;
655
656 for( sal_uInt32 i = 1; i < aValList.Count(); ++i )
657 {
658 double fTmp = rtl::math::approxFloor( aValList.Get(i) );
659 if( fTmp < 0.0 )
660 throw lang::IllegalArgumentException();
661
662 f = fTmp * f / GetGcd( fTmp, f );
663 if( f == 0.0 )
664 return f;
665 }
666
667 RETURN_FINITE( f );
668 }
669
getBesseli(double fNum,sal_Int32 nOrder)670 double SAL_CALL AnalysisAddIn::getBesseli( double fNum, sal_Int32 nOrder )
671 {
672 double fRet = sca::analysis::BesselI( fNum, nOrder );
673 RETURN_FINITE( fRet );
674 }
675
getBesselj(double fNum,sal_Int32 nOrder)676 double SAL_CALL AnalysisAddIn::getBesselj( double fNum, sal_Int32 nOrder )
677 {
678 double fRet = sca::analysis::BesselJ( fNum, nOrder );
679 RETURN_FINITE( fRet );
680 }
681
getBesselk(double fNum,sal_Int32 nOrder)682 double SAL_CALL AnalysisAddIn::getBesselk( double fNum, sal_Int32 nOrder )
683 {
684 if( nOrder < 0 || fNum <= 0.0 )
685 throw lang::IllegalArgumentException();
686
687 double fRet = sca::analysis::BesselK( fNum, nOrder );
688 RETURN_FINITE( fRet );
689 }
690
getBessely(double fNum,sal_Int32 nOrder)691 double SAL_CALL AnalysisAddIn::getBessely( double fNum, sal_Int32 nOrder )
692 {
693 if( nOrder < 0 || fNum <= 0.0 )
694 throw lang::IllegalArgumentException();
695
696 double fRet = sca::analysis::BesselY( fNum, nOrder );
697 RETURN_FINITE( fRet );
698 }
699
700 const double SCA_MAX2 = 511.0; // min. val for binary numbers (9 bits + sign)
701 const double SCA_MIN2 = -SCA_MAX2-1.0; // min. val for binary numbers (9 bits + sign)
702 const double SCA_MAX8 = 536870911.0; // max. val for octal numbers (29 bits + sign)
703 const double SCA_MIN8 = -SCA_MAX8-1.0; // min. val for octal numbers (29 bits + sign)
704 const double SCA_MAX16 = 549755813888.0; // max. val for hexadecimal numbers (39 bits + sign)
705 const double SCA_MIN16 = -SCA_MAX16-1.0; // min. val for hexadecimal numbers (39 bits + sign)
706 const sal_Int32 SCA_MAXPLACES = 10; // max. number of places
707
getBin2Oct(const uno::Reference<beans::XPropertySet> & xOpt,const OUString & aNum,const uno::Any & rPlaces)708 OUString SAL_CALL AnalysisAddIn::getBin2Oct( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
709 {
710 double fVal = ConvertToDec( aNum, 2, SCA_MAXPLACES );
711 sal_Int32 nPlaces = 0;
712 bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
713 return ConvertFromDec( fVal, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
714 }
715
getBin2Dec(const OUString & aNum)716 double SAL_CALL AnalysisAddIn::getBin2Dec( const OUString& aNum )
717 {
718 double fRet = ConvertToDec( aNum, 2, SCA_MAXPLACES );
719 RETURN_FINITE( fRet );
720 }
721
getBin2Hex(const uno::Reference<beans::XPropertySet> & xOpt,const OUString & aNum,const uno::Any & rPlaces)722 OUString SAL_CALL AnalysisAddIn::getBin2Hex( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
723 {
724 double fVal = ConvertToDec( aNum, 2, SCA_MAXPLACES );
725 sal_Int32 nPlaces = 0;
726 bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
727 return ConvertFromDec( fVal, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
728 }
729
getOct2Bin(const uno::Reference<beans::XPropertySet> & xOpt,const OUString & aNum,const uno::Any & rPlaces)730 OUString SAL_CALL AnalysisAddIn::getOct2Bin( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
731 {
732 double fVal = ConvertToDec( aNum, 8, SCA_MAXPLACES );
733 sal_Int32 nPlaces = 0;
734 bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
735 return ConvertFromDec( fVal, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
736 }
737
getOct2Dec(const OUString & aNum)738 double SAL_CALL AnalysisAddIn::getOct2Dec( const OUString& aNum )
739 {
740 double fRet = ConvertToDec( aNum, 8, SCA_MAXPLACES );
741 RETURN_FINITE( fRet );
742 }
743
getOct2Hex(const uno::Reference<beans::XPropertySet> & xOpt,const OUString & aNum,const uno::Any & rPlaces)744 OUString SAL_CALL AnalysisAddIn::getOct2Hex( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
745 {
746 double fVal = ConvertToDec( aNum, 8, SCA_MAXPLACES );
747 sal_Int32 nPlaces = 0;
748 bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
749 return ConvertFromDec( fVal, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
750 }
751
getDec2Bin(const uno::Reference<beans::XPropertySet> & xOpt,sal_Int32 nNum,const uno::Any & rPlaces)752 OUString SAL_CALL AnalysisAddIn::getDec2Bin( const uno::Reference< beans::XPropertySet >& xOpt, sal_Int32 nNum, const uno::Any& rPlaces )
753 {
754 sal_Int32 nPlaces = 0;
755 bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
756 return ConvertFromDec( nNum, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
757 }
758
getDec2Oct(const uno::Reference<beans::XPropertySet> & xOpt,sal_Int32 nNum,const uno::Any & rPlaces)759 OUString SAL_CALL AnalysisAddIn::getDec2Oct( const uno::Reference< beans::XPropertySet >& xOpt, sal_Int32 nNum, const uno::Any& rPlaces )
760 {
761 sal_Int32 nPlaces = 0;
762 bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
763 return ConvertFromDec( nNum, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
764 }
765
getDec2Hex(const uno::Reference<beans::XPropertySet> & xOpt,double fNum,const uno::Any & rPlaces)766 OUString SAL_CALL AnalysisAddIn::getDec2Hex( const uno::Reference< beans::XPropertySet >& xOpt, double fNum, const uno::Any& rPlaces )
767 {
768 sal_Int32 nPlaces = 0;
769 bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
770 return ConvertFromDec( fNum, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
771 }
772
getHex2Bin(const uno::Reference<beans::XPropertySet> & xOpt,const OUString & aNum,const uno::Any & rPlaces)773 OUString SAL_CALL AnalysisAddIn::getHex2Bin( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
774 {
775 double fVal = ConvertToDec( aNum, 16, SCA_MAXPLACES );
776 sal_Int32 nPlaces = 0;
777 bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
778 return ConvertFromDec( fVal, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
779 }
780
getHex2Dec(const OUString & aNum)781 double SAL_CALL AnalysisAddIn::getHex2Dec( const OUString& aNum )
782 {
783 double fRet = ConvertToDec( aNum, 16, SCA_MAXPLACES );
784 RETURN_FINITE( fRet );
785 }
786
getHex2Oct(const uno::Reference<beans::XPropertySet> & xOpt,const OUString & aNum,const uno::Any & rPlaces)787 OUString SAL_CALL AnalysisAddIn::getHex2Oct( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
788 {
789 double fVal = ConvertToDec( aNum, 16, SCA_MAXPLACES );
790 sal_Int32 nPlaces = 0;
791 bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
792 return ConvertFromDec( fVal, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
793 }
794
getDelta(const uno::Reference<beans::XPropertySet> & xOpt,double fNum1,const uno::Any & rNum2)795 sal_Int32 SAL_CALL AnalysisAddIn::getDelta( const uno::Reference< beans::XPropertySet >& xOpt, double fNum1, const uno::Any& rNum2 )
796 {
797 return sal_Int32(fNum1 == aAnyConv.getDouble( xOpt, rNum2, 0.0 ));
798 }
799
getErf(const uno::Reference<beans::XPropertySet> & xOpt,double fLL,const uno::Any & rUL)800 double SAL_CALL AnalysisAddIn::getErf( const uno::Reference< beans::XPropertySet >& xOpt, double fLL, const uno::Any& rUL )
801 {
802 double fUL, fRet;
803 bool bContainsValue = aAnyConv.getDouble( fUL, xOpt, rUL );
804
805 fRet = bContainsValue ? (Erf( fUL ) - Erf( fLL )) : Erf( fLL );
806 RETURN_FINITE( fRet );
807 }
808
getErfc(double f)809 double SAL_CALL AnalysisAddIn::getErfc( double f )
810 {
811 double fRet = Erfc( f );
812 RETURN_FINITE( fRet );
813 }
814
getGestep(const uno::Reference<beans::XPropertySet> & xOpt,double fNum,const uno::Any & rStep)815 sal_Int32 SAL_CALL AnalysisAddIn::getGestep( const uno::Reference< beans::XPropertySet >& xOpt, double fNum, const uno::Any& rStep )
816 {
817 return sal_Int32(fNum >= aAnyConv.getDouble( xOpt, rStep, 0.0 ));
818 }
819
getFactdouble(sal_Int32 nNum)820 double SAL_CALL AnalysisAddIn::getFactdouble( sal_Int32 nNum )
821 {
822 double fRet = FactDouble( nNum );
823 RETURN_FINITE( fRet );
824 }
825
getImabs(const OUString & aNum)826 double SAL_CALL AnalysisAddIn::getImabs( const OUString& aNum )
827 {
828 double fRet = Complex( aNum ).Abs();
829 RETURN_FINITE( fRet );
830 }
831
getImaginary(const OUString & aNum)832 double SAL_CALL AnalysisAddIn::getImaginary( const OUString& aNum )
833 {
834 double fRet = Complex( aNum ).Imag();
835 RETURN_FINITE( fRet );
836 }
837
getImpower(const OUString & aNum,double f)838 OUString SAL_CALL AnalysisAddIn::getImpower( const OUString& aNum, double f )
839 {
840 Complex z( aNum );
841
842 z.Power( f );
843
844 return z.GetString();
845 }
846
getImargument(const OUString & aNum)847 double SAL_CALL AnalysisAddIn::getImargument( const OUString& aNum )
848 {
849 double fRet = Complex( aNum ).Arg();
850 RETURN_FINITE( fRet );
851 }
852
getImcos(const OUString & aNum)853 OUString SAL_CALL AnalysisAddIn::getImcos( const OUString& aNum )
854 {
855 Complex z( aNum );
856
857 z.Cos();
858
859 return z.GetString();
860 }
861
getImdiv(const OUString & aDivid,const OUString & aDivis)862 OUString SAL_CALL AnalysisAddIn::getImdiv( const OUString& aDivid, const OUString& aDivis )
863 {
864 Complex z( aDivid );
865
866 z.Div( Complex( aDivis ) );
867
868 return z.GetString();
869 }
870
getImexp(const OUString & aNum)871 OUString SAL_CALL AnalysisAddIn::getImexp( const OUString& aNum )
872 {
873 Complex z( aNum );
874
875 z.Exp();
876
877 return z.GetString();
878 }
879
getImconjugate(const OUString & aNum)880 OUString SAL_CALL AnalysisAddIn::getImconjugate( const OUString& aNum )
881 {
882 Complex z( aNum );
883
884 z.Conjugate();
885
886 return z.GetString();
887 }
888
getImln(const OUString & aNum)889 OUString SAL_CALL AnalysisAddIn::getImln( const OUString& aNum )
890 {
891 Complex z( aNum );
892
893 z.Ln();
894
895 return z.GetString();
896 }
897
getImlog10(const OUString & aNum)898 OUString SAL_CALL AnalysisAddIn::getImlog10( const OUString& aNum )
899 {
900 Complex z( aNum );
901
902 z.Log10();
903
904 return z.GetString();
905 }
906
getImlog2(const OUString & aNum)907 OUString SAL_CALL AnalysisAddIn::getImlog2( const OUString& aNum )
908 {
909 Complex z( aNum );
910
911 z.Log2();
912
913 return z.GetString();
914 }
915
getImproduct(const uno::Reference<beans::XPropertySet> &,const uno::Sequence<uno::Sequence<OUString>> & aNum1,const uno::Sequence<uno::Any> & aNL)916 OUString SAL_CALL AnalysisAddIn::getImproduct( const uno::Reference< beans::XPropertySet >&, const uno::Sequence< uno::Sequence< OUString > >& aNum1, const uno::Sequence< uno::Any >& aNL )
917 {
918 ComplexList z_list;
919
920 z_list.Append( aNum1 );
921 z_list.Append( aNL );
922
923 if( z_list.empty() )
924 return Complex( 0 ).GetString();
925
926 Complex z = z_list.Get(0);
927 for( sal_uInt32 i = 1; i < z_list.Count(); ++i )
928 z.Mult( z_list.Get(i) );
929
930 return z.GetString();
931 }
932
getImreal(const OUString & aNum)933 double SAL_CALL AnalysisAddIn::getImreal( const OUString& aNum )
934 {
935 double fRet = Complex( aNum ).Real();
936 RETURN_FINITE( fRet );
937 }
938
getImsin(const OUString & aNum)939 OUString SAL_CALL AnalysisAddIn::getImsin( const OUString& aNum )
940 {
941 Complex z( aNum );
942
943 z.Sin();
944
945 return z.GetString();
946 }
947
getImsub(const OUString & aNum1,const OUString & aNum2)948 OUString SAL_CALL AnalysisAddIn::getImsub( const OUString& aNum1, const OUString& aNum2 )
949 {
950 Complex z( aNum1 );
951
952 z.Sub( Complex( aNum2 ) );
953
954 return z.GetString();
955 }
956
getImsum(const uno::Reference<beans::XPropertySet> &,const uno::Sequence<uno::Sequence<OUString>> & aNum1,const uno::Sequence<uno::Any> & aFollowingPars)957 OUString SAL_CALL AnalysisAddIn::getImsum( const uno::Reference< beans::XPropertySet >&, const uno::Sequence< uno::Sequence< OUString > >& aNum1, const uno::Sequence< uno::Any >& aFollowingPars )
958 {
959 ComplexList z_list;
960
961 z_list.Append( aNum1 );
962 z_list.Append( aFollowingPars );
963
964 if( z_list.empty() )
965 return Complex( 0 ).GetString();
966
967 Complex z( z_list.Get(0) );
968 for( sal_uInt32 i = 1; i < z_list.Count(); ++i )
969 z.Add( z_list.Get(i) );
970
971 return z.GetString();
972 }
973
getImsqrt(const OUString & aNum)974 OUString SAL_CALL AnalysisAddIn::getImsqrt( const OUString& aNum )
975 {
976 Complex z( aNum );
977
978 z.Sqrt();
979
980 return z.GetString();
981 }
982
getImtan(const OUString & aNum)983 OUString SAL_CALL AnalysisAddIn::getImtan( const OUString& aNum )
984 {
985 Complex z( aNum );
986
987 z.Tan();
988
989 return z.GetString();
990 }
991
getImsec(const OUString & aNum)992 OUString SAL_CALL AnalysisAddIn::getImsec( const OUString& aNum )
993 {
994 Complex z( aNum );
995
996 z.Sec();
997
998 return z.GetString();
999 }
1000
getImcsc(const OUString & aNum)1001 OUString SAL_CALL AnalysisAddIn::getImcsc( const OUString& aNum )
1002 {
1003 Complex z( aNum );
1004
1005 z.Csc();
1006
1007 return z.GetString();
1008 }
1009
getImcot(const OUString & aNum)1010 OUString SAL_CALL AnalysisAddIn::getImcot( const OUString& aNum )
1011 {
1012 Complex z( aNum );
1013
1014 z.Cot();
1015
1016 return z.GetString();
1017 }
1018
getImsinh(const OUString & aNum)1019 OUString SAL_CALL AnalysisAddIn::getImsinh( const OUString& aNum )
1020 {
1021 Complex z( aNum );
1022
1023 z.Sinh();
1024
1025 return z.GetString();
1026 }
1027
getImcosh(const OUString & aNum)1028 OUString SAL_CALL AnalysisAddIn::getImcosh( const OUString& aNum )
1029 {
1030 Complex z( aNum );
1031
1032 z.Cosh();
1033
1034 return z.GetString();
1035 }
1036
getImsech(const OUString & aNum)1037 OUString SAL_CALL AnalysisAddIn::getImsech( const OUString& aNum )
1038 {
1039 Complex z( aNum );
1040
1041 z.Sech();
1042
1043 return z.GetString();
1044 }
1045
getImcsch(const OUString & aNum)1046 OUString SAL_CALL AnalysisAddIn::getImcsch( const OUString& aNum )
1047 {
1048 Complex z( aNum );
1049
1050 z.Csch();
1051
1052 return z.GetString();
1053 }
1054
getComplex(double fR,double fI,const uno::Any & rSuff)1055 OUString SAL_CALL AnalysisAddIn::getComplex( double fR, double fI, const uno::Any& rSuff )
1056 {
1057 bool bi;
1058
1059 switch( rSuff.getValueTypeClass() )
1060 {
1061 case uno::TypeClass_VOID:
1062 bi = true;
1063 break;
1064 case uno::TypeClass_STRING:
1065 {
1066 auto pSuff = o3tl::forceAccess<OUString>(rSuff);
1067 bi = *pSuff == "i" || pSuff->isEmpty();
1068 if( !bi && *pSuff != "j" )
1069 throw lang::IllegalArgumentException();
1070 }
1071 break;
1072 default:
1073 throw lang::IllegalArgumentException();
1074 }
1075
1076 return Complex( fR, fI, bi ? 'i' : 'j' ).GetString();
1077 }
1078
getConvert(double f,const OUString & aFU,const OUString & aTU)1079 double SAL_CALL AnalysisAddIn::getConvert( double f, const OUString& aFU, const OUString& aTU )
1080 {
1081 if( !pCDL )
1082 pCDL.reset(new ConvertDataList());
1083
1084 double fRet = pCDL->Convert( f, aFU, aTU );
1085 RETURN_FINITE( fRet );
1086 }
1087
AnalysisResId(const char * pResId)1088 OUString AnalysisAddIn::AnalysisResId(const char* pResId)
1089 {
1090 return Translate::get(pResId, aResLocale);
1091 }
1092
1093 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1094