Coverage Report

Created: 2025-07-07 10:01

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