summaryrefslogtreecommitdiffstats
path: root/scaddins/source
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /scaddins/source
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--scaddins/source/analysis/analysis.component27
-rw-r--r--scaddins/source/analysis/analysis.cxx1059
-rw-r--r--scaddins/source/analysis/analysis.hxx235
-rw-r--r--scaddins/source/analysis/analysisdefs.hxx29
-rw-r--r--scaddins/source/analysis/analysishelper.cxx2811
-rw-r--r--scaddins/source/analysis/analysishelper.hxx905
-rw-r--r--scaddins/source/analysis/bessel.cxx452
-rw-r--r--scaddins/source/analysis/bessel.hxx58
-rw-r--r--scaddins/source/analysis/deffuncname.hxx628
-rw-r--r--scaddins/source/analysis/financial.cxx675
-rw-r--r--scaddins/source/datefunc/date.component27
-rw-r--r--scaddins/source/datefunc/datefunc.cxx688
-rw-r--r--scaddins/source/datefunc/datefunc.hxx189
-rw-r--r--scaddins/source/datefunc/deffuncname.hxx70
-rw-r--r--scaddins/source/pricing/black_scholes.cxx939
-rw-r--r--scaddins/source/pricing/black_scholes.hxx146
-rw-r--r--scaddins/source/pricing/pricing.component27
-rw-r--r--scaddins/source/pricing/pricing.cxx510
-rw-r--r--scaddins/source/pricing/pricing.hxx198
19 files changed, 9673 insertions, 0 deletions
diff --git a/scaddins/source/analysis/analysis.component b/scaddins/source/analysis/analysis.component
new file mode 100644
index 000000000..86d26c242
--- /dev/null
+++ b/scaddins/source/analysis/analysis.component
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.sheet.addin.AnalysisImpl"
+ constructor="scaddins_AnalysisAddIn_get_implementation" single-instance="true">
+ <service name="com.sun.star.sheet.AddIn"/>
+ <service name="com.sun.star.sheet.addin.Analysis"/>
+ </implementation>
+</component>
diff --git a/scaddins/source/analysis/analysis.cxx b/scaddins/source/analysis/analysis.cxx
new file mode 100644
index 000000000..9c9fc9718
--- /dev/null
+++ b/scaddins/source/analysis/analysis.cxx
@@ -0,0 +1,1059 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "analysisdefs.hxx"
+#include "analysis.hxx"
+#include "bessel.hxx"
+#include <comphelper/random.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <o3tl/any.hxx>
+#include <rtl/math.hxx>
+#include <sal/macros.h>
+#include <unotools/resmgr.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <algorithm>
+#include <cmath>
+#include <float.h>
+
+constexpr OUStringLiteral ADDIN_SERVICE = u"com.sun.star.sheet.AddIn";
+constexpr OUStringLiteral MY_SERVICE = u"com.sun.star.sheet.addin.Analysis";
+constexpr OUStringLiteral MY_IMPLNAME = u"com.sun.star.sheet.addin.AnalysisImpl";
+
+using namespace ::com::sun::star;
+using namespace sca::analysis;
+
+OUString AnalysisAddIn::GetFuncDescrStr(const TranslateId* pResId, sal_uInt16 nStrIndex)
+{
+ return AnalysisResId(pResId[nStrIndex - 1]);
+}
+
+void AnalysisAddIn::InitData()
+{
+ aResLocale = Translate::Create("sca", LanguageTag(aFuncLoc));
+
+ pFD.reset(new FuncDataList);
+ InitFuncDataList(*pFD);
+
+ pDefLocales.reset();
+}
+
+AnalysisAddIn::AnalysisAddIn( const uno::Reference< uno::XComponentContext >& xContext ) :
+ AnalysisAddIn_Base(m_aMutex),
+ aAnyConv( xContext )
+{
+}
+
+AnalysisAddIn::~AnalysisAddIn()
+{
+}
+
+sal_Int32 AnalysisAddIn::getDateMode(
+ const uno::Reference< beans::XPropertySet >& xPropSet,
+ const uno::Any& rAny )
+{
+ sal_Int32 nMode = aAnyConv.getInt32( xPropSet, rAny, 0 );
+ if( (nMode < 0) || (nMode > 4) )
+ throw lang::IllegalArgumentException();
+ return nMode;
+}
+
+#define MAXFACTDOUBLE 300
+
+double AnalysisAddIn::FactDouble( sal_Int32 nNum )
+{
+ if( nNum < 0 || nNum > MAXFACTDOUBLE )
+ throw lang::IllegalArgumentException();
+
+ if( !pFactDoubles )
+ {
+ pFactDoubles.reset( new double[ MAXFACTDOUBLE + 1 ] );
+
+ pFactDoubles[ 0 ] = 1.0; // by default
+
+ double fOdd = 1.0;
+ double fEven = 2.0;
+
+ pFactDoubles[ 1 ] = fOdd;
+ pFactDoubles[ 2 ] = fEven;
+
+ bool bOdd = true;
+
+ for( sal_uInt16 nCnt = 3 ; nCnt <= MAXFACTDOUBLE ; nCnt++ )
+ {
+ if( bOdd )
+ {
+ fOdd *= nCnt;
+ pFactDoubles[ nCnt ] = fOdd;
+ }
+ else
+ {
+ fEven *= nCnt;
+ pFactDoubles[ nCnt ] = fEven;
+ }
+
+ bOdd = !bOdd;
+
+ }
+ }
+
+ return pFactDoubles[ nNum ];
+}
+
+// XServiceName
+OUString SAL_CALL AnalysisAddIn::getServiceName()
+{
+ // name of specific AddIn service
+ return MY_SERVICE;
+}
+
+// XServiceInfo
+OUString SAL_CALL AnalysisAddIn::getImplementationName()
+{
+ return MY_IMPLNAME;
+}
+
+sal_Bool SAL_CALL AnalysisAddIn::supportsService( const OUString& aName )
+{
+ return cppu::supportsService(this, aName);
+}
+
+uno::Sequence< OUString > SAL_CALL AnalysisAddIn::getSupportedServiceNames()
+{
+ return { ADDIN_SERVICE, MY_SERVICE };
+}
+
+// XLocalizable
+void SAL_CALL AnalysisAddIn::setLocale( const lang::Locale& eLocale )
+{
+ aFuncLoc = eLocale;
+
+ InitData(); // change of locale invalidates resources!
+}
+
+lang::Locale SAL_CALL AnalysisAddIn::getLocale()
+{
+ return aFuncLoc;
+}
+
+// XAddIn
+OUString SAL_CALL AnalysisAddIn::getProgrammaticFuntionName( const OUString& )
+{
+ // not used by calc
+ // (but should be implemented for other uses of the AddIn service)
+
+ return OUString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getDisplayFunctionName( const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aProgrammaticName ) );
+ if( it != pFD->end() )
+ {
+ aRet = AnalysisResId(it->GetUINameID());
+ if( it->IsDouble() )
+ {
+ const OUString& rSuffix = it->GetSuffix();
+ if (!rSuffix.isEmpty())
+ aRet += rSuffix;
+ else
+ aRet += "_ADD";
+ }
+ }
+ else
+ {
+ aRet = "UNKNOWNFUNC_" + aProgrammaticName;
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL AnalysisAddIn::getFunctionDescription( const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aProgrammaticName ) );
+ if( it != pFD->end() )
+ aRet = GetFuncDescrStr( it->GetDescrID(), 1 );
+
+ return aRet;
+}
+
+OUString SAL_CALL AnalysisAddIn::getDisplayArgumentName( const OUString& aName, sal_Int32 nArg )
+{
+ OUString aRet;
+
+ auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aName ) );
+ if( it != pFD->end() && nArg <= 0xFFFF )
+ {
+ sal_uInt16 nStr = it->GetStrIndex( sal_uInt16( nArg ) );
+ if( nStr )
+ aRet = GetFuncDescrStr( it->GetDescrID(), nStr );
+ else
+ aRet = "internal";
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL AnalysisAddIn::getArgumentDescription( const OUString& aName, sal_Int32 nArg )
+{
+ OUString aRet;
+
+ auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aName ) );
+ if( it != pFD->end() && nArg <= 0xFFFF )
+ {
+ sal_uInt16 nStr = it->GetStrIndex( sal_uInt16( nArg ) );
+ if( nStr )
+ aRet = GetFuncDescrStr( it->GetDescrID(), nStr + 1 );
+ else
+ aRet = "for internal use only";
+ }
+
+ return aRet;
+}
+
+constexpr OUStringLiteral pDefCatName = u"Add-In";
+
+OUString SAL_CALL AnalysisAddIn::getProgrammaticCategoryName( const OUString& aName )
+{
+ // return non-translated strings
+ // return OUString( "Add-In" );
+ auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aName ) );
+ OUString aRet;
+ if( it != pFD->end() )
+ {
+ switch( it->GetCategory() )
+ {
+ case FDCategory::DateTime: aRet = "Date&Time"; break;
+ case FDCategory::Finance: aRet = "Financial"; break;
+ case FDCategory::Inf: aRet = "Information"; break;
+ case FDCategory::Math: aRet = "Mathematical"; break;
+ case FDCategory::Tech: aRet = "Technical"; break;
+ }
+ }
+ else
+ aRet = pDefCatName;
+
+ return aRet;
+}
+
+OUString SAL_CALL AnalysisAddIn::getDisplayCategoryName( const OUString& aProgrammaticFunctionName )
+{
+ // return translated strings, not used for predefined categories
+ auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aProgrammaticFunctionName ) );
+ OUString aRet;
+ if( it != pFD->end() )
+ {
+ switch( it->GetCategory() )
+ {
+ case FDCategory::DateTime: aRet = "Date&Time"; break;
+ case FDCategory::Finance: aRet = "Financial"; break;
+ case FDCategory::Inf: aRet = "Information"; break;
+ case FDCategory::Math: aRet = "Mathematical"; break;
+ case FDCategory::Tech: aRet = "Technical"; break;
+ }
+ }
+ else
+ aRet = pDefCatName;
+
+ return aRet;
+}
+
+static const char* pLang[] = { "de", "en" };
+static const char* pCoun[] = { "DE", "US" };
+const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS(pLang);
+
+void AnalysisAddIn::InitDefLocales()
+{
+ pDefLocales.reset( new lang::Locale[ nNumOfLoc ] );
+
+ for( sal_uInt32 n = 0 ; n < nNumOfLoc ; n++ )
+ {
+ pDefLocales[ n ].Language = OUString::createFromAscii( pLang[ n ] );
+ pDefLocales[ n ].Country = OUString::createFromAscii( pCoun[ n ] );
+ }
+}
+
+inline const lang::Locale& AnalysisAddIn::GetLocale( sal_uInt32 nInd )
+{
+ if( !pDefLocales )
+ InitDefLocales();
+
+ if( nInd < nNumOfLoc )
+ return pDefLocales[ nInd ];
+ else
+ return aFuncLoc;
+}
+
+uno::Sequence< sheet::LocalizedName > SAL_CALL AnalysisAddIn::getCompatibilityNames( const OUString& aProgrammaticName )
+{
+ auto it = std::find_if(pFD->begin(), pFD->end(), FindFuncData( aProgrammaticName ) );
+ if( it == pFD->end() )
+ return uno::Sequence< sheet::LocalizedName >( 0 );
+
+ const std::vector<OUString>& r = it->GetCompNameList();
+ sal_uInt32 nCount = r.size();
+
+ uno::Sequence< sheet::LocalizedName > aRet( nCount );
+
+ sheet::LocalizedName* pArray = aRet.getArray();
+
+ for( sal_uInt32 n = 0 ; n < nCount ; n++ )
+ {
+ pArray[ n ] = sheet::LocalizedName( GetLocale( n ), r[n] );
+ }
+
+ return aRet;
+}
+
+// XAnalysis
+/** Workday */
+sal_Int32 SAL_CALL AnalysisAddIn::getWorkday( const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nDate, sal_Int32 nDays, const uno::Any& aHDay )
+{
+ if( !nDays )
+ return nDate;
+
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+
+ SortedIndividualInt32List aSrtLst;
+
+ aSrtLst.InsertHolidayList( aAnyConv, xOptions, aHDay, nNullDate );
+
+ sal_Int32 nActDate = nDate + nNullDate;
+
+ if( nDays > 0 )
+ {
+ if( GetDayOfWeek( nActDate ) == 5 )
+ // when starting on Saturday, assuming we're starting on Sunday to get the jump over the weekend
+ nActDate++;
+
+ while( nDays )
+ {
+ nActDate++;
+
+ if( GetDayOfWeek( nActDate ) < 5 )
+ {
+ if( !aSrtLst.Find( nActDate ) )
+ nDays--;
+ }
+ else
+ nActDate++; // jump over weekend
+ }
+ }
+ else
+ {
+ if( GetDayOfWeek( nActDate ) == 6 )
+ // when starting on Sunday, assuming we're starting on Saturday to get the jump over the weekend
+ nActDate--;
+
+ while( nDays )
+ {
+ nActDate--;
+
+ if( GetDayOfWeek( nActDate ) < 5 )
+ {
+ if( !aSrtLst.Find( nActDate ) )
+ nDays++;
+ }
+ else
+ nActDate--; // jump over weekend
+ }
+ }
+
+ return nActDate - nNullDate;
+}
+
+/** Yearfrac */
+double SAL_CALL AnalysisAddIn::getYearfrac( const uno::Reference< beans::XPropertySet >& xOpt,
+ sal_Int32 nStartDate, sal_Int32 nEndDate, const uno::Any& rMode )
+{
+ double fRet = GetYearFrac( xOpt, nStartDate, nEndDate, getDateMode( xOpt, rMode ) );
+ RETURN_FINITE( fRet );
+}
+
+sal_Int32 SAL_CALL AnalysisAddIn::getEdate( const uno::Reference< beans::XPropertySet >& xOpt, sal_Int32 nStartDate, sal_Int32 nMonths )
+{
+ sal_Int32 nNullDate = GetNullDate( xOpt );
+ ScaDate aDate( nNullDate, nStartDate, 5 );
+ aDate.addMonths( nMonths );
+ return aDate.getDate( nNullDate );
+}
+
+sal_Int32 SAL_CALL AnalysisAddIn::getWeeknum( const uno::Reference< beans::XPropertySet >& xOpt, sal_Int32 nDate, sal_Int32 nMode )
+{
+ nDate += GetNullDate( xOpt );
+
+ sal_uInt16 nDay, nMonth, nYear;
+ DaysToDate( nDate, nDay, nMonth, nYear );
+
+ sal_Int32 nFirstInYear = DateToDays( 1, 1, nYear );
+ sal_uInt16 nFirstDayInYear = GetDayOfWeek( nFirstInYear );
+
+ return ( nDate - nFirstInYear + ( ( nMode == 1 )? ( nFirstDayInYear + 1 ) % 7 : nFirstDayInYear ) ) / 7 + 1;
+}
+
+sal_Int32 SAL_CALL AnalysisAddIn::getEomonth( const uno::Reference< beans::XPropertySet >& xOpt, sal_Int32 nDate, sal_Int32 nMonths )
+{
+ sal_Int32 nNullDate = GetNullDate( xOpt );
+ nDate += nNullDate;
+ sal_uInt16 nDay, nMonth, nYear;
+ DaysToDate( nDate, nDay, nMonth, nYear );
+
+ sal_Int32 nNewMonth = nMonth + nMonths;
+
+ if( nNewMonth > 12 )
+ {
+ nYear = sal::static_int_cast<sal_uInt16>( nYear + ( nNewMonth / 12 ) );
+ nNewMonth %= 12;
+ }
+ else if( nNewMonth < 1 )
+ {
+ nNewMonth = -nNewMonth;
+ nYear = sal::static_int_cast<sal_uInt16>( nYear - ( nNewMonth / 12 ) );
+ nYear--;
+ nNewMonth %= 12;
+ nNewMonth = 12 - nNewMonth;
+ }
+
+ return DateToDays( DaysInMonth( sal_uInt16( nNewMonth ), nYear ), sal_uInt16( nNewMonth ), nYear ) - nNullDate;
+}
+
+sal_Int32 SAL_CALL AnalysisAddIn::getNetworkdays( const uno::Reference< beans::XPropertySet >& xOpt,
+ sal_Int32 nStartDate, sal_Int32 nEndDate, const uno::Any& aHDay )
+{
+ sal_Int32 nNullDate = GetNullDate( xOpt );
+
+ SortedIndividualInt32List aSrtLst;
+
+ aSrtLst.InsertHolidayList( aAnyConv, xOpt, aHDay, nNullDate );
+
+ sal_Int32 nActDate = nStartDate + nNullDate;
+ sal_Int32 nStopDate = nEndDate + nNullDate;
+ sal_Int32 nCnt = 0;
+
+ if( nActDate <= nStopDate )
+ {
+ while( nActDate <= nStopDate )
+ {
+ if( GetDayOfWeek( nActDate ) < 5 && !aSrtLst.Find( nActDate ) )
+ nCnt++;
+
+ nActDate++;
+ }
+ }
+ else
+ {
+ while( nActDate >= nStopDate )
+ {
+ if( GetDayOfWeek( nActDate ) < 5 && !aSrtLst.Find( nActDate ) )
+ nCnt--;
+
+ nActDate--;
+ }
+ }
+
+ return nCnt;
+}
+
+sal_Int32 SAL_CALL AnalysisAddIn::getIseven( sal_Int32 nVal )
+{
+ return ( nVal & 0x00000001 )? 0 : 1;
+}
+
+sal_Int32 SAL_CALL AnalysisAddIn::getIsodd( sal_Int32 nVal )
+{
+ return ( nVal & 0x00000001 )? 1 : 0;
+}
+
+double SAL_CALL
+AnalysisAddIn::getMultinomial( const uno::Reference< beans::XPropertySet >& xOpt, const uno::Sequence< uno::Sequence< sal_Int32 > >& aVLst,
+ const uno::Sequence< uno::Any >& aOptVLst )
+{
+ ScaDoubleListGE0 aValList;
+
+ aValList.Append( aVLst );
+ aValList.Append( aAnyConv, xOpt, aOptVLst );
+
+ if( aValList.Count() == 0 )
+ return 0.0;
+
+ double nZ = 0;
+ double fRet = 1.0;
+
+ for( sal_uInt32 i = 0; i < aValList.Count(); ++i )
+ {
+ const double d = aValList.Get(i);
+ double n = (d >= 0.0) ? rtl::math::approxFloor( d ) : rtl::math::approxCeil( d );
+ if ( n < 0.0 )
+ throw lang::IllegalArgumentException();
+
+ if( n > 0.0 )
+ {
+ nZ += n;
+ fRet *= BinomialCoefficient(nZ, n);
+ }
+ }
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getSeriessum( double fX, double fN, double fM, const uno::Sequence< uno::Sequence< double > >& aCoeffList )
+{
+ double fRet = 0.0;
+
+ // #i32269# 0^0 is undefined, Excel returns #NUM! error
+ if( fX == 0.0 && fN == 0 )
+ throw uno::RuntimeException("undefined expression: 0^0");
+
+ if( fX != 0.0 )
+ {
+ for( const uno::Sequence< double >& rList : aCoeffList )
+ {
+ for( const double fCoef : rList )
+ {
+ fRet += fCoef * pow( fX, fN );
+
+ fN += fM;
+ }
+ }
+ }
+
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getQuotient( double fNum, double fDenom )
+{
+ double fRet;
+ if( (fNum < 0) != (fDenom < 0) )
+ fRet = ::rtl::math::approxCeil( fNum / fDenom );
+ else
+ fRet = ::rtl::math::approxFloor( fNum / fDenom );
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getMround( double fNum, double fMult )
+{
+ if( fMult == 0.0 )
+ return fMult;
+
+ double fRet = fMult * ::rtl::math::round( fNum / fMult );
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getSqrtpi( double fNum )
+{
+ double fRet = sqrt( fNum * M_PI );
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getRandbetween( double fMin, double fMax )
+{
+ fMin = ::rtl::math::round( fMin, 0, rtl_math_RoundingMode_Up );
+ fMax = ::rtl::math::round( fMax, 0, rtl_math_RoundingMode_Up );
+ if( fMin > fMax )
+ throw lang::IllegalArgumentException();
+
+ double fRet = floor(comphelper::rng::uniform_real_distribution(fMin, nextafter(fMax+1, -DBL_MAX)));
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getGcd( const uno::Reference< beans::XPropertySet >& xOpt, const uno::Sequence< uno::Sequence< double > >& aVLst, const uno::Sequence< uno::Any >& aOptVLst )
+{
+ ScaDoubleListGT0 aValList;
+
+ aValList.Append( aVLst );
+ aValList.Append( aAnyConv, xOpt, aOptVLst );
+
+ if( aValList.Count() == 0 )
+ return 0.0;
+
+ double f = aValList.Get(0);
+ for( sal_uInt32 i = 1; i < aValList.Count(); ++i )
+ {
+ f = GetGcd( aValList.Get(i), f );
+ }
+
+ RETURN_FINITE( f );
+}
+
+double SAL_CALL AnalysisAddIn::getLcm( const uno::Reference< beans::XPropertySet >& xOpt, const uno::Sequence< uno::Sequence< double > >& aVLst, const uno::Sequence< uno::Any >& aOptVLst )
+{
+ ScaDoubleListGE0 aValList;
+
+ aValList.Append( aVLst );
+ aValList.Append( aAnyConv, xOpt, aOptVLst );
+
+ if( aValList.Count() == 0 )
+ return 0.0;
+
+ double f = rtl::math::approxFloor( aValList.Get(0) );
+ if( f < 0.0 )
+ throw lang::IllegalArgumentException();
+
+ if( f == 0.0 )
+ return f;
+
+ for( sal_uInt32 i = 1; i < aValList.Count(); ++i )
+ {
+ double fTmp = rtl::math::approxFloor( aValList.Get(i) );
+ if( fTmp < 0.0 )
+ throw lang::IllegalArgumentException();
+
+ f = fTmp * f / GetGcd( fTmp, f );
+ if( f == 0.0 )
+ return f;
+ }
+
+ RETURN_FINITE( f );
+}
+
+double SAL_CALL AnalysisAddIn::getBesseli( double fNum, sal_Int32 nOrder )
+{
+ double fRet = sca::analysis::BesselI( fNum, nOrder );
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getBesselj( double fNum, sal_Int32 nOrder )
+{
+ double fRet = sca::analysis::BesselJ( fNum, nOrder );
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getBesselk( double fNum, sal_Int32 nOrder )
+{
+ if( nOrder < 0 || fNum <= 0.0 )
+ throw lang::IllegalArgumentException();
+
+ double fRet = sca::analysis::BesselK( fNum, nOrder );
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getBessely( double fNum, sal_Int32 nOrder )
+{
+ if( nOrder < 0 || fNum <= 0.0 )
+ throw lang::IllegalArgumentException();
+
+ double fRet = sca::analysis::BesselY( fNum, nOrder );
+ RETURN_FINITE( fRet );
+}
+
+const double SCA_MAX2 = 511.0; // min. val for binary numbers (9 bits + sign)
+const double SCA_MIN2 = -SCA_MAX2-1.0; // min. val for binary numbers (9 bits + sign)
+const double SCA_MAX8 = 536870911.0; // max. val for octal numbers (29 bits + sign)
+const double SCA_MIN8 = -SCA_MAX8-1.0; // min. val for octal numbers (29 bits + sign)
+const double SCA_MAX16 = 549755813887.0; // max. val for hexadecimal numbers (39 bits + sign)
+const double SCA_MIN16 = -SCA_MAX16-1.0; // min. val for hexadecimal numbers (39 bits + sign)
+const sal_Int32 SCA_MAXPLACES = 10; // max. number of places
+
+OUString SAL_CALL AnalysisAddIn::getBin2Oct( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
+{
+ double fVal = ConvertToDec( aNum, 2, SCA_MAXPLACES );
+ sal_Int32 nPlaces = 0;
+ bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
+ return ConvertFromDec( fVal, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
+}
+
+double SAL_CALL AnalysisAddIn::getBin2Dec( const OUString& aNum )
+{
+ double fRet = ConvertToDec( aNum, 2, SCA_MAXPLACES );
+ RETURN_FINITE( fRet );
+}
+
+OUString SAL_CALL AnalysisAddIn::getBin2Hex( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
+{
+ double fVal = ConvertToDec( aNum, 2, SCA_MAXPLACES );
+ sal_Int32 nPlaces = 0;
+ bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
+ return ConvertFromDec( fVal, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
+}
+
+OUString SAL_CALL AnalysisAddIn::getOct2Bin( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
+{
+ double fVal = ConvertToDec( aNum, 8, SCA_MAXPLACES );
+ sal_Int32 nPlaces = 0;
+ bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
+ return ConvertFromDec( fVal, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
+}
+
+double SAL_CALL AnalysisAddIn::getOct2Dec( const OUString& aNum )
+{
+ double fRet = ConvertToDec( aNum, 8, SCA_MAXPLACES );
+ RETURN_FINITE( fRet );
+}
+
+OUString SAL_CALL AnalysisAddIn::getOct2Hex( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
+{
+ double fVal = ConvertToDec( aNum, 8, SCA_MAXPLACES );
+ sal_Int32 nPlaces = 0;
+ bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
+ return ConvertFromDec( fVal, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
+}
+
+OUString SAL_CALL AnalysisAddIn::getDec2Bin( const uno::Reference< beans::XPropertySet >& xOpt, sal_Int32 nNum, const uno::Any& rPlaces )
+{
+ sal_Int32 nPlaces = 0;
+ bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
+ return ConvertFromDec( nNum, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
+}
+
+OUString SAL_CALL AnalysisAddIn::getDec2Oct( const uno::Reference< beans::XPropertySet >& xOpt, sal_Int32 nNum, const uno::Any& rPlaces )
+{
+ sal_Int32 nPlaces = 0;
+ bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
+ return ConvertFromDec( nNum, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
+}
+
+OUString SAL_CALL AnalysisAddIn::getDec2Hex( const uno::Reference< beans::XPropertySet >& xOpt, double fNum, const uno::Any& rPlaces )
+{
+ sal_Int32 nPlaces = 0;
+ bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
+ return ConvertFromDec( fNum, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
+}
+
+OUString SAL_CALL AnalysisAddIn::getHex2Bin( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
+{
+ double fVal = ConvertToDec( aNum, 16, SCA_MAXPLACES );
+ sal_Int32 nPlaces = 0;
+ bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
+ return ConvertFromDec( fVal, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
+}
+
+double SAL_CALL AnalysisAddIn::getHex2Dec( const OUString& aNum )
+{
+ double fRet = ConvertToDec( aNum, 16, SCA_MAXPLACES );
+ RETURN_FINITE( fRet );
+}
+
+OUString SAL_CALL AnalysisAddIn::getHex2Oct( const uno::Reference< beans::XPropertySet >& xOpt, const OUString& aNum, const uno::Any& rPlaces )
+{
+ double fVal = ConvertToDec( aNum, 16, SCA_MAXPLACES );
+ sal_Int32 nPlaces = 0;
+ bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
+ return ConvertFromDec( fVal, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
+}
+
+sal_Int32 SAL_CALL AnalysisAddIn::getDelta( const uno::Reference< beans::XPropertySet >& xOpt, double fNum1, const uno::Any& rNum2 )
+{
+ return sal_Int32(fNum1 == aAnyConv.getDouble( xOpt, rNum2, 0.0 ));
+}
+
+double SAL_CALL AnalysisAddIn::getErf( const uno::Reference< beans::XPropertySet >& xOpt, double fLL, const uno::Any& rUL )
+{
+ double fUL, fRet;
+ bool bContainsValue = aAnyConv.getDouble( fUL, xOpt, rUL );
+
+ fRet = bContainsValue ? (Erf( fUL ) - Erf( fLL )) : Erf( fLL );
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getErfc( double f )
+{
+ double fRet = Erfc( f );
+ RETURN_FINITE( fRet );
+}
+
+sal_Int32 SAL_CALL AnalysisAddIn::getGestep( const uno::Reference< beans::XPropertySet >& xOpt, double fNum, const uno::Any& rStep )
+{
+ return sal_Int32(fNum >= aAnyConv.getDouble( xOpt, rStep, 0.0 ));
+}
+
+double SAL_CALL AnalysisAddIn::getFactdouble( sal_Int32 nNum )
+{
+ double fRet = FactDouble( nNum );
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getImabs( const OUString& aNum )
+{
+ double fRet = Complex( aNum ).Abs();
+ RETURN_FINITE( fRet );
+}
+
+double SAL_CALL AnalysisAddIn::getImaginary( const OUString& aNum )
+{
+ double fRet = Complex( aNum ).Imag();
+ RETURN_FINITE( fRet );
+}
+
+OUString SAL_CALL AnalysisAddIn::getImpower( const OUString& aNum, double f )
+{
+ Complex z( aNum );
+
+ z.Power( f );
+
+ return z.GetString();
+}
+
+double SAL_CALL AnalysisAddIn::getImargument( const OUString& aNum )
+{
+ double fRet = Complex( aNum ).Arg();
+ RETURN_FINITE( fRet );
+}
+
+OUString SAL_CALL AnalysisAddIn::getImcos( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Cos();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImdiv( const OUString& aDivid, const OUString& aDivis )
+{
+ Complex z( aDivid );
+
+ z.Div( Complex( aDivis ) );
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImexp( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Exp();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImconjugate( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Conjugate();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImln( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Ln();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImlog10( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Log10();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImlog2( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Log2();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImproduct( const uno::Reference< beans::XPropertySet >&, const uno::Sequence< uno::Sequence< OUString > >& aNum1, const uno::Sequence< uno::Any >& aNL )
+{
+ ComplexList z_list;
+
+ z_list.Append( aNum1 );
+ z_list.Append( aNL );
+
+ if( z_list.empty() )
+ return Complex( 0 ).GetString();
+
+ Complex z = z_list.Get(0);
+ for( sal_uInt32 i = 1; i < z_list.Count(); ++i )
+ z.Mult( z_list.Get(i) );
+
+ return z.GetString();
+}
+
+double SAL_CALL AnalysisAddIn::getImreal( const OUString& aNum )
+{
+ double fRet = Complex( aNum ).Real();
+ RETURN_FINITE( fRet );
+}
+
+OUString SAL_CALL AnalysisAddIn::getImsin( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Sin();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImsub( const OUString& aNum1, const OUString& aNum2 )
+{
+ Complex z( aNum1 );
+
+ z.Sub( Complex( aNum2 ) );
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImsum( const uno::Reference< beans::XPropertySet >&, const uno::Sequence< uno::Sequence< OUString > >& aNum1, const uno::Sequence< uno::Any >& aFollowingPars )
+{
+ ComplexList z_list;
+
+ z_list.Append( aNum1 );
+ z_list.Append( aFollowingPars );
+
+ if( z_list.empty() )
+ return Complex( 0 ).GetString();
+
+ Complex z( z_list.Get(0) );
+ for( sal_uInt32 i = 1; i < z_list.Count(); ++i )
+ z.Add( z_list.Get(i) );
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImsqrt( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Sqrt();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImtan( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Tan();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImsec( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Sec();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImcsc( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Csc();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImcot( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Cot();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImsinh( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Sinh();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImcosh( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Cosh();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImsech( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Sech();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getImcsch( const OUString& aNum )
+{
+ Complex z( aNum );
+
+ z.Csch();
+
+ return z.GetString();
+}
+
+OUString SAL_CALL AnalysisAddIn::getComplex( double fR, double fI, const uno::Any& rSuff )
+{
+ bool bi;
+
+ switch( rSuff.getValueTypeClass() )
+ {
+ case uno::TypeClass_VOID:
+ bi = true;
+ break;
+ case uno::TypeClass_STRING:
+ {
+ auto pSuff = o3tl::forceAccess<OUString>(rSuff);
+ bi = *pSuff == "i" || pSuff->isEmpty();
+ if( !bi && *pSuff != "j" )
+ throw lang::IllegalArgumentException();
+ }
+ break;
+ default:
+ throw lang::IllegalArgumentException();
+ }
+
+ return Complex( fR, fI, bi ? 'i' : 'j' ).GetString();
+}
+
+double SAL_CALL AnalysisAddIn::getConvert( double f, const OUString& aFU, const OUString& aTU )
+{
+ if( !pCDL )
+ pCDL.reset(new ConvertDataList());
+
+ double fRet = pCDL->Convert( f, aFU, aTU );
+ RETURN_FINITE( fRet );
+}
+
+OUString AnalysisAddIn::AnalysisResId(TranslateId aResId)
+{
+ return Translate::get(aResId, aResLocale);
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scaddins_AnalysisAddIn_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new AnalysisAddIn(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/analysis/analysis.hxx b/scaddins/source/analysis/analysis.hxx
new file mode 100644
index 000000000..841979f99
--- /dev/null
+++ b/scaddins/source/analysis/analysis.hxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+
+#include <com/sun/star/sheet/XAddIn.hpp>
+#include <com/sun/star/lang/XServiceName.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sheet/addin/XAnalysis.hpp>
+#include <com/sun/star/sheet/XCompatibilityNames.hpp>
+
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <unotools/resmgr.hxx>
+
+#include "analysishelper.hxx"
+
+#include <memory>
+
+namespace com::sun::star::lang { class XMultiServiceFactory; }
+namespace com::sun::star::sheet { struct LocalizedName; }
+
+typedef cppu::WeakComponentImplHelper<
+ css::sheet::XAddIn,
+ css::sheet::XCompatibilityNames,
+ css::sheet::addin::XAnalysis,
+ css::lang::XServiceName,
+ css::lang::XServiceInfo > AnalysisAddIn_Base;
+
+class AnalysisAddIn : private cppu::BaseMutex, public AnalysisAddIn_Base
+{
+private:
+ css::lang::Locale aFuncLoc;
+ std::unique_ptr<css::lang::Locale[]> pDefLocales;
+ std::unique_ptr<sca::analysis::FuncDataList> pFD;
+ std::unique_ptr<double[]> pFactDoubles;
+ std::unique_ptr<sca::analysis::ConvertDataList> pCDL;
+ std::locale aResLocale;
+
+ sca::analysis::ScaAnyConverter aAnyConv;
+
+ /// @throws css::uno::RuntimeException
+ OUString GetFuncDescrStr(const TranslateId* pResId, sal_uInt16 nStrIndex);
+ void InitDefLocales();
+ inline const css::lang::Locale& GetLocale( sal_uInt32 nInd );
+ void InitData();
+
+ /// Converts an Any to sal_Int32 in the range from 0 to 4 (date calculation mode).
+ ///
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ sal_Int32 getDateMode(
+ const css::uno::Reference< css::beans::XPropertySet >& xPropSet,
+ const css::uno::Any& rAny );
+
+public:
+ explicit AnalysisAddIn(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext );
+
+ OUString AnalysisResId(TranslateId aId);
+
+ virtual ~AnalysisAddIn() override;
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ double FactDouble( sal_Int32 nNum );
+
+ // XAddIn
+ virtual OUString SAL_CALL getProgrammaticFuntionName( const OUString& aDisplayName ) override;
+ virtual OUString SAL_CALL getDisplayFunctionName( const OUString& aProgrammaticName ) override;
+ virtual OUString SAL_CALL getFunctionDescription( const OUString& aProgrammaticName ) override;
+ virtual OUString SAL_CALL getDisplayArgumentName( const OUString& aProgrammaticFunctionName, sal_Int32 nArgument ) override;
+ virtual OUString SAL_CALL getArgumentDescription( const OUString& aProgrammaticFunctionName, sal_Int32 nArgument ) override;
+ virtual OUString SAL_CALL getProgrammaticCategoryName( const OUString& aProgrammaticFunctionName ) override;
+ virtual OUString SAL_CALL getDisplayCategoryName( const OUString& aProgrammaticFunctionName ) override;
+
+ // XCompatibilityNames
+ virtual css::uno::Sequence< css::sheet::LocalizedName > SAL_CALL getCompatibilityNames( const OUString& aProgrammaticName ) override;
+
+ // XLocalizable
+ virtual void SAL_CALL setLocale( const css::lang::Locale& eLocale ) override;
+ virtual css::lang::Locale SAL_CALL getLocale( ) override;
+
+ // XServiceName
+ virtual OUString SAL_CALL getServiceName( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // methods from own interfaces start here
+
+ // XAnalysis
+// virtual double SAL_CALL get_Test( const css::uno::Reference< css::beans::XPropertySet >&, sal_Int32 nMode, double f1, double f2, double f3 ) throw( css::uno::RuntimeException );
+
+ virtual sal_Int32 SAL_CALL getWorkday( const css::uno::Reference< css::beans::XPropertySet >&, sal_Int32 nStartDate, sal_Int32 nDays, const css::uno::Any& aHDay ) override;
+ virtual double SAL_CALL getYearfrac( const css::uno::Reference< css::beans::XPropertySet >&, sal_Int32 nStartDate, sal_Int32 nEndDate, const css::uno::Any& aMode ) override;
+ virtual sal_Int32 SAL_CALL getEdate( const css::uno::Reference< css::beans::XPropertySet >&, sal_Int32 nStartDate, sal_Int32 nMonths ) override;
+ virtual sal_Int32 SAL_CALL getWeeknum( const css::uno::Reference< css::beans::XPropertySet >&, sal_Int32 nStartDate, sal_Int32 nMode ) override;
+ virtual sal_Int32 SAL_CALL getEomonth( const css::uno::Reference< css::beans::XPropertySet >&, sal_Int32 nStartDate, sal_Int32 nMonths ) override;
+ virtual sal_Int32 SAL_CALL getNetworkdays( const css::uno::Reference< css::beans::XPropertySet >&, sal_Int32 nStartDate, sal_Int32 nEndDate, const css::uno::Any& aHDay ) override;
+
+ virtual sal_Int32 SAL_CALL getIseven( sal_Int32 nVal ) override;
+ virtual sal_Int32 SAL_CALL getIsodd( sal_Int32 nVal ) override;
+
+ virtual double SAL_CALL getMultinomial( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const css::uno::Sequence< css::uno::Sequence< sal_Int32 > >& aVLst, const css::uno::Sequence< css::uno::Any >& aOptVLst ) override;
+ virtual double SAL_CALL getSeriessum( double fX, double fN, double fM, const css::uno::Sequence< css::uno::Sequence< double > >& aCoeffList ) override;
+ virtual double SAL_CALL getQuotient( double fNum, double fDenum ) override;
+
+ virtual double SAL_CALL getMround( double fNum, double fMult ) override;
+ virtual double SAL_CALL getSqrtpi( double fNum ) override;
+
+ virtual double SAL_CALL getRandbetween( double fMin, double fMax ) override;
+
+ virtual double SAL_CALL getGcd( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const css::uno::Sequence< css::uno::Sequence< double > >& aVLst, const css::uno::Sequence< css::uno::Any >& aOptVLst ) override;
+ virtual double SAL_CALL getLcm( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const css::uno::Sequence< css::uno::Sequence< double > >& aVLst, const css::uno::Sequence< css::uno::Any >& aOptVLst ) override;
+
+ virtual double SAL_CALL getBesseli( double fNum, sal_Int32 nOrder ) override;
+ virtual double SAL_CALL getBesselj( double fNum, sal_Int32 nOrder ) override;
+ virtual double SAL_CALL getBesselk( double fNum, sal_Int32 nOrder ) override;
+ virtual double SAL_CALL getBessely( double fNum, sal_Int32 nOrder ) override;
+
+ virtual OUString SAL_CALL getBin2Oct( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const OUString& aNum, const css::uno::Any& rPlaces ) override;
+ virtual double SAL_CALL getBin2Dec( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getBin2Hex( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const OUString& aNum, const css::uno::Any& rPlaces ) override;
+
+ virtual OUString SAL_CALL getOct2Bin( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const OUString& aNum, const css::uno::Any& rPlaces ) override;
+ virtual double SAL_CALL getOct2Dec( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getOct2Hex( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const OUString& aNum, const css::uno::Any& rPlaces ) override;
+
+ virtual OUString SAL_CALL getDec2Bin( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 fNum, const css::uno::Any& rPlaces ) override;
+ virtual OUString SAL_CALL getDec2Oct( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 fNum, const css::uno::Any& rPlaces ) override;
+ virtual OUString SAL_CALL getDec2Hex( const css::uno::Reference< css::beans::XPropertySet >& xOpt, double fNum, const css::uno::Any& rPlaces ) override;
+
+ virtual OUString SAL_CALL getHex2Bin( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const OUString& aNum, const css::uno::Any& rPlaces ) override;
+ virtual double SAL_CALL getHex2Dec( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getHex2Oct( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const OUString& aNum, const css::uno::Any& rPlaces ) override;
+
+ virtual sal_Int32 SAL_CALL getDelta( const css::uno::Reference< css::beans::XPropertySet >& xOpt, double fNum1, const css::uno::Any& rNum2 ) override;
+
+ virtual double SAL_CALL getErf( const css::uno::Reference< css::beans::XPropertySet >& xOpt, double fLowerLimit, const css::uno::Any& rUpperLimit ) override;
+ virtual double SAL_CALL getErfc( double fLowerLimit ) override;
+
+ virtual sal_Int32 SAL_CALL getGestep( const css::uno::Reference< css::beans::XPropertySet >& xOpt, double fNum, const css::uno::Any& rStep ) override;
+
+ virtual double SAL_CALL getFactdouble( sal_Int32 nNum ) override;
+
+ virtual double SAL_CALL getImabs( const OUString& aNum ) override;
+ virtual double SAL_CALL getImaginary( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImpower( const OUString& aNum, double fPower ) override;
+ virtual double SAL_CALL getImargument( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImcos( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImdiv( const OUString& aDivident, const OUString& aDivisor ) override;
+ virtual OUString SAL_CALL getImexp( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImconjugate( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImln( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImlog10( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImlog2( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImproduct( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const css::uno::Sequence< css::uno::Sequence< OUString > >& aNum1, const css::uno::Sequence< css::uno::Any >& aNumList ) override;
+ virtual double SAL_CALL getImreal( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImsin( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImsub( const OUString& aNum1, const OUString& aNum2 ) override;
+ virtual OUString SAL_CALL getImsum( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const css::uno::Sequence< css::uno::Sequence< OUString > >& aNum1, const css::uno::Sequence< css::uno::Any >& aFollowingPars ) override;
+
+ virtual OUString SAL_CALL getImsqrt( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImtan( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImsec( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImcsc( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImcot( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImsinh( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImcosh( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImsech( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getImcsch( const OUString& aNum ) override;
+ virtual OUString SAL_CALL getComplex( double fReal, double fImaginary, const css::uno::Any& rSuffix ) override;
+
+ virtual double SAL_CALL getConvert( double fVal, const OUString& aFromUnit, const OUString& aToUnit ) override;
+
+ virtual double SAL_CALL getAmordegrc( const css::uno::Reference< css::beans::XPropertySet >&, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer, double fRestVal, double fPer, double fRate, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getAmorlinc( const css::uno::Reference< css::beans::XPropertySet >&, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer, double fRestVal, double fPer, double fRate, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getAccrint( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nIssue, sal_Int32 nFirstInter, sal_Int32 nSettle, double fRate, const css::uno::Any& rVal, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getAccrintm( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nIssue, sal_Int32 nSettle, double fRate, const css::uno::Any& rVal, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getReceived( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fInvest, double fDisc, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getDisc( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fPrice, double fRedemp, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getDuration( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fYield, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getEffect( double fNominal, sal_Int32 nPeriods ) override;
+ virtual double SAL_CALL getCumprinc( double fRate, sal_Int32 nNumPeriods, double fVal, sal_Int32 nStartPer, sal_Int32 nEndPer, sal_Int32 nPayType ) override;
+ virtual double SAL_CALL getCumipmt( double fRate, sal_Int32 nNumPeriods, double fVal, sal_Int32 nStartPer, sal_Int32 nEndPer, sal_Int32 nPayType ) override;
+ virtual double SAL_CALL getPrice( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield, double fRedemp, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getPricedisc( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fDisc, double fRedemp, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getPricemat( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, double fRate, double fYield, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getMduration( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fYield, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getNominal( double fRate, sal_Int32 nPeriods ) override;
+ virtual double SAL_CALL getDollarfr( double fDollarDec, sal_Int32 nFrac ) override;
+ virtual double SAL_CALL getDollarde( double fDollarFrac, sal_Int32 nFrac ) override;
+ virtual double SAL_CALL getYield( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice, double fRedemp, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getYielddisc( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fPrice, double fRedemp, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getYieldmat( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, double fRate, double fPrice, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getTbilleq( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fDisc ) override;
+ virtual double SAL_CALL getTbillprice( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fDisc ) override;
+ virtual double SAL_CALL getTbillyield( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fPrice ) override;
+ virtual double SAL_CALL getOddfprice( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, sal_Int32 nFirstCoup, double fRate, double fYield, double fRedemp, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getOddfyield( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, sal_Int32 nFirstCoup, double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getOddlprice( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastInterest, double fRate, double fYield, double fRedemp, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getOddlyield( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastInterest, double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, const css::uno::Any& rOptBase) override;
+ virtual double SAL_CALL getXirr( const css::uno::Reference< css::beans::XPropertySet >& xOpt, const css::uno::Sequence< css::uno::Sequence< double > >& rValues, const css::uno::Sequence< css::uno::Sequence< sal_Int32 > >& rDates, const css::uno::Any& rGuess ) override;
+ virtual double SAL_CALL getXnpv( double fRate, const css::uno::Sequence< css::uno::Sequence< double > >& rValues, const css::uno::Sequence< css::uno::Sequence< sal_Int32 > >& rDates ) override;
+ virtual double SAL_CALL getIntrate( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fInvest, double fRedemp, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getCoupncd( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getCoupdays( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getCoupdaysnc( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getCoupdaybs( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getCouppcd( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getCoupnum( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOptBase ) override;
+ virtual double SAL_CALL getFvschedule( double fPrinc, const css::uno::Sequence< css::uno::Sequence< double > >& rSchedule ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/analysis/analysisdefs.hxx b/scaddins/source/analysis/analysisdefs.hxx
new file mode 100644
index 000000000..09ba53752
--- /dev/null
+++ b/scaddins/source/analysis/analysisdefs.hxx
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <cmath>
+
+#define CHK_Freq ( nFreq != 1 && nFreq != 2 && nFreq != 4 )
+#define CHK_FINITE(d) if( !std::isfinite( d ) ) throw css::lang::IllegalArgumentException()
+#define RETURN_FINITE(d) if( !std::isfinite( d ) ) throw css::lang::IllegalArgumentException(); return d;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/analysis/analysishelper.cxx b/scaddins/source/analysis/analysishelper.cxx
new file mode 100644
index 000000000..405fdae9e
--- /dev/null
+++ b/scaddins/source/analysis/analysishelper.cxx
@@ -0,0 +1,2811 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+
+#include <string.h>
+#include <stdio.h>
+#include <o3tl/any.hxx>
+#include <rtl/math.hxx>
+#include <algorithm>
+#include <memory>
+#include "analysisdefs.hxx"
+#include "analysishelper.hxx"
+#include <analysis.hrc>
+#include <strings.hrc>
+#include "deffuncname.hxx"
+
+using namespace ::com::sun::star;
+using namespace sca::analysis;
+
+#define UNIQUE false // function name does not exist in Calc
+#define DOUBLE true // function name exists in Calc
+
+#define STDPAR false // all parameters are described
+#define INTPAR true // first parameter is internal
+
+#define FUNCDATA( FUNCNAME, DBL, OPT, NUMOFPAR, CAT ) \
+ { "get" #FUNCNAME, ANALYSIS_FUNCNAME_##FUNCNAME, ANALYSIS_##FUNCNAME, DBL, OPT, ANALYSIS_DEFFUNCNAME_##FUNCNAME, NUMOFPAR, CAT, nullptr }
+
+#define FUNCDATAS( FUNCNAME, DBL, OPT, NUMOFPAR, CAT, SUFFIX ) \
+ { "get" #FUNCNAME, ANALYSIS_FUNCNAME_##FUNCNAME, ANALYSIS_##FUNCNAME, DBL, OPT, ANALYSIS_DEFFUNCNAME_##FUNCNAME, NUMOFPAR, CAT, SUFFIX }
+
+const FuncDataBase pFuncDatas[] =
+{
+ // UNIQUE or INTPAR or
+ // function name DOUBLE STDPAR # of param category
+ FUNCDATA( Workday, UNIQUE, INTPAR, 3, FDCategory::DateTime ),
+ FUNCDATA( Yearfrac, UNIQUE, INTPAR, 3, FDCategory::DateTime ),
+ FUNCDATA( Edate, UNIQUE, INTPAR, 2, FDCategory::DateTime ),
+ FUNCDATAS( Weeknum, DOUBLE, INTPAR, 2, FDCategory::DateTime, "_EXCEL2003" ),
+ FUNCDATA( Eomonth, UNIQUE, INTPAR, 2, FDCategory::DateTime ),
+ FUNCDATAS( Networkdays, DOUBLE, INTPAR, 3, FDCategory::DateTime, "_EXCEL2003" ),
+ FUNCDATA( Iseven, DOUBLE, STDPAR, 1, FDCategory::Inf ),
+ FUNCDATA( Isodd, DOUBLE, STDPAR, 1, FDCategory::Inf ),
+ FUNCDATA( Multinomial, UNIQUE, STDPAR, 1, FDCategory::Math ),
+ FUNCDATA( Seriessum, UNIQUE, STDPAR, 4, FDCategory::Math ),
+ FUNCDATA( Quotient, UNIQUE, STDPAR, 2, FDCategory::Math ),
+ FUNCDATA( Mround, UNIQUE, STDPAR, 2, FDCategory::Math ),
+ FUNCDATA( Sqrtpi, UNIQUE, STDPAR, 1, FDCategory::Math ),
+ FUNCDATA( Randbetween, UNIQUE, STDPAR, 2, FDCategory::Math ),
+ FUNCDATAS( Gcd, DOUBLE, INTPAR, 1, FDCategory::Math, "_EXCEL2003" ),
+ FUNCDATAS( Lcm, DOUBLE, INTPAR, 1, FDCategory::Math, "_EXCEL2003" ),
+ FUNCDATA( Besseli, UNIQUE, STDPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Besselj, UNIQUE, STDPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Besselk, UNIQUE, STDPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Bessely, UNIQUE, STDPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Bin2Oct, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Bin2Dec, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Bin2Hex, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Oct2Bin, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Oct2Dec, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Oct2Hex, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Dec2Bin, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Dec2Hex, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Dec2Oct, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Hex2Bin, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Hex2Dec, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Hex2Oct, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Delta, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Erf, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Erfc, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Gestep, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Factdouble, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imabs, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imaginary, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Impower, UNIQUE, STDPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Imargument, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imcos, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imdiv, UNIQUE, STDPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Imexp, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imconjugate, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imln, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imlog10, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imlog2, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Improduct, UNIQUE, INTPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Imreal, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imsin, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imsub, UNIQUE, STDPAR, 2, FDCategory::Tech ),
+ FUNCDATA( Imsqrt, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imsum, UNIQUE, INTPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imtan, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imsec, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imcsc, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imcot, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imsinh, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imcosh, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imsech, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Imcsch, UNIQUE, STDPAR, 1, FDCategory::Tech ),
+ FUNCDATA( Complex, UNIQUE, STDPAR, 3, FDCategory::Tech ),
+ FUNCDATA( Convert, UNIQUE, STDPAR, 3, FDCategory::Tech ),
+ FUNCDATA( Amordegrc, UNIQUE, INTPAR, 7, FDCategory::Finance ),
+ FUNCDATA( Amorlinc, UNIQUE, INTPAR, 7, FDCategory::Finance ),
+ FUNCDATA( Accrint, UNIQUE, INTPAR, 7, FDCategory::Finance ),
+ FUNCDATA( Accrintm, UNIQUE, INTPAR, 5, FDCategory::Finance ),
+ FUNCDATA( Received, UNIQUE, INTPAR, 5, FDCategory::Finance ),
+ FUNCDATA( Disc, UNIQUE, INTPAR, 5, FDCategory::Finance ),
+ FUNCDATA( Duration, UNIQUE, INTPAR, 6, FDCategory::Finance ),
+ FUNCDATA( Effect, DOUBLE, STDPAR, 2, FDCategory::Finance ),
+ FUNCDATA( Cumprinc, DOUBLE, STDPAR, 6, FDCategory::Finance ),
+ FUNCDATA( Cumipmt, DOUBLE, STDPAR, 6, FDCategory::Finance ),
+ FUNCDATA( Price, UNIQUE, INTPAR, 7, FDCategory::Finance ),
+ FUNCDATA( Pricedisc, UNIQUE, INTPAR, 5, FDCategory::Finance ),
+ FUNCDATA( Pricemat, UNIQUE, INTPAR, 6, FDCategory::Finance ),
+ FUNCDATA( Mduration, UNIQUE, INTPAR, 6, FDCategory::Finance ),
+ FUNCDATA( Nominal, DOUBLE, STDPAR, 2, FDCategory::Finance ),
+ FUNCDATA( Dollarfr, UNIQUE, STDPAR, 2, FDCategory::Finance ),
+ FUNCDATA( Dollarde, UNIQUE, STDPAR, 2, FDCategory::Finance ),
+ FUNCDATA( Yield, UNIQUE, INTPAR, 7, FDCategory::Finance ),
+ FUNCDATA( Yielddisc, UNIQUE, INTPAR, 5, FDCategory::Finance ),
+ FUNCDATA( Yieldmat, UNIQUE, INTPAR, 6, FDCategory::Finance ),
+ FUNCDATA( Tbilleq, UNIQUE, INTPAR, 3, FDCategory::Finance ),
+ FUNCDATA( Tbillprice, UNIQUE, INTPAR, 3, FDCategory::Finance ),
+ FUNCDATA( Tbillyield, UNIQUE, INTPAR, 3, FDCategory::Finance ),
+ FUNCDATA( Oddfprice, UNIQUE, INTPAR, 9, FDCategory::Finance ),
+ FUNCDATA( Oddfyield, UNIQUE, INTPAR, 9, FDCategory::Finance ),
+ FUNCDATA( Oddlprice, UNIQUE, INTPAR, 8, FDCategory::Finance ),
+ FUNCDATA( Oddlyield, UNIQUE, INTPAR, 8, FDCategory::Finance ),
+ FUNCDATA( Xirr, UNIQUE, INTPAR, 3, FDCategory::Finance ),
+ FUNCDATA( Xnpv, UNIQUE, STDPAR, 3, FDCategory::Finance ),
+ FUNCDATA( Intrate, UNIQUE, INTPAR, 5, FDCategory::Finance ),
+ FUNCDATA( Coupncd, UNIQUE, INTPAR, 4, FDCategory::Finance ),
+ FUNCDATA( Coupdays, UNIQUE, INTPAR, 4, FDCategory::Finance ),
+ FUNCDATA( Coupdaysnc, UNIQUE, INTPAR, 4, FDCategory::Finance ),
+ FUNCDATA( Coupdaybs, UNIQUE, INTPAR, 4, FDCategory::Finance ),
+ FUNCDATA( Couppcd, UNIQUE, INTPAR, 4, FDCategory::Finance ),
+ FUNCDATA( Coupnum, UNIQUE, INTPAR, 4, FDCategory::Finance ),
+ FUNCDATA( Fvschedule, UNIQUE, STDPAR, 2, FDCategory::Finance )
+};
+#undef FUNCDATA
+
+namespace sca::analysis {
+
+sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
+{
+ if( (nMonth == 2) && IsLeapYear( nYear ) )
+ return 29;
+ static const sal_uInt16 aDaysInMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ return aDaysInMonth[ nMonth ];
+}
+
+
+/**
+ * Convert a date to a count of days starting from 01/01/0001
+ *
+ * The internal representation of a Date used in this Addin
+ * is the number of days between 01/01/0001 and the date
+ * this function converts a Day , Month, Year representation
+ * to this internal Date value.
+ *
+ */
+
+sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
+{
+ sal_Int32 nDays = (static_cast<sal_Int32>(nYear)-1) * 365;
+ nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
+
+ for( sal_uInt16 i = 1; i < nMonth; i++ )
+ nDays += DaysInMonth(i,nYear);
+ nDays += nDay;
+
+ return nDays;
+}
+
+
+/**
+ * Convert a count of days starting from 01/01/0001 to a date
+ *
+ * The internal representation of a Date used in this Addin
+ * is the number of days between 01/01/0001 and the date
+ * this function converts this internal Date value
+ * to a Day , Month, Year representation of a Date.
+ *
+ */
+
+void DaysToDate( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
+{
+ if( nDays < 0 )
+ throw lang::IllegalArgumentException();
+
+ sal_Int32 nTempDays;
+ sal_Int32 i = 0;
+ bool bCalc;
+
+ do
+ {
+ nTempDays = nDays;
+ rYear = static_cast<sal_uInt16>((nTempDays / 365) - i);
+ nTempDays -= (static_cast<sal_Int32>(rYear) -1) * 365;
+ nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
+ bCalc = false;
+ if ( nTempDays < 1 )
+ {
+ i++;
+ bCalc = true;
+ }
+ else
+ {
+ if ( nTempDays > 365 )
+ {
+ if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
+ {
+ i--;
+ bCalc = true;
+ }
+ }
+ }
+ }
+ while ( bCalc );
+
+ rMonth = 1;
+ while ( nTempDays > DaysInMonth( rMonth, rYear ) )
+ {
+ nTempDays -= DaysInMonth( rMonth, rYear );
+ rMonth++;
+ }
+ rDay = static_cast<sal_uInt16>(nTempDays);
+}
+
+
+/**
+ * Get the null date used by the spreadsheet document
+ *
+ * The internal representation of a Date used in this Addin
+ * is the number of days between 01/01/0001 and the date
+ * this function returns this internal Date value for the document null date
+ *
+ */
+
+sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOpt )
+{
+ if( xOpt.is() )
+ {
+ try
+ {
+ uno::Any aAny = xOpt->getPropertyValue( "NullDate" );
+ util::Date aDate;
+ if( aAny >>= aDate )
+ return DateToDays( aDate.Day, aDate.Month, aDate.Year );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+
+ // no null date available -> no calculations possible
+ throw uno::RuntimeException();
+}
+
+
+sal_Int32 GetDiffDate360(
+ sal_uInt16 nDay1, sal_uInt16 nMonth1, sal_uInt16 nYear1, bool bLeapYear1,
+ sal_uInt16 nDay2, sal_uInt16 nMonth2, sal_uInt16 nYear2,
+ bool bUSAMethod )
+{
+ if( nDay1 == 31 )
+ nDay1--;
+ else if( bUSAMethod && ( nMonth1 == 2 && ( nDay1 == 29 || ( nDay1 == 28 && !bLeapYear1 ) ) ) )
+ nDay1 = 30;
+
+ if( nDay2 == 31 )
+ {
+ if( bUSAMethod && nDay1 != 30 )
+ {
+ nDay2 = 1;
+ if( nMonth2 == 12 )
+ {
+ nYear2++;
+ nMonth2 = 1;
+ }
+ else
+ nMonth2++;
+ }
+ else
+ nDay2 = 30;
+ }
+
+ return nDay2 + nMonth2 * 30 + nYear2 * 360 - nDay1 - nMonth1 * 30 - nYear1 * 360;
+}
+
+
+sal_Int32 GetDiffDate360( sal_Int32 nNullDate, sal_Int32 nDate1, sal_Int32 nDate2, bool bUSAMethod )
+{
+ nDate1 += nNullDate;
+ nDate2 += nNullDate;
+
+ sal_uInt16 nDay1, nMonth1, nYear1, nDay2, nMonth2, nYear2;
+
+ DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
+ DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
+
+ return GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ), nDay2, nMonth2, nYear2, bUSAMethod );
+}
+
+
+sal_Int32 GetDaysInYears( sal_uInt16 nYear1, sal_uInt16 nYear2 )
+{
+ sal_uInt16 nLeaps = 0;
+ for( sal_uInt16 n = nYear1 ; n <= nYear2 ; n++ )
+ {
+ if( IsLeapYear( n ) )
+ nLeaps++;
+ }
+
+ sal_uInt32 nSum = 1;
+ nSum += nYear2;
+ nSum -= nYear1;
+ nSum *= 365;
+ nSum += nLeaps;
+
+ return nSum;
+}
+
+
+sal_Int32 GetDiffDate( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
+ sal_Int32* pOptDaysIn1stYear )
+{
+ bool bNeg = nStartDate > nEndDate;
+
+ if( bNeg )
+ {
+ sal_Int32 n = nEndDate;
+ nEndDate = nStartDate;
+ nStartDate = n;
+ }
+
+ sal_Int32 nRet;
+
+ switch( nMode )
+ {
+ case 0: // 0=USA (NASD) 30/360
+ case 4: // 4=Europe 30/360
+ {
+ sal_uInt16 nD1, nM1, nY1, nD2, nM2, nY2;
+
+ nStartDate += nNullDate;
+ nEndDate += nNullDate;
+
+ DaysToDate( nStartDate, nD1, nM1, nY1 );
+ DaysToDate( nEndDate, nD2, nM2, nY2 );
+
+ bool bLeap = IsLeapYear( nY1 );
+ sal_Int32 nDays, nMonths;
+
+ nMonths = nM2 - nM1;
+ nDays = nD2 - nD1;
+
+ nMonths += ( nY2 - nY1 ) * 12;
+
+ nRet = nMonths * 30 + nDays;
+ if( nMode == 0 && nM1 == 2 && nM2 != 2 && nY1 == nY2 )
+ nRet -= bLeap? 1 : 2;
+
+ if( pOptDaysIn1stYear )
+ *pOptDaysIn1stYear = 360;
+ }
+ break;
+ case 1: // 1=exact/exact
+ if( pOptDaysIn1stYear )
+ {
+ sal_uInt16 nD, nM, nY;
+
+ DaysToDate( nStartDate + nNullDate, nD, nM, nY );
+
+ *pOptDaysIn1stYear = IsLeapYear( nY )? 366 : 365;
+ }
+ nRet = nEndDate - nStartDate;
+ break;
+ case 2: // 2=exact/360
+ nRet = nEndDate - nStartDate;
+ if( pOptDaysIn1stYear )
+ *pOptDaysIn1stYear = 360;
+ break;
+ case 3: //3=exact/365
+ nRet = nEndDate - nStartDate;
+ if( pOptDaysIn1stYear )
+ *pOptDaysIn1stYear = 365;
+ break;
+ default:
+ throw lang::IllegalArgumentException();
+ }
+
+ return bNeg? -nRet : nRet;
+}
+
+
+double GetYearDiff( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode )
+{
+ sal_Int32 nDays1stYear;
+ sal_Int32 nTotalDays = GetDiffDate( nNullDate, nStartDate, nEndDate, nMode, &nDays1stYear );
+
+ return double( nTotalDays ) / double( nDays1stYear );
+}
+
+
+sal_Int32 GetDaysInYear( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nMode )
+{
+ switch( nMode )
+ {
+ case 0: // 0=USA (NASD) 30/360
+ case 2: // 2=exact/360
+ case 4: // 4=Europe 30/360
+ return 360;
+ case 1: // 1=exact/exact
+ {
+ sal_uInt16 nD, nM, nY;
+ nDate += nNullDate;
+ DaysToDate( nDate, nD, nM, nY );
+ return IsLeapYear( nY )? 366 : 365;
+ }
+ case 3: //3=exact/365
+ return 365;
+ default:
+ throw lang::IllegalArgumentException();
+ }
+}
+
+
+// tdf69569 making code compliant with change request for ODFF1.2 par 4.11.7.7
+/**
+ * Function GetYearFrac implements YEARFRAC as defined in:
+ * Open Document Format for Office Applications version 1.2 Part 2, par. 6.10.24
+ * The calculations are defined in:
+ * Open Document Format for Office Applications version 1.2 Part 2, par. 4.11.7
+ */
+double GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode )
+{
+ if( nStartDate == nEndDate )
+ return 0.0; // nothing to do...
+
+ if( nStartDate > nEndDate )
+ {
+ sal_Int32 n = nEndDate;
+ nEndDate = nStartDate;
+ nStartDate = n;
+ }
+
+ sal_Int32 nDate1 = nStartDate + nNullDate;
+ sal_Int32 nDate2 = nEndDate + nNullDate;
+
+ sal_uInt16 nDay1, nDay2;
+ sal_uInt16 nMonth1, nMonth2;
+ sal_uInt16 nYear1, nYear2;
+
+ DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
+ DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
+
+ // calculate days between nDate1 and nDate2
+ sal_Int32 nDayDiff;
+ switch( nMode )
+ {
+ case 0: // 0=USA (NASD) 30/360
+ if ( nDay1 == 31 )
+ {
+ nDay1--;
+ }
+ if ( nDay1 == 30 && nDay2 == 31 )
+ {
+ nDay2--;
+ }
+ else
+ {
+ if ( nMonth1 == 2 && nDay1 == ( IsLeapYear( nYear1 ) ? 29 : 28 ) )
+ {
+ nDay1 = 30;
+ if ( nMonth2 == 2 && nDay2 == ( IsLeapYear( nYear2 ) ? 29 : 28 ) )
+ {
+ nDay2 = 30;
+ }
+ }
+ }
+ nDayDiff = ( nYear2 - nYear1 ) * 360 + ( nMonth2 - nMonth1 ) * 30 + ( nDay2 - nDay1 );
+ break;
+ case 1: // 1=exact/exact
+ case 2: // 2=exact/360
+ case 3: // 3=exact/365
+ nDayDiff = nDate2 - nDate1;
+ break;
+ case 4: // 4=Europe 30/360
+ if ( nDay1 == 31 )
+ {
+ nDay1--;
+ }
+ if ( nDay2 == 31 )
+ {
+ nDay2--;
+ }
+ nDayDiff = ( nYear2 - nYear1 ) * 360 + ( nMonth2 - nMonth1 ) * 30 + ( nDay2 - nDay1 );
+ break;
+ default:
+ throw lang::IllegalArgumentException();
+ }
+
+ //calculate days in year
+ double nDaysInYear;
+ switch( nMode )
+ {
+ case 0: // 0=USA (NASD) 30/360
+ case 2: // 2=exact/360
+ case 4: // 4=Europe 30/360
+ nDaysInYear = 360;
+ break;
+ case 1: // 1=exact/exact
+ {
+ const bool isYearDifferent = ( nYear1 != nYear2 );
+ // ODFv1.2 part 2 section 4.11.7.7.7
+ if ( isYearDifferent &&
+ ( ( nYear2 != nYear1 + 1 ) ||
+ ( nMonth1 < nMonth2 ) ||
+ ( nMonth1 == nMonth2 && nDay1 < nDay2 ) ) )
+ {
+ // return average of days in year between nDate1 and nDate2, inclusive
+ sal_Int32 nDayCount = 0;
+ for ( sal_uInt16 i = nYear1; i <= nYear2; i++ )
+ nDayCount += ( IsLeapYear( i ) ? 366 : 365 );
+
+ nDaysInYear = static_cast<double>(nDayCount) / static_cast<double>( nYear2 - nYear1 + 1 );
+ }
+ else
+ {
+ // as a consequence, !isYearDifferent or
+ // nYear2 == nYear + 1 and (nMonth1 > nMonth2 or
+ // (nMonth1 == nMonth2 and nDay1 >= nDay2))
+ assert( ( !isYearDifferent ||
+ ( nYear1 + 1 == nYear2 &&
+ ( nMonth1 > nMonth2 ||
+ ( nMonth1 == nMonth2 || nDay1 >= nDay2 ) ) ) ) );
+
+ // ODFv1.2 part 2 section 4.11.7.7.8 (CHANGE REQUEST PENDING, see tdf6959)
+ if ( !isYearDifferent && IsLeapYear( nYear1 ) )
+ {
+ nDaysInYear = 366;
+ }
+ else
+ {
+ // ODFv1.2 part 2 section 4.11.7.7.9/10 (CHANGE REQUEST PENDING, see tdf69569)
+ // we need to determine whether there is a 29 February
+ // between nDate1 (inclusive) and nDate2 (inclusive)
+ // the case of nYear1 == nYear2 is adequately tested in previous test
+ if( isYearDifferent &&
+ ( ( IsLeapYear( nYear1 ) &&
+ ( ( nMonth1 < 2 ) || ( ( nMonth1 == 2 ) && ( nDay1 <= 29 ) ) ) ) ||
+ ( IsLeapYear( nYear2 ) &&
+ ( nMonth2 > 2 || ( ( nMonth2 == 2 ) && ( nDay2 == 29 ) ) ) ) ) )
+ {
+ nDaysInYear = 366;
+ }
+ else
+ {
+ nDaysInYear = 365;
+ }
+ }
+ }
+ }
+ break;
+ case 3: // 3=exact/365
+ nDaysInYear = 365;
+ break;
+ // coverity[dead_error_begin] - following conditions exist to avoid compiler warning
+ default:
+ throw lang::IllegalArgumentException();
+ }
+
+ return double( nDayDiff ) / nDaysInYear;
+}
+
+double BinomialCoefficient( double n, double k )
+{
+ // This method is a copy of BinomKoeff()
+ // found in sc/source/core/tool/interpr3.cxx
+
+ double nVal = 0.0;
+ k = ::rtl::math::approxFloor(k);
+ if (n < k)
+ nVal = 0.0;
+ else if (k == 0.0)
+ nVal = 1.0;
+ else
+ {
+ nVal = n/k;
+ n--;
+ k--;
+ while (k > 0.0)
+ {
+ nVal *= n/k;
+ k--;
+ n--;
+ }
+ }
+ return nVal;
+}
+
+double GetGcd( double f1, double f2 )
+{
+ double f = fmod( f1, f2 );
+ while( f > 0.0 )
+ {
+ f1 = f2;
+ f2 = f;
+ f = fmod( f1, f2 );
+ }
+
+ return f2;
+}
+
+
+double ConvertToDec( const OUString& aStr, sal_uInt16 nBase, sal_uInt16 nCharLim )
+{
+ if ( nBase < 2 || nBase > 36 )
+ throw lang::IllegalArgumentException();
+
+ sal_uInt32 nStrLen = aStr.getLength();
+ if( nStrLen > nCharLim )
+ throw lang::IllegalArgumentException();
+ else if( !nStrLen )
+ return 0.0;
+
+ double fVal = 0.0;
+
+ const sal_Unicode* p = aStr.getStr();
+
+ sal_uInt16 nFirstDig = 0;
+ bool bFirstDig = true;
+ double fBase = nBase;
+
+ while ( *p )
+ {
+ sal_uInt16 n;
+
+ if( '0' <= *p && *p <= '9' )
+ n = *p - '0';
+ else if( 'A' <= *p && *p <= 'Z' )
+ n = 10 + ( *p - 'A' );
+ else if ( 'a' <= *p && *p <= 'z' )
+ n = 10 + ( *p - 'a' );
+ else
+ n = nBase;
+
+ if( n >= nBase )
+ throw lang::IllegalArgumentException(); // illegal char!
+
+ if( bFirstDig )
+ {
+ bFirstDig = false;
+ nFirstDig = n;
+ }
+ fVal = fVal * fBase + double( n );
+
+ p++;
+
+ }
+
+ if( nStrLen == nCharLim && !bFirstDig && (nFirstDig >= nBase / 2) )
+ { // handling negative values
+ fVal = ( pow( double( nBase ), double( nCharLim ) ) - fVal ); // complement
+ fVal *= -1.0;
+ }
+
+ return fVal;
+}
+
+
+static char GetMaxChar( sal_uInt16 nBase )
+{
+ const char* const c = "--123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ return c[ nBase ];
+}
+
+
+OUString ConvertFromDec( double fNum, double fMin, double fMax, sal_uInt16 nBase,
+ sal_Int32 nPlaces, sal_Int32 nMaxPlaces, bool bUsePlaces )
+{
+ fNum = ::rtl::math::approxFloor( fNum );
+ fMin = ::rtl::math::approxFloor( fMin );
+ fMax = ::rtl::math::approxFloor( fMax );
+
+ if( fNum < fMin || fNum > fMax || ( bUsePlaces && ( nPlaces <= 0 || nPlaces > nMaxPlaces ) ) )
+ throw lang::IllegalArgumentException();
+
+ sal_Int64 nNum = static_cast< sal_Int64 >( fNum );
+ bool bNeg = nNum < 0;
+ if( bNeg )
+ nNum = sal_Int64( pow( double( nBase ), double( nMaxPlaces ) ) ) + nNum;
+
+ OUString aRet(OUString::number(nNum, nBase).toAsciiUpperCase());
+
+
+ if( bUsePlaces )
+ {
+ sal_Int32 nLen = aRet.getLength();
+ if( !bNeg && nLen > nPlaces )
+ {
+ throw lang::IllegalArgumentException();
+ }
+ else if( ( bNeg && nLen < nMaxPlaces ) || ( !bNeg && nLen < nPlaces ) )
+ {
+ sal_Int32 nLeft = nPlaces - nLen;
+ std::unique_ptr<char[]> p( new char[ nLeft + 1 ] );
+ memset( p.get(), bNeg ? GetMaxChar( nBase ) : '0', nLeft );
+ p[ nLeft ] = 0x00;
+ aRet = OUString( p.get(), nLeft, RTL_TEXTENCODING_MS_1252 ) + aRet;
+ }
+ }
+
+ return aRet;
+}
+
+double Erf( double x )
+{
+ return std::erf(x);
+}
+
+double Erfc( double x )
+{
+ return std::erfc(x);
+}
+
+static bool IsNum( sal_Unicode c )
+{
+ return c >= '0' && c <= '9';
+}
+
+
+static bool IsComma( sal_Unicode c )
+{
+ return c == '.' || c == ',';
+}
+
+
+static bool IsExpStart( sal_Unicode c )
+{
+ return c == 'e' || c == 'E';
+}
+
+
+static bool IsImagUnit( sal_Unicode c )
+{
+ return c == 'i' || c == 'j';
+}
+
+
+static sal_uInt16 GetVal( sal_Unicode c )
+{
+ return sal_uInt16( c - '0' );
+}
+
+
+bool ParseDouble( const sal_Unicode*& rp, double& rRet )
+{
+ double fInt = 0.0;
+ double fFrac = 0.0;
+ double fMult = 0.1; // multiplier to multiply digits with, when adding fractional ones
+ sal_Int32 nExp = 0;
+ sal_Int32 nMaxExp = 307;
+ sal_uInt16 nDigCnt = 18; // max. number of digits to read in, rest doesn't matter
+
+ enum State { S_End = 0, S_Sign, S_IntStart, S_Int, S_IgnoreIntDigs, S_Frac, S_IgnoreFracDigs, S_ExpSign, S_Exp };
+
+ State eS = S_Sign;
+
+ bool bNegNum = false;
+ bool bNegExp = false;
+
+ const sal_Unicode* p = rp;
+ sal_Unicode c;
+
+ while( eS )
+ {
+ c = *p;
+ switch( eS )
+ {
+ case S_Sign:
+ if( IsNum( c ) )
+ {
+ fInt = GetVal( c );
+ nDigCnt--;
+ eS = S_Int;
+ }
+ else if( c == '-' )
+ {
+ bNegNum = true;
+ eS = S_IntStart;
+ }
+ else if( c == '+' )
+ eS = S_IntStart;
+ else if( IsComma( c ) )
+ eS = S_Frac;
+ else
+ return false;
+ break;
+ case S_IntStart:
+ if( IsNum( c ) )
+ {
+ fInt = GetVal( c );
+ nDigCnt--;
+ eS = S_Int;
+ }
+ else if( IsComma( c ) )
+ eS = S_Frac;
+ else if( IsImagUnit( c ) )
+ {
+ rRet = 0.0;
+ return true;
+ }
+ else
+ return false;
+ break;
+ case S_Int:
+ if( IsNum( c ) )
+ {
+ fInt *= 10.0;
+ fInt += double( GetVal( c ) );
+ nDigCnt--;
+ if( !nDigCnt )
+ eS = S_IgnoreIntDigs;
+ }
+ else if( IsComma( c ) )
+ eS = S_Frac;
+ else if( IsExpStart( c ) )
+ eS = S_ExpSign;
+ else
+ eS = S_End;
+ break;
+ case S_IgnoreIntDigs:
+ if( IsNum( c ) )
+ nExp++; // just multiply num with 10... ;-)
+ else if( IsComma( c ) )
+ eS = S_Frac;
+ else if( IsExpStart( c ) )
+ eS = S_ExpSign;
+ else
+ eS = S_End;
+ break;
+ case S_Frac:
+ if( IsNum( c ) )
+ {
+ fFrac += double( GetVal( c ) ) * fMult;
+ nDigCnt--;
+ if( nDigCnt )
+ fMult *= 0.1;
+ else
+ eS = S_IgnoreFracDigs;
+ }
+ else if( IsExpStart( c ) )
+ eS = S_ExpSign;
+ else
+ eS = S_End;
+ break;
+ case S_IgnoreFracDigs:
+ if( IsExpStart( c ) )
+ eS = S_ExpSign;
+ else if( !IsNum( c ) )
+ eS = S_End;
+ break;
+ case S_ExpSign:
+ if( IsNum( c ) )
+ {
+ nExp = GetVal( c );
+ eS = S_Exp;
+ }
+ else if( c == '-' )
+ {
+ bNegExp = true;
+ eS = S_Exp;
+ }
+ else if( c != '+' )
+ eS = S_End;
+ break;
+ case S_Exp:
+ if( IsNum( c ) )
+ {
+ nExp *= 10;
+ nExp += GetVal( c );
+ if( nExp > nMaxExp )
+ return false;
+ }
+ else
+ eS = S_End;
+ break;
+ // coverity[dead_error_begin] - following conditions exist to avoid compiler warning
+ case S_End:
+ break;
+ }
+
+ p++;
+ }
+
+ p--; // set pointer back to last
+ rp = p;
+
+ fInt += fFrac;
+
+ if (fInt != 0.0) // exact check; log10(0.0) may entail a pole error
+ {
+ sal_Int32 nLog10 = sal_Int32( log10( fInt ) );
+
+ if( bNegExp )
+ nExp = -nExp;
+
+ if( nLog10 + nExp > nMaxExp )
+ return false;
+
+ fInt = ::rtl::math::pow10Exp( fInt, nExp );
+ }
+
+ if( bNegNum )
+ fInt = -fInt;
+
+ rRet = fInt;
+
+ return true;
+}
+
+
+OUString GetString( double f, bool bLeadingSign, sal_uInt16 nMaxDig )
+{
+ const int nBuff = 256;
+ char aBuff[ nBuff + 1 ];
+ const char* pFormStr = bLeadingSign? "%+.*g" : "%.*g";
+ int nLen = snprintf( aBuff, nBuff, pFormStr, int( nMaxDig ), f );
+ // you never know which underlying implementation you get ...
+ aBuff[nBuff] = 0;
+ if ( nLen < 0 || nLen > nBuff )
+ nLen = strlen( aBuff );
+
+ OUString aRet( aBuff, nLen, RTL_TEXTENCODING_MS_1252 );
+
+ return aRet;
+}
+
+
+double GetAmordegrc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
+ double fRestVal, double fPer, double fRate, sal_Int32 nBase )
+{
+ sal_uInt32 nPer = sal_uInt32( fPer );
+ double fUsePer = 1.0 / fRate;
+ double fAmorCoeff;
+
+ if( fUsePer < 3.0 )
+ fAmorCoeff = 1.0;
+ else if( fUsePer < 5.0 )
+ fAmorCoeff = 1.5;
+ else if( fUsePer <= 6.0 )
+ fAmorCoeff = 2.0;
+ else
+ fAmorCoeff = 2.5;
+
+ fRate *= fAmorCoeff;
+ double fNRate = ::rtl::math::round( GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost );
+ fCost -= fNRate;
+ double fRest = fCost - fRestVal; // aboriginal cost - residual value - sum of all write-downs
+
+ for( sal_uInt32 n = 0 ; n < nPer ; n++ )
+ {
+ fNRate = ::rtl::math::round( fRate * fCost );
+ fRest -= fNRate;
+
+ if( fRest < 0.0 )
+ {
+ switch( nPer - n )
+ {
+ case 0:
+ case 1:
+ return ::rtl::math::round( fCost * 0.5 );
+ default:
+ return 0.0;
+ }
+ }
+
+ fCost -= fNRate;
+ }
+
+ return fNRate;
+}
+
+
+double GetAmorlinc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
+ double fRestVal, double fPer, double fRate, sal_Int32 nBase )
+{
+ sal_uInt32 nPer = sal_uInt32( fPer );
+ double fOneRate = fCost * fRate;
+ double fCostDelta = fCost - fRestVal;
+ double f0Rate = GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost;
+ sal_uInt32 nNumOfFullPeriods = sal_uInt32( ( fCost - fRestVal - f0Rate) / fOneRate );
+
+ double fResult = 0.0;
+ if( nPer == 0 )
+ fResult = f0Rate;
+ else if( nPer <= nNumOfFullPeriods )
+ fResult = fOneRate;
+ else if( nPer == nNumOfFullPeriods + 1 )
+ fResult = fCostDelta - fOneRate * nNumOfFullPeriods - f0Rate;
+
+ if ( fResult > 0.0 )
+ return fResult;
+ else
+ return 0.0;
+}
+
+
+double GetDuration( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup,
+ double fYield, sal_Int32 nFreq, sal_Int32 nBase )
+{
+ double fYearfrac = GetYearFrac( nNullDate, nSettle, nMat, nBase );
+ double fNumOfCoups = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
+ double fDur = 0.0;
+ const double f100 = 100.0;
+ fCoup *= f100 / double( nFreq ); // fCoup is used as cash flow
+ fYield /= nFreq;
+ fYield += 1.0;
+
+ double nDiff = fYearfrac * nFreq - fNumOfCoups;
+
+ double t;
+
+ for( t = 1.0 ; t < fNumOfCoups ; t++ )
+ fDur += ( t + nDiff ) * fCoup / pow( fYield, t + nDiff );
+
+ fDur += ( fNumOfCoups + nDiff ) * ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
+
+ double p = 0.0;
+ for( t = 1.0 ; t < fNumOfCoups ; t++ )
+ p += fCoup / pow( fYield, t + nDiff );
+
+ p += ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
+
+ fDur /= p;
+ fDur /= double( nFreq );
+
+ return fDur;
+}
+
+
+double GetYieldmat( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
+ double fRate, double fPrice, sal_Int32 nBase )
+{
+ double fIssMat = GetYearFrac( nNullDate, nIssue, nMat, nBase );
+ double fIssSet = GetYearFrac( nNullDate, nIssue, nSettle, nBase );
+ double fSetMat = GetYearFrac( nNullDate, nSettle, nMat, nBase );
+
+ double y = 1.0 + fIssMat * fRate;
+ y /= fPrice / 100.0 + fIssSet * fRate;
+ y--;
+ y /= fSetMat;
+
+ return y;
+}
+
+
+double GetOddfprice( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
+ sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fYield*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
+ sal_Int32 /*nBase*/ )
+{
+ // If you change this to not unconditionally throw, the
+ // SAL_WNOUNREACHABLE_CODE_PUSH/POP around the caller in
+ // financial.cxx can be removed.
+ throw uno::RuntimeException();
+}
+
+
+double getYield_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice,
+ double fRedemp, sal_Int32 nFreq, sal_Int32 nBase )
+{
+ double fRate = fCoup;
+ double fPriceN = 0.0;
+ double fYield1 = 0.0;
+ double fYield2 = 1.0;
+ double fPrice1 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield1, fRedemp, nFreq, nBase );
+ double fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
+ double fYieldN = ( fYield2 - fYield1 ) * 0.5;
+
+ for( sal_uInt32 nIter = 0 ; nIter < 100 && !rtl::math::approxEqual(fPriceN, fPrice) ; nIter++ )
+ {
+ fPriceN = getPrice_( nNullDate, nSettle, nMat, fRate, fYieldN, fRedemp, nFreq, nBase );
+
+ if( rtl::math::approxEqual(fPrice, fPrice1) )
+ return fYield1;
+ else if( rtl::math::approxEqual(fPrice, fPrice2) )
+ return fYield2;
+ else if( rtl::math::approxEqual(fPrice, fPriceN) )
+ return fYieldN;
+ else if( fPrice < fPrice2 )
+ {
+ fYield2 *= 2.0;
+ fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
+
+ fYieldN = ( fYield2 - fYield1 ) * 0.5;
+ }
+ else
+ {
+ if( fPrice < fPriceN )
+ {
+ fYield1 = fYieldN;
+ fPrice1 = fPriceN;
+ }
+ else
+ {
+ fYield2 = fYieldN;
+ fPrice2 = fPriceN;
+ }
+
+ fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
+ }
+ }
+
+ if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
+ throw lang::IllegalArgumentException(); // result not precise enough
+
+ return fYieldN;
+}
+
+
+double getPrice_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield,
+ double fRedemp, sal_Int32 nFreq, sal_Int32 nBase )
+{
+ double fFreq = nFreq;
+
+ double fE = GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
+ double fDSC_E = GetCoupdaysnc( nNullDate, nSettle, nMat, nFreq, nBase ) / fE;
+ double fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
+ double fA = GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
+
+ double fRet = fRedemp / ( pow( 1.0 + fYield / fFreq, fN - 1.0 + fDSC_E ) );
+ fRet -= 100.0 * fRate / fFreq * fA / fE;
+
+ double fT1 = 100.0 * fRate / fFreq;
+ double fT2 = 1.0 + fYield / fFreq;
+
+ for( double fK = 0.0 ; fK < fN ; fK++ )
+ fRet += fT1 / pow( fT2, fK + fDSC_E );
+
+ return fRet;
+}
+
+
+double GetOddfyield( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
+ sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fPrice*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
+ sal_Int32 /*nBase*/ )
+{
+ // If you change this to not unconditionally throw, the
+ // SAL_WNOUNREACHABLE_CODE_PUSH/POP around the caller in
+ // financial.cxx can be removed.
+ throw uno::RuntimeException();
+}
+
+
+double GetOddlprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
+ double fRate, double fYield, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase )
+{
+ double fFreq = double( nFreq );
+ double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
+ double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
+ double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
+
+ double p = fRedemp + fDCi * 100.0 * fRate / fFreq;
+ p /= fDSCi * fYield / fFreq + 1.0;
+ p -= fAi * 100.0 * fRate / fFreq;
+
+ return p;
+}
+
+
+double GetOddlyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
+ double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase )
+{
+ double fFreq = double( nFreq );
+ double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
+ double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
+ double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
+
+ double y = fRedemp + fDCi * 100.0 * fRate / fFreq;
+ y /= fPrice + fAi * 100.0 * fRate / fFreq;
+ y--;
+ y *= fFreq / fDSCi;
+
+ return y;
+}
+
+
+double GetPmt( double fRate, double fNper, double fPv, double fFv, sal_Int32 nPayType )
+{
+ double fPmt;
+ if( fRate == 0.0 )
+ fPmt = ( fPv + fFv ) / fNper;
+ else
+ {
+ double fTerm = pow( 1.0 + fRate, fNper );
+ if( nPayType > 0 )
+ fPmt = ( fFv * fRate / ( fTerm - 1.0 ) + fPv * fRate / ( 1.0 - 1.0 / fTerm ) ) / ( 1.0 + fRate );
+ else
+ fPmt = fFv * fRate / ( fTerm - 1.0 ) + fPv * fRate / ( 1.0 - 1.0 / fTerm );
+ }
+
+ return -fPmt;
+}
+
+
+double GetFv( double fRate, double fNper, double fPmt, double fPv, sal_Int32 nPayType )
+{
+ double fFv;
+ if( fRate == 0.0 )
+ fFv = fPv + fPmt * fNper;
+ else
+ {
+ double fTerm = pow( 1.0 + fRate, fNper );
+ if( nPayType > 0 )
+ fFv = fPv * fTerm + fPmt * ( 1.0 + fRate ) * ( fTerm - 1.0 ) / fRate;
+ else
+ fFv = fPv * fTerm + fPmt * ( fTerm - 1.0 ) / fRate;
+ }
+
+ return -fFv;
+}
+
+// financial functions COUP***
+
+// COUPPCD: find last coupon date before settlement (can be equal to settlement)
+/// @throws css::lang::IllegalArgumentException
+static void lcl_GetCouppcd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
+{
+ rDate = rMat;
+ rDate.setYear( rSettle.getYear() );
+ if( rDate < rSettle )
+ rDate.addYears( 1 );
+ while( rDate > rSettle )
+ rDate.addMonths( -12 / nFreq );
+}
+
+double GetCouppcd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
+{
+ if( nSettle >= nMat || CHK_Freq )
+ throw lang::IllegalArgumentException();
+
+ ScaDate aDate;
+ lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
+ return aDate.getDate( nNullDate );
+}
+
+// COUPNCD: find first coupon date after settlement (is never equal to settlement)
+/// @throws css::lang::IllegalArgumentException
+static void lcl_GetCoupncd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
+{
+ rDate = rMat;
+ rDate.setYear( rSettle.getYear() );
+ if( rDate > rSettle )
+ rDate.addYears( -1 );
+ while( rDate <= rSettle )
+ rDate.addMonths( 12 / nFreq );
+}
+
+double GetCoupncd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
+{
+ if( nSettle >= nMat || CHK_Freq )
+ throw lang::IllegalArgumentException();
+
+ ScaDate aDate;
+ lcl_GetCoupncd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
+ return aDate.getDate( nNullDate );
+}
+
+// COUPDAYBS: get day count: coupon date before settlement <-> settlement
+double GetCoupdaybs( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
+{
+ if( nSettle >= nMat || CHK_Freq )
+ throw lang::IllegalArgumentException();
+
+ ScaDate aSettle( nNullDate, nSettle, nBase );
+ ScaDate aDate;
+ lcl_GetCouppcd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
+ return ScaDate::getDiff( aDate, aSettle );
+}
+
+// COUPDAYSNC: get day count: settlement <-> coupon date after settlement
+double GetCoupdaysnc( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
+{
+ if( nSettle >= nMat || CHK_Freq )
+ throw lang::IllegalArgumentException();
+
+ if( (nBase != 0) && (nBase != 4) )
+ {
+ ScaDate aSettle( nNullDate, nSettle, nBase );
+ ScaDate aDate;
+ lcl_GetCoupncd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
+ return ScaDate::getDiff( aSettle, aDate );
+ }
+ return GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase ) - GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
+}
+
+// COUPDAYS: get day count: coupon date before settlement <-> coupon date after settlement
+double GetCoupdays( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
+{
+ if( nSettle >= nMat || CHK_Freq )
+ throw lang::IllegalArgumentException();
+
+ if( nBase == 1 )
+ {
+ ScaDate aDate;
+ lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
+ ScaDate aNextDate( aDate );
+ aNextDate.addMonths( 12 / nFreq );
+ return ScaDate::getDiff( aDate, aNextDate );
+ }
+ return static_cast< double >( GetDaysInYear( 0, 0, nBase ) ) / nFreq;
+}
+
+// COUPNUM: get count of coupon dates
+double GetCoupnum( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
+{
+ if( nSettle >= nMat || CHK_Freq )
+ throw lang::IllegalArgumentException();
+
+ ScaDate aMat( nNullDate, nMat, nBase );
+ ScaDate aDate;
+ lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), aMat, nFreq );
+ sal_uInt16 nMonths = (aMat.getYear() - aDate.getYear()) * 12 + aMat.getMonth() - aDate.getMonth();
+ return static_cast< double >( nMonths * nFreq / 12 );
+}
+
+FuncData::FuncData(const FuncDataBase& r) :
+ aIntName( OUString::createFromAscii( r.pIntName ) ),
+ pUINameID( r.pUINameID ),
+ pDescrID( r.pDescrID ),
+ bDouble( r.bDouble ),
+ bWithOpt( r.bWithOpt ),
+ nParam( r.nNumOfParams ),
+ eCat( r.eCat )
+{
+ if (r.pSuffix)
+ aSuffix = OUString::createFromAscii(r.pSuffix);
+
+ aCompList.resize(2);
+ aCompList[0] = OUString(r.pCompListID[0], strlen(r.pCompListID[0]), RTL_TEXTENCODING_UTF8);
+ aCompList[1] = OUString(r.pCompListID[1], strlen(r.pCompListID[1]), RTL_TEXTENCODING_UTF8);
+}
+
+sal_uInt16 FuncData::GetStrIndex( sal_uInt16 nParamNum ) const
+{
+ if( !bWithOpt )
+ nParamNum++;
+
+ if( nParamNum > nParam )
+ return nParam * 2;
+ else
+ return nParamNum * 2;
+}
+
+void InitFuncDataList(FuncDataList& rList)
+{
+ for(const auto & rFuncData : pFuncDatas)
+ rList.push_back(FuncData(rFuncData));
+}
+
+SortedIndividualInt32List::SortedIndividualInt32List()
+{
+}
+
+
+SortedIndividualInt32List::~SortedIndividualInt32List()
+{
+}
+
+
+void SortedIndividualInt32List::Insert( sal_Int32 nDay )
+{
+ sal_uInt32 nIndex = Count();
+ while( nIndex )
+ {
+ nIndex--;
+ sal_Int32 nRef = Get( nIndex );
+ if( nDay == nRef )
+ return;
+ else if( nDay > nRef )
+ {
+ maVector.insert( maVector.begin() + nIndex + 1, nDay );
+ return;
+ }
+ }
+ maVector.insert( maVector.begin(), nDay );
+}
+
+
+void SortedIndividualInt32List::Insert( sal_Int32 nDay, sal_Int32 nNullDate, bool bInsertOnWeekend )
+{
+ if( !nDay )
+ return;
+
+ nDay += nNullDate;
+ if( bInsertOnWeekend || (GetDayOfWeek( nDay ) < 5) )
+ Insert( nDay );
+}
+
+
+void SortedIndividualInt32List::Insert(
+ double fDay, sal_Int32 nNullDate, bool bInsertOnWeekend )
+{
+ if( (fDay < -2147483648.0) || (fDay > 2147483649.0) )
+ throw lang::IllegalArgumentException();
+ Insert( static_cast< sal_Int32 >( fDay ), nNullDate, bInsertOnWeekend );
+}
+
+
+bool SortedIndividualInt32List::Find( sal_Int32 nVal ) const
+{
+ sal_uInt32 nE = Count();
+
+ if( !nE || nVal < Get( 0 ) || nVal > Get( nE - 1 ) )
+ return false;
+
+ // linear search
+
+ for( sal_uInt32 n = 0 ; n < nE ; n++ )
+ {
+ sal_Int32 nRef = Get( n );
+
+ if( nRef == nVal )
+ return true;
+ else if( nRef > nVal )
+ return false;
+ }
+ return false;
+}
+
+
+void SortedIndividualInt32List::InsertHolidayList(
+ const ScaAnyConverter& rAnyConv,
+ const uno::Any& rHolAny,
+ sal_Int32 nNullDate,
+ bool bInsertOnWeekend )
+{
+ double fDay;
+ if( rAnyConv.getDouble( fDay, rHolAny ) )
+ Insert( fDay, nNullDate, bInsertOnWeekend );
+}
+
+
+void SortedIndividualInt32List::InsertHolidayList(
+ ScaAnyConverter& rAnyConv,
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ const uno::Any& rHolAny,
+ sal_Int32 nNullDate )
+{
+ rAnyConv.init( xOptions );
+ if( rHolAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
+ {
+ uno::Sequence< uno::Sequence< uno::Any > > aAnySeq;
+ if( !(rHolAny >>= aAnySeq) )
+ throw lang::IllegalArgumentException();
+
+ for( const uno::Sequence< uno::Any >& rSubSeq : std::as_const(aAnySeq) )
+ {
+ for( const uno::Any& rAny : rSubSeq )
+ InsertHolidayList( rAnyConv, rAny, nNullDate, false/*bInsertOnWeekend*/ );
+ }
+ }
+ else
+ InsertHolidayList( rAnyConv, rHolAny, nNullDate, false/*bInsertOnWeekend*/ );
+}
+
+
+void ScaDoubleList::Append(
+ const uno::Sequence< uno::Sequence< double > >& rValueSeq )
+{
+ for( const uno::Sequence< double >& rSubSeq : rValueSeq )
+ {
+ for( const double fValue : rSubSeq )
+ Append( fValue );
+ }
+}
+
+
+void ScaDoubleList::Append(
+ const uno::Sequence< uno::Sequence< sal_Int32 > >& rValueSeq )
+{
+ for( const uno::Sequence< sal_Int32 >& rSubSeq : rValueSeq )
+ {
+ for( const sal_Int32 nValue : rSubSeq )
+ Append( nValue );
+ }
+}
+
+void ScaDoubleList::Append(
+ const ScaAnyConverter& rAnyConv,
+ const uno::Any& rAny,
+ bool bIgnoreEmpty )
+{
+ if( auto s = o3tl::tryAccess<
+ css::uno::Sequence<css::uno::Sequence<css::uno::Any>>>(rAny) )
+ Append( rAnyConv, *s, bIgnoreEmpty );
+ else
+ {
+ double fValue;
+ if( rAnyConv.getDouble( fValue, rAny ) )
+ Append( fValue );
+ else if( !bIgnoreEmpty )
+ Append( 0.0 );
+ }
+}
+
+
+void ScaDoubleList::Append(
+ const ScaAnyConverter& rAnyConv,
+ const uno::Sequence< uno::Any >& rAnySeq,
+ bool bIgnoreEmpty )
+{
+ for( const uno::Any& rAny : rAnySeq )
+ Append( rAnyConv, rAny, bIgnoreEmpty );
+}
+
+
+void ScaDoubleList::Append(
+ const ScaAnyConverter& rAnyConv,
+ const uno::Sequence< uno::Sequence< uno::Any > >& rAnySeq,
+ bool bIgnoreEmpty )
+{
+ for( const uno::Sequence< uno::Any >& rArray : rAnySeq )
+ Append( rAnyConv, rArray, bIgnoreEmpty );
+}
+
+void ScaDoubleList::Append(
+ ScaAnyConverter& rAnyConv,
+ const uno::Reference< beans::XPropertySet >& xOpt,
+ const uno::Sequence< uno::Any >& rAnySeq )
+{
+ rAnyConv.init( xOpt );
+ Append( rAnyConv, rAnySeq, true/*bIgnoreEmpty*/ );
+}
+
+
+bool ScaDoubleList::CheckInsert( double ) const
+{
+ return true;
+}
+
+
+bool ScaDoubleListGT0::CheckInsert( double fValue ) const
+{
+ if( fValue < 0.0 )
+ throw lang::IllegalArgumentException();
+ return fValue > 0.0;
+}
+
+
+bool ScaDoubleListGE0::CheckInsert( double fValue ) const
+{
+ if( fValue < 0.0 )
+ throw lang::IllegalArgumentException();
+ return true;
+}
+
+
+Complex::Complex( const OUString& rStr )
+{
+ if( !ParseString( rStr, *this ) )
+ throw lang::IllegalArgumentException();
+}
+
+
+inline bool Complex::IsImagUnit( sal_Unicode c )
+{
+ return c == 'i' || c == 'j';
+}
+
+bool Complex::ParseString( const OUString& rStr, Complex& rCompl )
+{
+ rCompl.c = '\0'; // do not force a symbol, if only real part present
+
+ const sal_Unicode* pStr = rStr.getStr();
+
+ if( IsImagUnit( *pStr ) && rStr.getLength() == 1)
+ {
+ rCompl.r = 0.0;
+ rCompl.i = 1.0;
+ rCompl.c = *pStr;
+ return true;
+ }
+
+ double f;
+
+ if( !ParseDouble( pStr, f ) )
+ return false;
+
+ switch( *pStr )
+ {
+ case '-': // imag part follows
+ case '+':
+ {
+ double r = f;
+ if( IsImagUnit( pStr[ 1 ] ) )
+ {
+ rCompl.c = pStr[ 1 ];
+ if( pStr[ 2 ] == 0 )
+ {
+ rCompl.r = f;
+ rCompl.i = ( *pStr == '+' )? 1.0 : -1.0;
+ return true;
+ }
+ }
+ else if( ParseDouble( pStr, f ) && IsImagUnit( *pStr ) )
+ {
+ rCompl.c = *pStr;
+ pStr++;
+ if( *pStr == 0 )
+ {
+ rCompl.r = r;
+ rCompl.i = f;
+ return true;
+ }
+ }
+ }
+ break;
+ case 'j':
+ case 'i':
+ rCompl.c = *pStr;
+ pStr++;
+ if( *pStr == 0 )
+ {
+ rCompl.i = f;
+ rCompl.r = 0.0;
+ return true;
+ }
+ break;
+ case 0: // only real-part
+ rCompl.r = f;
+ rCompl.i = 0.0;
+ return true;
+ }
+
+ return false;
+}
+
+
+OUString Complex::GetString() const
+{
+ CHK_FINITE(r);
+ CHK_FINITE(i);
+ OUStringBuffer aRet;
+
+ bool bHasImag = i != 0.0;
+ bool bHasReal = !bHasImag || (r != 0.0);
+
+ if( bHasReal )
+ aRet.append(::GetString( r, false ));
+ if( bHasImag )
+ {
+ if( i == 1.0 )
+ {
+ if( bHasReal )
+ aRet.append('+');
+ }
+ else if( i == -1.0 )
+ aRet.append('-');
+ else
+ aRet.append(::GetString( i, bHasReal ));
+ aRet.append((c != 'j') ? 'i' : 'j');
+ }
+
+ return aRet.makeStringAndClear();
+}
+
+
+double Complex::Arg() const
+{
+ if( r == 0.0 && i == 0.0 )
+ throw lang::IllegalArgumentException();
+
+ double phi = acos( r / Abs() );
+
+ if( i < 0.0 )
+ phi = -phi;
+
+ return phi;
+}
+
+
+void Complex::Power( double fPower )
+{
+ if( r == 0.0 && i == 0.0 )
+ {
+ if( fPower <= 0 )
+ throw lang::IllegalArgumentException();
+ r = i = 0.0;
+ return;
+ }
+
+ double p, phi;
+
+ p = Abs();
+
+ phi = acos( r / p );
+ if( i < 0.0 )
+ phi = -phi;
+
+ p = pow( p, fPower );
+ phi *= fPower;
+
+ r = cos( phi ) * p;
+ i = sin( phi ) * p;
+}
+
+
+void Complex::Sqrt()
+{
+ static const double fMultConst = 0.7071067811865475; // ...2440084436210485 = 1/sqrt(2)
+ double p = Abs();
+ double i_ = sqrt( p - r ) * fMultConst;
+
+ r = sqrt( p + r ) * fMultConst;
+ i = ( i < 0.0 )? -i_ : i_;
+}
+
+
+void Complex::Sin()
+{
+ if( !::rtl::math::isValidArcArg( r ) )
+ throw lang::IllegalArgumentException();
+
+ if( i )
+ {
+ double r_;
+
+ r_ = sin( r ) * cosh( i );
+ i = cos( r ) * sinh( i );
+ r = r_;
+ }
+ else
+ r = sin( r );
+}
+
+
+void Complex::Cos()
+{
+ if( !::rtl::math::isValidArcArg( r ) )
+ throw lang::IllegalArgumentException();
+
+ if( i )
+ {
+ double r_;
+
+ r_ = cos( r ) * cosh( i );
+ i = -( sin( r ) * sinh( i ) );
+ r = r_;
+ }
+ else
+ r = cos( r );
+}
+
+
+void Complex::Div( const Complex& z )
+{
+ if( z.r == 0 && z.i == 0 )
+ throw lang::IllegalArgumentException();
+
+ double a1 = r;
+ double a2 = z.r;
+ double b1 = i;
+ double b2 = z.i;
+
+ double f = 1.0 / ( a2 * a2 + b2 * b2 );
+
+ r = ( a1 * a2 + b1 * b2 ) * f;
+ i = ( a2 * b1 - a1 * b2 ) * f;
+
+ if( !c ) c = z.c;
+}
+
+
+void Complex::Exp()
+{
+ double fE = exp( r );
+ r = fE * cos( i );
+ i = fE * sin( i );
+}
+
+
+void Complex::Ln()
+{
+ if( r == 0.0 && i == 0.0 )
+ throw lang::IllegalArgumentException();
+
+ double fAbs = Abs();
+ bool bNegi = i < 0.0;
+
+ i = acos( r / fAbs );
+
+ if( bNegi )
+ i = -i;
+
+ r = log( fAbs );
+}
+
+
+void Complex::Log10()
+{
+ Ln();
+ Mult( 0.434294481903251828 ); // * log10( e )
+}
+
+
+void Complex::Log2()
+{
+ Ln();
+ Mult( 1.442695040888963407 ); // * log2( e )
+}
+
+
+void Complex::Tan()
+{
+ if ( i )
+ {
+ if( !::rtl::math::isValidArcArg( 2.0 * r ) )
+ throw lang::IllegalArgumentException();
+ double fScale =1.0 / ( cos( 2.0 * r ) + cosh( 2.0 * i ));
+ r = sin( 2.0 * r ) * fScale;
+ i = sinh( 2.0 * i ) * fScale;
+ }
+ else
+ {
+ if( !::rtl::math::isValidArcArg( r ) )
+ throw lang::IllegalArgumentException();
+ r = tan( r );
+ }
+}
+
+
+void Complex::Sec()
+{
+ if( i )
+ {
+ if( !::rtl::math::isValidArcArg( 2 * r ) )
+ throw lang::IllegalArgumentException();
+ double fScale = 1.0 / (cosh( 2.0 * i) + cos ( 2.0 * r));
+ double r_;
+ r_ = 2.0 * cos( r ) * cosh( i ) * fScale;
+ i = 2.0 * sin( r ) * sinh( i ) * fScale;
+ r = r_;
+ }
+ else
+ {
+ if( !::rtl::math::isValidArcArg( r ) )
+ throw lang::IllegalArgumentException();
+ r = 1.0 / cos( r );
+ }
+}
+
+
+void Complex::Csc()
+{
+ if( i )
+ {
+ if( !::rtl::math::isValidArcArg( 2 * r ) )
+ throw lang::IllegalArgumentException();
+ double fScale = 1.0 / (cosh( 2.0 * i) - cos ( 2.0 * r));
+ double r_;
+ r_ = 2.0 * sin( r ) * cosh( i ) * fScale;
+ i = -2.0 * cos( r ) * sinh( i ) * fScale;
+ r = r_;
+ }
+ else
+ {
+ if( !::rtl::math::isValidArcArg( r ) )
+ throw lang::IllegalArgumentException();
+ r = 1.0 / sin( r );
+ }
+}
+
+
+void Complex::Cot()
+{
+ if ( i )
+ {
+ if( !::rtl::math::isValidArcArg( 2.0 * r ) )
+ throw lang::IllegalArgumentException();
+ double fScale =1.0 / ( cosh( 2.0 * i ) - cos( 2.0 * r ) );
+ r = sin( 2.0 * r ) * fScale;
+ i = - ( sinh( 2.0 * i ) * fScale );
+ }
+ else
+ {
+ if( !::rtl::math::isValidArcArg( r ) )
+ throw lang::IllegalArgumentException();
+ r = 1.0 / tan( r );
+ }
+}
+
+
+void Complex::Sinh()
+{
+ if( !::rtl::math::isValidArcArg( r ) )
+ throw lang::IllegalArgumentException();
+
+ if( i )
+ {
+ double r_;
+ r_ = sinh( r ) * cos( i );
+ i = cosh( r ) * sin( i );
+ r = r_;
+ }
+ else
+ r = sinh( r );
+}
+
+
+void Complex::Cosh()
+{
+ if( !::rtl::math::isValidArcArg( r ) )
+ throw lang::IllegalArgumentException();
+
+ if( i )
+ {
+ double r_;
+ r_ = cosh( r ) * cos( i );
+ i = sinh( r ) * sin( i );
+ r = r_;
+ }
+ else
+ r = cosh( r );
+}
+
+
+void Complex::Sech()
+{
+ if ( i )
+ {
+ if( !::rtl::math::isValidArcArg( 2.0 * r ) )
+ throw lang::IllegalArgumentException();
+ double fScale =1.0 / ( cosh( 2.0 * r ) + cos( 2.0 * i ));
+ double r_;
+ r_ = 2.0 * cosh( r ) * cos( i ) * fScale;
+ i = - (2.0 * sinh( r ) * sin( i ) * fScale );
+ r = r_ ;
+ }
+ else
+ {
+ if( !::rtl::math::isValidArcArg( r ) )
+ throw lang::IllegalArgumentException();
+ r = 1.0 / cosh( r );
+ }
+}
+
+
+void Complex::Csch()
+{
+ if ( i )
+ {
+ if( !::rtl::math::isValidArcArg( 2.0 * r ) )
+ throw lang::IllegalArgumentException();
+ double fScale =1.0 / ( cosh( 2.0 * r ) - cos( 2.0 * i ));
+ double r_;
+ r_ = 2.0 * sinh( r ) * cos( i ) * fScale;
+ i = - ( 2.0 * cosh( r ) * sin( i ) * fScale );
+ r = r_ ;
+ }
+ else
+ {
+ if( !::rtl::math::isValidArcArg( r ) )
+ throw lang::IllegalArgumentException();
+ r = 1.0 / sinh( r );
+ }
+}
+
+
+ComplexList::~ComplexList()
+{
+}
+
+
+void ComplexList::Append( const uno::Sequence< uno::Sequence< OUString > >& r )
+{
+ for( const uno::Sequence< OUString >& rList : r )
+ {
+ for( const OUString& rStr : rList )
+ {
+ if( !rStr.isEmpty() )
+ Append( Complex( rStr ) );
+ }
+ }
+}
+
+
+void ComplexList::Append( const uno::Sequence< uno::Any >& aMultPars )
+{
+ for( const uno::Any& r : aMultPars )
+ {
+ switch( r.getValueTypeClass() )
+ {
+ case uno::TypeClass_VOID: break;
+ case uno::TypeClass_STRING:
+ {
+ auto pStr = o3tl::forceAccess<OUString>(r);
+
+ if( !pStr->isEmpty() )
+ Append( Complex( *pStr ) );
+ }
+ break;
+ case uno::TypeClass_DOUBLE:
+ Append( Complex( *o3tl::forceAccess<double>(r), 0.0 ) );
+ break;
+ case uno::TypeClass_SEQUENCE:
+ {
+ uno::Sequence< uno::Sequence< uno::Any > > aValArr;
+ if( !(r >>= aValArr) )
+ throw lang::IllegalArgumentException();
+
+ for( const uno::Sequence< uno::Any >& rArr : std::as_const(aValArr) )
+ Append( rArr );
+ }
+ break;
+ default:
+ throw lang::IllegalArgumentException();
+ }
+ }
+}
+
+ConvertData::ConvertData(const char p[], double fC, ConvertDataClass e, bool bPrefSupport)
+ : fConst(fC)
+ , aName(p, strlen(p), RTL_TEXTENCODING_MS_1252)
+ , eClass(e)
+ , bPrefixSupport(bPrefSupport)
+{
+}
+
+ConvertData::~ConvertData()
+{
+}
+
+sal_Int16 ConvertData::GetMatchingLevel( const OUString& rRef ) const
+{
+ OUString aStr = rRef;
+ sal_Int32 nLen = rRef.getLength();
+ sal_Int32 nIndex = rRef.lastIndexOf( '^' );
+ if( nIndex > 0 && nIndex == ( nLen - 2 ) )
+ aStr = aStr.subView( 0, nLen - 2 ) + OUStringChar( aStr[ nLen - 1 ] );
+ if( aName == aStr )
+ return 0;
+ else
+ {
+ const sal_Unicode* p = aStr.getStr();
+
+ nLen = aStr.getLength();
+ bool bPref = bPrefixSupport;
+ bool bOneChar = (bPref && nLen > 1 && (aName == p + 1));
+ if (bOneChar || (bPref && nLen > 2 && (aName == p + 2) &&
+ *p == 'd' && *(p+1) == 'a'))
+ {
+ sal_Int16 n;
+ switch( *p )
+ {
+ case 'y': n = -24; break; // yocto
+ case 'z': n = -21; break; // zepto
+ case 'a': n = -18; break;
+ case 'f': n = -15; break;
+ case 'p': n = -12; break;
+ case 'n': n = -9; break;
+ case 'u': n = -6; break;
+ case 'm': n = -3; break;
+ case 'c': n = -2; break;
+ case 'd':
+ {
+ if ( bOneChar )
+ n = -1; // deci
+ else
+ n = 1; // deca
+ }
+ break;
+ case 'e': n = 1; break;
+ case 'h': n = 2; break;
+ case 'k': n = 3; break;
+ case 'M': n = 6; break;
+ case 'G': n = 9; break;
+ case 'T': n = 12; break;
+ case 'P': n = 15; break;
+ case 'E': n = 18; break;
+ case 'Z': n = 21; break; // zetta
+ case 'Y': n = 24; break; // yotta
+ default:
+ n = INV_MATCHLEV;
+ }
+
+// We could weed some nonsense out, ODFF doesn't say so though.
+#if 0
+ if (n < 0 && Class() == CDC_Information)
+ n = INV_MATCHLEV; // milli-bits doesn't make sense
+#endif
+
+//! <HACK> "cm3" is not 10^-2 m^3 but 10^-6 m^3 !!! ------------------
+ if( n != INV_MATCHLEV )
+ {
+ sal_Unicode cLast = p[ aStr.getLength() - 1 ];
+ if( cLast == '2' )
+ n *= 2;
+ else if( cLast == '3' )
+ n *= 3;
+ }
+//! </HACK> -------------------------------------------------------------------
+
+ return n;
+ }
+ else if ( nLen > 2 && ( aName == p + 2 ) && ( Class() == CDC_Information ) )
+ {
+ const sal_Unicode* pStr = aStr.getStr();
+ if ( *(pStr + 1) != 'i')
+ return INV_MATCHLEV;
+ sal_Int16 n;
+ switch( *pStr )
+ {
+ case 'k': n = 10; break;
+ case 'M': n = 20; break;
+ case 'G': n = 30; break;
+ case 'T': n = 40; break;
+ case 'P': n = 50; break;
+ case 'E': n = 60; break;
+ case 'Z': n = 70; break;
+ case 'Y': n = 80; break;
+ default:
+ n = INV_MATCHLEV;
+ }
+ return n;
+ }
+ else
+ return INV_MATCHLEV;
+ }
+}
+
+
+double ConvertData::Convert(
+ double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const
+{
+ if( Class() != r.Class() )
+ throw lang::IllegalArgumentException();
+
+ bool bBinFromLev = ( nLevFrom > 0 && ( nLevFrom % 10 ) == 0 );
+ bool bBinToLev = ( nLevTo > 0 && ( nLevTo % 10 ) == 0 );
+
+ if ( Class() == CDC_Information && ( bBinFromLev || bBinToLev ) )
+ {
+ if ( bBinFromLev && bBinToLev )
+ {
+ nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo );
+ f *= r.fConst / fConst;
+ if( nLevFrom )
+ f *= pow( 2.0, nLevFrom );
+ }
+ else if ( bBinFromLev )
+ f *= ( r.fConst / fConst ) * ( pow( 2.0, nLevFrom ) / pow( 10.0, nLevTo ) );
+ else
+ f *= ( r.fConst / fConst ) * ( pow( 10.0, nLevFrom ) / pow( 2.0, nLevTo ) );
+ return f;
+ }
+
+ nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo ); // effective level
+
+ f *= r.fConst / fConst;
+
+ if( nLevFrom )
+ f = ::rtl::math::pow10Exp( f, nLevFrom );
+
+ return f;
+}
+
+
+double ConvertData::ConvertFromBase( double f, sal_Int16 n ) const
+{
+ return ::rtl::math::pow10Exp( f * fConst, -n );
+}
+
+ConvertDataLinear::~ConvertDataLinear()
+{
+}
+
+double ConvertDataLinear::Convert(
+ double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const
+{
+ if( Class() != r.Class() )
+ throw lang::IllegalArgumentException();
+ return r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo );
+}
+
+
+double ConvertDataLinear::ConvertToBase( double f, sal_Int16 n ) const
+{
+ if( n )
+ f = ::rtl::math::pow10Exp( f, n );
+
+ f /= fConst;
+ f -= fOffs;
+
+ return f;
+}
+
+
+double ConvertDataLinear::ConvertFromBase( double f, sal_Int16 n ) const
+{
+ f += fOffs;
+ f *= fConst;
+
+ if( n )
+ f = ::rtl::math::pow10Exp( f, -n );
+
+ return f;
+}
+
+
+ConvertDataList::ConvertDataList()
+{
+#define NEWD(str,unit,cl) maVector.emplace_back(new ConvertData(str,unit,cl))
+#define NEWDP(str,unit,cl) maVector.emplace_back(new ConvertData(str,unit,cl,true))
+#define NEWL(str,unit,offs,cl) maVector.emplace_back(new ConvertDataLinear(str,unit,offs,cl))
+#define NEWLP(str,unit,offs,cl) maVector.emplace_back(new ConvertDataLinear(str,unit,offs,cl,true))
+
+ // *** are extra and not standard Excel Analysis Addin!
+
+ // MASS: 1 Gram is...
+ NEWDP( "g", 1.0000000000000000E00, CDC_Mass ); // Gram
+ NEWD( "sg", 6.8522050005347800E-05, CDC_Mass ); // Pieces
+ NEWD( "lbm", 2.2046229146913400E-03, CDC_Mass ); // Pound (commercial weight)
+ NEWDP( "u", 6.0221370000000000E23, CDC_Mass ); // U (atomic mass)
+ NEWD( "ozm", 3.5273971800362700E-02, CDC_Mass ); // Ounce (commercial weight)
+ NEWD( "stone", 1.574730e-04, CDC_Mass ); // *** Stone
+ NEWD( "ton", 1.102311e-06, CDC_Mass ); // *** Ton
+ NEWD( "grain", 1.543236E01, CDC_Mass ); // *** Grain
+ NEWD( "pweight", 7.054792E-01, CDC_Mass ); // *** Pennyweight
+ NEWD( "hweight", 1.968413E-05, CDC_Mass ); // *** Hundredweight
+ NEWD( "shweight", 2.204623E-05, CDC_Mass ); // *** Shorthundredweight
+ NEWD( "brton", 9.842065E-07, CDC_Mass ); // *** Gross Registered Ton
+ NEWD( "cwt", 2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight
+ NEWD( "shweight", 2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight also
+ NEWD( "uk_cwt", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight
+ NEWD( "lcwt", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
+ NEWD( "hweight", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
+ NEWD( "uk_ton", 9.8420652761106063E-07, CDC_Mass ); // Imperial ton
+ NEWD( "LTON", 9.8420652761106063E-07, CDC_Mass ); // Imperial ton also
+
+ // LENGTH: 1 Meter is...
+ NEWDP( "m", 1.0000000000000000E00, CDC_Length ); // Meter
+ NEWD( "mi", 6.2137119223733397E-04, CDC_Length ); // Britsh Mile 6,21371192237333969617434184363e-4
+ NEWD( "Nmi", 5.3995680345572354E-04, CDC_Length ); // Nautical Mile 5,39956803455723542116630669546e-4
+ NEWD( "in", 3.9370078740157480E01, CDC_Length ); // Inch 39,37007874015748031496062992126
+ NEWD( "ft", 3.2808398950131234E00, CDC_Length ); // Foot 3,2808398950131233595800524934383
+ NEWD( "yd", 1.0936132983377078E00, CDC_Length ); // Yard 1,0936132983377077865266841644794
+ NEWDP( "ang", 1.0000000000000000E10, CDC_Length ); // Angstrom
+ NEWD( "Pica", 2.8346456692913386E03, CDC_Length ); // Pica Point (1/72 Inch) 2834,6456692913385826771653543307
+ NEWD( "picapt", 2.8346456692913386E03, CDC_Length ); // Pica Point (1/72 Inch) 2834,6456692913385826771653543307
+ NEWD( "pica", 2.36220472441E02, CDC_Length ); // pica (1/6 Inch)
+ NEWD( "ell", 8.748906E-01, CDC_Length ); // *** Ell
+ NEWDP( "parsec", 3.240779E-17, CDC_Length ); // *** Parsec
+ NEWDP( "pc", 3.240779E-17, CDC_Length ); // *** Parsec also
+ NEWDP( "lightyear", 1.0570234557732930E-16, CDC_Length ); // *** Light Year
+ NEWDP( "ly", 1.0570234557732930E-16, CDC_Length ); // *** Light Year also
+ NEWD( "survey_mi", 6.2136994949494949E-04, CDC_Length ); // U.S. survey mile
+
+ // TIME: 1 Second is...
+ NEWD( "yr", 3.1688087814028950E-08, CDC_Time ); // Year
+ NEWD( "day", 1.1574074074074074E-05, CDC_Time ); // Day
+ NEWD( "d", 1.1574074074074074E-05, CDC_Time ); // Day also
+ NEWD( "hr", 2.7777777777777778E-04, CDC_Time ); // Hour
+ NEWD( "mn", 1.6666666666666667E-02, CDC_Time ); // Minute
+ NEWD( "min", 1.6666666666666667E-02, CDC_Time ); // Minute also
+ NEWDP( "sec", 1.0000000000000000E00, CDC_Time ); // Second
+ NEWDP( "s", 1.0000000000000000E00, CDC_Time ); // Second also
+
+ // PRESSURE: 1 Pascal is...
+ NEWDP( "Pa", 1.0000000000000000E00, CDC_Pressure ); // Pascal
+ NEWDP( "atm", 9.8692329999819300E-06, CDC_Pressure ); // Atmosphere
+ NEWDP( "at", 9.8692329999819300E-06, CDC_Pressure ); // Atmosphere also
+ NEWDP( "mmHg", 7.5006170799862700E-03, CDC_Pressure ); // mm Hg (Mercury)
+ NEWD( "Torr", 7.5006380000000000E-03, CDC_Pressure ); // *** Torr
+ NEWD( "psi", 1.4503770000000000E-04, CDC_Pressure ); // *** Psi
+
+ // FORCE: 1 Newton is...
+ NEWDP( "N", 1.0000000000000000E00, CDC_Force ); // Newton
+ NEWDP( "dyn", 1.0000000000000000E05, CDC_Force ); // Dyn
+ NEWDP( "dy", 1.0000000000000000E05, CDC_Force ); // Dyn also
+ NEWD( "lbf", 2.24808923655339E-01, CDC_Force ); // Pound-Force
+ NEWDP( "pond", 1.019716E02, CDC_Force ); // *** Pond
+
+ // ENERGY: 1 Joule is...
+ NEWDP( "J", 1.0000000000000000E00, CDC_Energy ); // Joule
+ NEWDP( "e", 1.0000000000000000E07, CDC_Energy ); // Erg -> https://en.wikipedia.org/wiki/Erg
+ NEWDP( "c", 2.3900624947346700E-01, CDC_Energy ); // Thermodynamical Calorie
+ NEWDP( "cal", 2.3884619064201700E-01, CDC_Energy ); // Calorie
+ NEWDP( "eV", 6.2414570000000000E18, CDC_Energy ); // Electronvolt
+ NEWDP( "ev", 6.2414570000000000E18, CDC_Energy ); // Electronvolt also
+ NEWD( "HPh", 3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours
+ NEWD( "hh", 3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours also
+ NEWDP( "Wh", 2.7777777777777778E-04, CDC_Energy ); // Watt Hours
+ NEWDP( "wh", 2.7777777777777778E-04, CDC_Energy ); // Watt Hours also
+ NEWD( "flb", 2.37304222192651E01, CDC_Energy ); // Foot Pound
+ NEWD( "BTU", 9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit
+ NEWD( "btu", 9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit also
+
+ // POWER: 1 Watt is...
+ NEWDP( "W", 1.0000000000000000E00, CDC_Power ); // Watt
+ NEWDP( "w", 1.0000000000000000E00, CDC_Power ); // Watt also
+ NEWD( "HP", 1.341022E-03, CDC_Power ); // Horsepower
+ NEWD( "h", 1.341022E-03, CDC_Power ); // Horsepower also
+ NEWD( "PS", 1.359622E-03, CDC_Power ); // *** German Pferdestaerke
+
+ // MAGNETISM: 1 Tesla is...
+ NEWDP( "T", 1.0000000000000000E00, CDC_Magnetism ); // Tesla
+ NEWDP( "ga", 1.0000000000000000E04, CDC_Magnetism ); // Gauss
+
+ // TEMPERATURE: 1 Kelvin is...
+ NEWL( "C", 1.0000000000000000E00, -2.7315000000000000E02, CDC_Temperature ); // Celsius
+ NEWL( "cel", 1.0000000000000000E00, -2.7315000000000000E02, CDC_Temperature ); // Celsius also
+ NEWL( "F", 1.8000000000000000E00, -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit
+ NEWL( "fah", 1.8000000000000000E00, -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit also
+ NEWLP( "K", 1.0000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // Kelvin
+ NEWLP( "kel", 1.0000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // Kelvin also
+ NEWL( "Reau", 8.0000000000000000E-01, -2.7315000000000000E02, CDC_Temperature ); // *** Reaumur
+ NEWL( "Rank", 1.8000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // *** Rankine
+
+ // VOLUME: 1 Liter is...
+ NEWD( "tsp", 2.0288413621105798E02, CDC_Volume ); // US teaspoon 1/768 gallon
+ NEWD( "tbs", 6.7628045403685994E01, CDC_Volume ); // US tablespoon 1/256 gallon
+ NEWD( "oz", 3.3814022701842997E01, CDC_Volume ); // Ounce Liquid 1/128 gallon
+ NEWD( "cup", 4.2267528377303746E00, CDC_Volume ); // Cup 1/16 gallon
+ NEWD( "pt", 2.1133764188651873E00, CDC_Volume ); // US Pint 1/8 gallon
+ NEWD( "us_pt", 2.1133764188651873E00, CDC_Volume ); // US Pint also
+ NEWD( "uk_pt", 1.7597539863927023E00, CDC_Volume ); // UK Pint 1/8 imperial gallon
+ NEWD( "qt", 1.0566882094325937E00, CDC_Volume ); // Quart 1/4 gallon
+ NEWD( "gal", 2.6417205235814842E-01, CDC_Volume ); // Gallon 1/3.785411784
+ NEWDP( "l", 1.0000000000000000E00, CDC_Volume ); // Liter
+ NEWDP( "L", 1.0000000000000000E00, CDC_Volume ); // Liter also
+ NEWDP( "lt", 1.0000000000000000E00, CDC_Volume ); // Liter also
+ NEWDP( "m3", 1.0000000000000000E-03, CDC_Volume ); // *** Cubic Meter
+ NEWD( "mi3", 2.3991275857892772E-13, CDC_Volume ); // *** Cubic Britsh Mile
+ NEWD( "Nmi3", 1.5742621468581148E-13, CDC_Volume ); // *** Cubic Nautical Mile
+ NEWD( "in3", 6.1023744094732284E01, CDC_Volume ); // *** Cubic Inch
+ NEWD( "ft3", 3.5314666721488590E-02, CDC_Volume ); // *** Cubic Foot
+ NEWD( "yd3", 1.3079506193143922E-03, CDC_Volume ); // *** Cubic Yard
+ NEWDP( "ang3", 1.0000000000000000E27, CDC_Volume ); // *** Cubic Angstrom
+ NEWD( "Pica3", 2.2776990435870636E07, CDC_Volume ); // *** Cubic Pica Point (1/72 inch)
+ NEWD( "picapt3", 2.2776990435870636E07, CDC_Volume ); // *** Cubic Pica Point (1/72 inch)
+ NEWD( "pica3", 1.31811287245E04, CDC_Volume ); // *** Cubic Pica (1/6 inch)
+ NEWD( "barrel", 6.2898107704321051E-03, CDC_Volume ); // *** Barrel (=42gal)
+ NEWD( "bushel", 2.837759E-02, CDC_Volume ); // *** Bushel
+ NEWD( "regton", 3.531467E-04, CDC_Volume ); // *** Register ton
+ NEWD( "GRT", 3.531467E-04, CDC_Volume ); // *** Register ton also
+ NEWD( "Schooner", 2.3529411764705882E00, CDC_Volume ); // *** austr. Schooner
+ NEWD( "Middy", 3.5087719298245614E00, CDC_Volume ); // *** austr. Middy
+ NEWD( "Glass", 5.0000000000000000E00, CDC_Volume ); // *** austr. Glass
+ NEWD( "Sixpack", 0.5, CDC_Volume ); // ***
+ NEWD( "Humpen", 2.0, CDC_Volume ); // ***
+ NEWD( "ly3", 1.1810108125623799E-51, CDC_Volume ); // *** Cubic light-year
+ NEWD( "MTON", 1.4125866688595436E00, CDC_Volume ); // *** Measurement ton
+ NEWD( "tspm", 2.0000000000000000E02, CDC_Volume ); // *** Modern teaspoon
+ NEWD( "uk_gal", 2.1996924829908779E-01, CDC_Volume ); // U.K. / Imperial gallon 1/4.54609
+ NEWD( "uk_qt", 8.7987699319635115E-01, CDC_Volume ); // U.K. / Imperial quart 1/4 imperial gallon
+
+ // 1 Square Meter is...
+ NEWDP( "m2", 1.0000000000000000E00, CDC_Area ); // *** Square Meter
+ NEWD( "mi2", 3.8610215854244585E-07, CDC_Area ); // *** Square Britsh Mile
+ NEWD( "Nmi2", 2.9155334959812286E-07, CDC_Area ); // *** Square Nautical Mile
+ NEWD( "in2", 1.5500031000062000E03, CDC_Area ); // *** Square Inch
+ NEWD( "ft2", 1.0763910416709722E01, CDC_Area ); // *** Square Foot
+ NEWD( "yd2", 1.1959900463010803E00, CDC_Area ); // *** Square Yard
+ NEWDP( "ang2", 1.0000000000000000E20, CDC_Area ); // *** Square Angstrom
+ NEWD( "Pica2", 8.0352160704321409E06, CDC_Area ); // *** Square Pica Point (1/72 inch)
+ NEWD( "picapt2", 8.0352160704321409E06, CDC_Area ); // *** Square Pica Point (1/72 inch)
+ NEWD( "pica2", 5.58001116002232E04, CDC_Area ); // *** Square Pica (1/6 inch)
+ NEWD( "Morgen", 4.0000000000000000E-04, CDC_Area ); // *** Morgen
+ NEWDP( "ar", 1.000000E-02, CDC_Area ); // *** Ar
+ NEWD( "acre", 2.471053815E-04, CDC_Area ); // *** Acre
+ NEWD( "uk_acre", 2.4710538146716534E-04, CDC_Area ); // *** International acre
+ NEWD( "us_acre", 2.4710439304662790E-04, CDC_Area ); // *** U.S. survey/statute acre
+ NEWD( "ly2", 1.1172985860549147E-32, CDC_Area ); // *** Square Light-year
+ NEWD( "ha", 1.000000E-04, CDC_Area ); // *** Hectare
+
+ // SPEED: 1 Meter per Second is...
+ NEWDP( "m/s", 1.0000000000000000E00, CDC_Speed ); // *** Meters per Second
+ NEWDP( "m/sec", 1.0000000000000000E00, CDC_Speed ); // *** Meters per Second also
+ NEWDP( "m/h", 3.6000000000000000E03, CDC_Speed ); // *** Meters per Hour
+ NEWDP( "m/hr", 3.6000000000000000E03, CDC_Speed ); // *** Meters per Hour also
+ NEWD( "mph", 2.2369362920544023E00, CDC_Speed ); // *** Britsh Miles per Hour
+ NEWD( "kn", 1.9438444924406048E00, CDC_Speed ); // *** Knot = Nautical Miles per Hour
+ NEWD( "admkn", 1.9438446603753486E00, CDC_Speed ); // *** Admiralty Knot
+ NEWD( "ludicrous speed", 2.0494886343432328E-14, CDC_Speed ); // ***
+ NEWD( "ridiculous speed", 4.0156958471424288E-06, CDC_Speed); // ***
+
+ // INFORMATION: 1 Bit is...
+ NEWDP( "bit", 1.00E00, CDC_Information); // *** Bit
+ NEWDP( "byte", 1.25E-01, CDC_Information); // *** Byte
+}
+
+
+ConvertDataList::~ConvertDataList()
+{
+}
+
+
+double ConvertDataList::Convert( double fVal, const OUString& rFrom, const OUString& rTo )
+{
+ ConvertData* pFrom = nullptr;
+ ConvertData* pTo = nullptr;
+ bool bSearchFrom = true;
+ bool bSearchTo = true;
+ sal_Int16 nLevelFrom = 0;
+ sal_Int16 nLevelTo = 0;
+
+ for( const auto& rItem : maVector )
+ {
+ ConvertData* p = rItem.get();
+ if( bSearchFrom )
+ {
+ sal_Int16 n = p->GetMatchingLevel( rFrom );
+ if( n != INV_MATCHLEV )
+ {
+ if( n )
+ { // only first match for partial equality rulz a little bit more
+ pFrom = p;
+ nLevelFrom = n;
+ }
+ else
+ { // ... but exact match rulz most
+ pFrom = p;
+ bSearchFrom = false;
+ nLevelFrom = n;
+ }
+ }
+ }
+
+ if( bSearchTo )
+ {
+ sal_Int16 n = p->GetMatchingLevel( rTo );
+ if( n != INV_MATCHLEV )
+ {
+ if( n )
+ { // only first match for partial equality rulz a little bit more
+ pTo = p;
+ nLevelTo = n;
+ }
+ else
+ { // ... but exact match rulz most
+ pTo = p;
+ bSearchTo = false;
+ nLevelTo = n;
+ }
+ }
+ }
+
+ if( !bSearchFrom && !bSearchTo )
+ break;
+ }
+
+ if( !pFrom || !pTo )
+ throw lang::IllegalArgumentException();
+
+ return pFrom->Convert( fVal, *pTo, nLevelFrom, nLevelTo );
+}
+
+
+ScaDate::ScaDate() :
+ nOrigDay( 1 ),
+ nDay( 1 ),
+ nMonth( 1 ),
+ nYear( 1900 ),
+ bLastDayMode( true ),
+ bLastDay( false ),
+ b30Days( false ),
+ bUSMode( false )
+{
+}
+
+ScaDate::ScaDate( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nBase )
+{
+ DaysToDate( nNullDate + nDate, nOrigDay, nMonth, nYear );
+ bLastDayMode = (nBase != 5);
+ bLastDay = (nOrigDay >= ::DaysInMonth( nMonth, nYear ));
+ b30Days = (nBase == 0) || (nBase == 4);
+ bUSMode = (nBase == 0);
+ setDay();
+}
+
+ScaDate::ScaDate( const ScaDate& rCopy ) :
+ nOrigDay( rCopy.nOrigDay ),
+ nDay( rCopy.nDay ),
+ nMonth( rCopy.nMonth ),
+ nYear( rCopy.nYear ),
+ bLastDayMode( rCopy.bLastDayMode ),
+ bLastDay( rCopy.bLastDay ),
+ b30Days( rCopy.b30Days ),
+ bUSMode( rCopy.bUSMode )
+{
+}
+
+ScaDate& ScaDate::operator=( const ScaDate& rCopy )
+{
+ if( this != &rCopy )
+ {
+ nOrigDay = rCopy.nOrigDay;
+ nDay = rCopy.nDay;
+ nMonth = rCopy.nMonth;
+ nYear = rCopy.nYear;
+ bLastDayMode = rCopy.bLastDayMode;
+ bLastDay = rCopy.bLastDay;
+ b30Days = rCopy.b30Days;
+ bUSMode = rCopy.bUSMode;
+ }
+ return *this;
+}
+
+void ScaDate::setDay()
+{
+ if( b30Days )
+ {
+ // 30-days-mode: set nDay to 30 if original was last day in month
+ nDay = std::min( nOrigDay, static_cast< sal_uInt16 >( 30 ) );
+ if( bLastDay || (nDay >= ::DaysInMonth( nMonth, nYear )) )
+ nDay = 30;
+ }
+ else
+ {
+ // set nDay to last day in this month if original was last day
+ sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
+ nDay = bLastDay ? nLastDay : std::min( nOrigDay, nLastDay );
+ }
+}
+
+sal_Int32 ScaDate::getDaysInMonthRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
+{
+ if( nFrom > nTo )
+ return 0;
+
+ sal_Int32 nRet = 0;
+ if( b30Days )
+ nRet = (nTo - nFrom + 1) * 30;
+ else
+ {
+ for( sal_uInt16 nMonthIx = nFrom; nMonthIx <= nTo; ++nMonthIx )
+ nRet += getDaysInMonth( nMonthIx );
+ }
+ return nRet;
+}
+
+sal_Int32 ScaDate::getDaysInYearRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
+{
+ if( nFrom > nTo )
+ return 0;
+
+ return b30Days ? ((nTo - nFrom + 1) * 360) : ::GetDaysInYears( nFrom, nTo );
+}
+
+void ScaDate::doAddYears( sal_Int32 nYearCount )
+{
+ sal_Int32 nNewYear = nYearCount + nYear;
+ if( (nNewYear < 0) || (nNewYear > 0x7FFF) )
+ throw lang::IllegalArgumentException();
+ nYear = static_cast< sal_uInt16 >( nNewYear );
+}
+
+void ScaDate::addMonths( sal_Int32 nMonthCount )
+{
+ sal_Int32 nNewMonth = nMonthCount + nMonth;
+ if( nNewMonth > 12 )
+ {
+ --nNewMonth;
+ doAddYears( nNewMonth / 12 );
+ nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 ) + 1;
+ }
+ else if( nNewMonth < 1 )
+ {
+ doAddYears( nNewMonth / 12 - 1 );
+ nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 + 12 );
+ }
+ else
+ nMonth = static_cast< sal_uInt16 >( nNewMonth );
+ setDay();
+}
+
+sal_Int32 ScaDate::getDate( sal_Int32 nNullDate ) const
+{
+ sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
+ sal_uInt16 nRealDay = (bLastDayMode && bLastDay) ? nLastDay : std::min( nLastDay, nOrigDay );
+ return ::DateToDays( nRealDay, nMonth, nYear ) - nNullDate;
+}
+
+sal_Int32 ScaDate::getDiff( const ScaDate& rFrom, const ScaDate& rTo )
+{
+ if( rFrom > rTo )
+ return getDiff( rTo, rFrom );
+
+ sal_Int32 nDiff = 0;
+ ScaDate aFrom( rFrom );
+ ScaDate aTo( rTo );
+
+ if( rTo.b30Days )
+ {
+ // corrections for base 0 (US NASD)
+ if( rTo.bUSMode )
+ {
+ if( ((rFrom.nMonth == 2) || (rFrom.nDay < 30)) && (aTo.nOrigDay == 31) )
+ aTo.nDay = 31;
+ else if( (aTo.nMonth == 2) && aTo.bLastDay )
+ aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
+ }
+ // corrections for base 4 (Europe)
+ else
+ {
+ if( (aFrom.nMonth == 2) && (aFrom.nDay == 30) )
+ aFrom.nDay = ::DaysInMonth( 2, aFrom.nYear );
+ if( (aTo.nMonth == 2) && (aTo.nDay == 30) )
+ aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
+ }
+ }
+
+ if( (aFrom.nYear < aTo.nYear) || ((aFrom.nYear == aTo.nYear) && (aFrom.nMonth < aTo.nMonth)) )
+ {
+ // move aFrom to 1st day of next month
+ nDiff = aFrom.getDaysInMonth() - aFrom.nDay + 1;
+ aFrom.nOrigDay = aFrom.nDay = 1;
+ aFrom.bLastDay = false;
+ aFrom.addMonths( 1 );
+
+ if( aFrom.nYear < aTo.nYear )
+ {
+ // move aFrom to 1st day of next year
+ nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, 12 );
+ aFrom.addMonths( 13 - aFrom.nMonth );
+
+ // move aFrom to 1st day of this year
+ nDiff += aFrom.getDaysInYearRange( aFrom.nYear, aTo.nYear - 1 );
+ aFrom.addYears( aTo.nYear - aFrom.nYear );
+ }
+
+ // move aFrom to 1st day of this month
+ nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, aTo.nMonth - 1 );
+ aFrom.addMonths( aTo.nMonth - aFrom.nMonth );
+ }
+ // finally add remaining days in this month
+ nDiff += aTo.nDay - aFrom.nDay;
+ return std::max<sal_Int32>(nDiff, 0);
+}
+
+bool ScaDate::operator<( const ScaDate& rCmp ) const
+{
+ if( nYear != rCmp.nYear )
+ return nYear < rCmp.nYear;
+ if( nMonth != rCmp.nMonth )
+ return nMonth < rCmp.nMonth;
+ if( nDay != rCmp.nDay )
+ return nDay < rCmp.nDay;
+ if( bLastDay || rCmp.bLastDay )
+ return !bLastDay && rCmp.bLastDay;
+ return nOrigDay < rCmp.nOrigDay;
+}
+
+
+ScaAnyConverter::ScaAnyConverter( const uno::Reference< uno::XComponentContext >& xContext )
+ : nDefaultFormat(0)
+ , bHasValidFormat(false)
+{
+ xFormatter = util::NumberFormatter::create(xContext);
+}
+
+ScaAnyConverter::~ScaAnyConverter()
+{
+}
+
+void ScaAnyConverter::init( const uno::Reference< beans::XPropertySet >& xPropSet )
+{
+ // try to get default number format
+ bHasValidFormat = false;
+ if( !xFormatter.is() )
+ return;
+
+ // get XFormatsSupplier from outer XPropertySet
+ uno::Reference< util::XNumberFormatsSupplier > xFormatsSupp( xPropSet, uno::UNO_QUERY );
+ if( !xFormatsSupp.is() )
+ return;
+
+ // get XNumberFormatTypes from XNumberFormatsSupplier to get standard index
+ uno::Reference< util::XNumberFormats > xFormats( xFormatsSupp->getNumberFormats() );
+ uno::Reference< util::XNumberFormatTypes > xFormatTypes( xFormats, uno::UNO_QUERY );
+ if( xFormatTypes.is() )
+ {
+ lang::Locale eLocale;
+ nDefaultFormat = xFormatTypes->getStandardIndex( eLocale );
+ xFormatter->attachNumberFormatsSupplier( xFormatsSupp );
+ bHasValidFormat = true;
+ }
+}
+
+double ScaAnyConverter::convertToDouble( const OUString& rString ) const
+{
+ double fValue = 0.0;
+ if( bHasValidFormat )
+ {
+ try
+ {
+ fValue = xFormatter->convertStringToNumber( nDefaultFormat, rString );
+ }
+ catch( uno::Exception& )
+ {
+ throw lang::IllegalArgumentException();
+ }
+ }
+ else
+ {
+ rtl_math_ConversionStatus eStatus;
+ sal_Int32 nEnd;
+ fValue = ::rtl::math::stringToDouble( rString, '.', ',', &eStatus, &nEnd );
+ if( (eStatus != rtl_math_ConversionStatus_Ok) || (nEnd < rString.getLength()) )
+ throw lang::IllegalArgumentException();
+ }
+ return fValue;
+}
+
+bool ScaAnyConverter::getDouble(
+ double& rfResult,
+ const uno::Any& rAny ) const
+{
+ rfResult = 0.0;
+ bool bContainsVal = true;
+ switch( rAny.getValueTypeClass() )
+ {
+ case uno::TypeClass_VOID:
+ bContainsVal = false;
+ break;
+ case uno::TypeClass_DOUBLE:
+ rAny >>= rfResult;
+ break;
+ case uno::TypeClass_STRING:
+ {
+ auto pString = o3tl::forceAccess< OUString >( rAny );
+ if( !pString->isEmpty() )
+ rfResult = convertToDouble( *pString );
+ else
+ bContainsVal = false;
+ }
+ break;
+ default:
+ throw lang::IllegalArgumentException();
+ }
+ return bContainsVal;
+}
+
+bool ScaAnyConverter::getDouble(
+ double& rfResult,
+ const uno::Reference< beans::XPropertySet >& xPropSet,
+ const uno::Any& rAny )
+{
+ init( xPropSet );
+ return getDouble( rfResult, rAny );
+}
+
+double ScaAnyConverter::getDouble(
+ const uno::Reference< beans::XPropertySet >& xPropSet,
+ const uno::Any& rAny,
+ double fDefault )
+{
+ double fResult;
+ if( !getDouble( fResult, xPropSet, rAny ) )
+ fResult = fDefault;
+ return fResult;
+}
+
+bool ScaAnyConverter::getInt32(
+ sal_Int32& rnResult,
+ const uno::Reference< beans::XPropertySet >& xPropSet,
+ const uno::Any& rAny )
+{
+ double fResult;
+ bool bContainsVal = getDouble( fResult, xPropSet, rAny );
+ if( (fResult <= -2147483649.0) || (fResult >= 2147483648.0) )
+ throw lang::IllegalArgumentException();
+
+ rnResult = static_cast< sal_Int32 >( fResult );
+ return bContainsVal;
+}
+
+sal_Int32 ScaAnyConverter::getInt32(
+ const uno::Reference< beans::XPropertySet >& xPropSet,
+ const uno::Any& rAny,
+ sal_Int32 nDefault )
+{
+ sal_Int32 nResult;
+ if( !getInt32( nResult, xPropSet, rAny ) )
+ nResult = nDefault;
+ return nResult;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/analysis/analysishelper.hxx b/scaddins/source/analysis/analysishelper.hxx
new file mode 100644
index 000000000..093d93930
--- /dev/null
+++ b/scaddins/source/analysis/analysishelper.hxx
@@ -0,0 +1,905 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <unotools/resmgr.hxx>
+
+#include <cmath>
+
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::util { class XNumberFormatter2; }
+
+namespace sca::analysis {
+
+class ScaAnyConverter;
+
+inline bool IsLeapYear( sal_uInt16 nYear );
+
+#ifdef DISABLE_DYNLOADING
+
+// Avoid clash with the functions with same name in
+// scaddins/source/datefunc/datefunc.cxx. I am not sure if each pair
+// have identical semantics, but if yes, one copy should be enough,
+// but what would be a suitable library where such functions could go?
+// Or can the analysis library depend on the date library or the other
+// way around?
+
+#define DaysInMonth analysishelper_DaysInMonth
+#define DateToDays analysishelper_DateToDays
+#define DaysToDate analysishelper_DaysToDate
+#define GetNullDate analysishelper_GetNullDate
+
+#endif
+
+sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear );
+sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear );
+/// @throws css::lang::IllegalArgumentException
+void DaysToDate( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear );
+/// @throws css::uno::RuntimeException
+sal_Int32 GetNullDate( const css::uno::Reference< css::beans::XPropertySet >& xOptions );
+sal_Int32 GetDiffDate360(
+ sal_uInt16 nDay1, sal_uInt16 nMonth1, sal_uInt16 nYear1, bool bLeapYear1,
+ sal_uInt16 nDay2, sal_uInt16 nMonth2, sal_uInt16 nYear2,
+ bool bUSAMethod );
+inline sal_Int32 GetDiffDate360( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nDate1, sal_Int32 nDate2, bool bUSAMethod );
+sal_Int32 GetDiffDate360( sal_Int32 nNullDate, sal_Int32 nDate1, sal_Int32 nDate2, bool bUSAMethod );
+
+sal_Int32 GetDaysInYears( sal_uInt16 nYear1, sal_uInt16 nYear2 );
+inline sal_Int16 GetDayOfWeek( sal_Int32 nDate );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+sal_Int32 GetDiffDate( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
+ sal_Int32* pOptDaysIn1stYear );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetYearDiff( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+sal_Int32 GetDaysInYear( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nMode );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+inline double GetYearFrac( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode );
+
+double BinomialCoefficient( double n, double k );
+double GetGcd( double f1, double f2 );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double ConvertToDec( const OUString& rFromNum, sal_uInt16 nBaseFrom, sal_uInt16 nCharLim );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+OUString ConvertFromDec(
+ double fNum, double fMin, double fMax, sal_uInt16 nBase,
+ sal_Int32 nPlaces, sal_Int32 nMaxPlaces, bool bUsePlaces );
+double Erf( double fX );
+double Erfc( double fX );
+bool ParseDouble( const sal_Unicode*& rpDoubleAsString, double& rReturn );
+OUString GetString( double fNumber, bool bLeadingSign, sal_uInt16 nMaxNumOfDigits = 15 );
+
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetAmordegrc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
+ double fRestVal, double fPer, double fRate, sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetAmorlinc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
+ double fRestVal, double fPer, double fRate, sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetDuration( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup,
+ double fYield, sal_Int32 nFreq, sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetYieldmat( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
+ double fRate, double fPrice, sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetOddfprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
+ sal_Int32 nFirstCoup, double fRate, double fYield, double fRedemp,
+ sal_Int32 nFreq, sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double getYield_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice,
+ double fRedemp, sal_Int32 nFreq, sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double getPrice_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield,
+ double fRedemp, sal_Int32 nFreq, sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetOddfyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
+ sal_Int32 nFirstCoup, double fRate, double fPrice, double fRedemp,
+ sal_Int32 nFreq, sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetOddlprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastInterest,
+ double fRate, double fYield, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetOddlyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastInterest,
+ double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase );
+double GetPmt( double fRate, double fNper, double fPv, double fFv, sal_Int32 nPayType );
+double GetFv( double fRate, double fNper, double fPmt, double fPv, sal_Int32 nPayType );
+
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetCouppcd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq,
+ sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetCoupncd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq,
+ sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetCoupdaybs( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq,
+ sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetCoupdaysnc( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq,
+ sal_Int32 nBase );
+
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetCoupnum( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat,
+ sal_Int32 nFreq, sal_Int32 nBase );
+/// @throws css::uno::RuntimeException
+/// @throws css::lang::IllegalArgumentException
+double GetCoupdays( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq,
+ sal_Int32 nBase );
+
+
+enum class FDCategory
+{
+ DateTime,
+ Finance,
+ Inf,
+ Math,
+ Tech
+};
+
+
+struct FuncDataBase
+{
+ const char* pIntName;
+ TranslateId pUINameID; // resource ID to UI name
+ const TranslateId* pDescrID; // resource ID to description, parameter names and ~ description
+ bool bDouble; // name already exist in Calc
+ bool bWithOpt; // first parameter is internal
+ const char** pCompListID; // list of valid names
+ sal_uInt16 nNumOfParams; // number of named / described parameters
+ FDCategory eCat; // function category
+ const char* pSuffix; // if bDouble, append a suffix other than "_ADD" for UI
+};
+
+
+class FuncData final
+{
+private:
+ OUString aIntName;
+ TranslateId pUINameID;
+ const TranslateId* pDescrID; // leads also to parameter descriptions!
+ bool bDouble; // flag for names that already exist in Calc
+ bool bWithOpt; // has internal parameter on first position
+
+ sal_uInt16 nParam; // num of parameters
+ std::vector<OUString> aCompList; // list of all valid names
+ FDCategory eCat; // function category
+ OUString aSuffix; // if bDouble and not empty, append a suffix other than "_ADD" for UI
+
+public:
+ FuncData(const FuncDataBase& rBaseData);
+
+ inline const TranslateId& GetUINameID() const;
+ inline const TranslateId* GetDescrID() const;
+ inline bool IsDouble() const;
+ inline const OUString& GetSuffix() const;
+
+ sal_uInt16 GetStrIndex( sal_uInt16 nParamNum ) const;
+ inline bool Is( std::u16string_view rCompareTo ) const;
+
+ inline const std::vector<OUString> &
+ GetCompNameList() const;
+
+ inline FDCategory GetCategory() const;
+};
+
+typedef std::vector< FuncData > FuncDataList;
+
+void InitFuncDataList(FuncDataList& rList);
+
+// Predicate for use with std::find_if
+struct FindFuncData
+{
+ const OUString& m_rId;
+ explicit FindFuncData( const OUString& rId ) : m_rId(rId) {}
+ bool operator() ( FuncData const & rCandidate ) const { return rCandidate.Is(m_rId); }
+};
+
+/// sorted list with unique sal_Int32 values
+class SortedIndividualInt32List final
+{
+private:
+ std::vector<sal_Int32> maVector;
+
+ void Insert( sal_Int32 nDay );
+ void Insert( sal_Int32 nDay, sal_Int32 nNullDate, bool bInsertOnWeekend );
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Insert( double fDay, sal_Int32 nNullDate, bool bInsertOnWeekend );
+
+ /** @param rAnyConv must be an initialized ScaAnyConmverter
+ @param bInsertOnWeekend insertion mode: false = holidays on weekend are omitted
+ @throws css::uno::RuntimeException
+ @throws css::lang::IllegalArgumentException
+ */
+ void InsertHolidayList(
+ const ScaAnyConverter& rAnyConv,
+ const css::uno::Any& rHolAny,
+ sal_Int32 nNullDate,
+ bool bInsertOnWeekend );
+
+public:
+ SortedIndividualInt32List();
+ ~SortedIndividualInt32List();
+
+ sal_uInt32 Count() const
+ { return maVector.size(); }
+
+ /// @return element on position nIndex or 0 on invalid index
+ sal_Int32 Get( sal_uInt32 n ) const
+ { return maVector[n]; }
+
+ /// @return true if nVal (internal date representation) is contained
+ bool Find( sal_Int32 nVal ) const;
+
+ /** @param rAnyConv is an initialized or uninitialized ScaAnyConverter
+ holidays on weekend are omitted
+ @throws css::uno::RuntimeException
+ @throws css::lang::IllegalArgumentException
+ */
+ void InsertHolidayList(
+ ScaAnyConverter& rAnyConv,
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ const css::uno::Any& rHolAny,
+ sal_Int32 nNullDate);
+};
+
+
+class ScaDoubleList
+{
+private:
+ std::vector<double> maVector;
+protected:
+ void ListAppend( double fValue ) { maVector.push_back(fValue); }
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Append( double fValue )
+ { if( CheckInsert( fValue ) ) ListAppend( fValue ); }
+
+ /** @param rAnyConv must be an initialized ScaAnyConmverter
+ @param bIgnoreEmpty handling of empty Any's/strings: false = inserted as 0.0; true = omitted
+ @throws css::uno::RuntimeException
+ @throws css::lang::IllegalArgumentException
+ */
+ void Append(
+ const ScaAnyConverter& rAnyConv,
+ const css::uno::Any& rAny,
+ bool bIgnoreEmpty );
+
+ /** @param rAnyConv must be an initialized ScaAnyConmverter
+ @param bIgnoreEmpty handling of empty Any's/strings: false = inserted as 0.0; true = omitted
+ @throws css::uno::RuntimeException
+ @throws css::lang::IllegalArgumentException
+ */
+ void Append(
+ const ScaAnyConverter& rAnyConv,
+ const css::uno::Sequence< css::uno::Any >& rAnySeq,
+ bool bIgnoreEmpty );
+
+ /** @param rAnyConv must be an initialized ScaAnyConmverter
+ @param bIgnoreEmpty handling of empty Any's/strings: false = inserted as 0.0; true = omitted
+ @throws css::uno::RuntimeException
+ @throws css::lang::IllegalArgumentException
+ */
+ void Append(
+ const ScaAnyConverter& rAnyConv,
+ const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& rAnySeq,
+ bool bIgnoreEmpty );
+
+public:
+ virtual ~ScaDoubleList() {}
+
+ sal_uInt32 Count() const
+ { return maVector.size(); }
+ double Get( sal_uInt32 n ) const
+ { return maVector[n]; }
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Append( const css::uno::Sequence< css::uno::Sequence< double > >& rValueArr );
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Append( const css::uno::Sequence< css::uno::Sequence< sal_Int32 > >& rValueArr );
+
+ /** @param rAnyConv is an initialized or uninitialized ScaAnyConverter
+ @param bIgnoreEmpty handling of empty Any's/strings: false = inserted as 0.0; true = omitted
+ @throws css::uno::RuntimeException
+ @throws css::lang::IllegalArgumentException
+ */
+ void Append(
+ ScaAnyConverter& rAnyConv,
+ const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ const css::uno::Sequence< css::uno::Any >& rAnySeq );
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ virtual bool CheckInsert( double fValue ) const;
+};
+
+
+/// stores double values >0.0, throws exception for double values <0.0, does nothing for 0.0
+class ScaDoubleListGT0 : public ScaDoubleList
+{
+public:
+ virtual bool CheckInsert( double fValue ) const override;
+};
+
+
+/// stores double values >=0.0, throws exception for double values <0.0
+class ScaDoubleListGE0 : public ScaDoubleList
+{
+public:
+ virtual bool CheckInsert( double fValue ) const override;
+};
+
+
+class Complex
+{
+ double r;
+ double i;
+ sal_Unicode c;
+
+public:
+ inline Complex( double fReal, double fImag = 0.0, sal_Unicode cC = '\0' );
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ explicit Complex( const OUString& rComplexAsString );
+
+ inline static bool IsImagUnit( sal_Unicode c );
+ static bool ParseString( const OUString& rComplexAsString, Complex& rReturn );
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ OUString GetString() const;
+
+ inline double Real() const;
+ inline double Imag() const;
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ double Arg() const;
+ inline double Abs() const;
+
+ // following functions change the complex number itself to avoid unnecessary copy actions!
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Power( double fPower );
+ void Sqrt();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Sin();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Cos();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Div( const Complex& rDivisor );
+ void Exp();
+ inline void Conjugate();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Ln();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Log10();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Log2();
+ inline void Mult( double fFact );
+ inline void Mult( const Complex& rMult );
+ inline void Sub( const Complex& rMult );
+ inline void Add( const Complex& rAdd );
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Tan();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Sec();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Csc();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Cot();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Sinh();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Cosh();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Sech();
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Csch();
+
+};
+
+
+class ComplexList final
+{
+private:
+ std::vector<Complex> maVector;
+public:
+ ~ComplexList();
+
+ inline const Complex& Get( sal_uInt32 nIndex ) const;
+
+ bool empty() const
+ { return maVector.empty(); }
+ sal_uInt32 Count() const
+ { return maVector.size(); }
+
+ inline void Append( Complex&& pNew );
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Append( const css::uno::Sequence< css::uno::Sequence< OUString > >& rComplexNumList );
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ void Append( const css::uno::Sequence< css::uno::Any >& aMultPars );
+};
+
+
+enum ConvertDataClass
+{
+ CDC_Mass, CDC_Length, CDC_Time, CDC_Pressure, CDC_Force, CDC_Energy, CDC_Power, CDC_Magnetism,
+ CDC_Temperature, CDC_Volume, CDC_Area, CDC_Speed, CDC_Information
+};
+
+
+#define INV_MATCHLEV 1764 // guess, what this is... :-)
+
+
+class ConvertData
+{
+protected:
+ friend class ConvertDataList;
+ double fConst;
+ OUString aName;
+ ConvertDataClass eClass;
+ bool bPrefixSupport;
+public:
+ ConvertData(
+ const char pUnitName[],
+ double fConvertConstant,
+ ConvertDataClass eClass,
+ bool bPrefSupport = false );
+
+ virtual ~ConvertData();
+
+ sal_Int16 GetMatchingLevel( const OUString& rRef ) const;
+ // 0.0 = no equality
+ // 1.0 = matches exact
+ // rest = matches without an assumed prefix of one character
+ // rest gives power for 10 represented by the prefix (e.g. 3 for k or -9 for n
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ virtual double Convert( double fVal, const ConvertData& rTo,
+ sal_Int16 nMatchLevelFrom, sal_Int16 nMatchLevelTo ) const;
+ virtual double ConvertFromBase( double fVal, sal_Int16 nMatchLevel ) const;
+
+ inline ConvertDataClass Class() const;
+};
+
+class ConvertDataLinear final : public ConvertData
+{
+ double fOffs;
+public:
+ inline ConvertDataLinear(
+ const char pUnitName[],
+ double fConvertConstant,
+ double fConvertOffset,
+ ConvertDataClass eClass,
+ bool bPrefSupport = false );
+
+ virtual ~ConvertDataLinear() override;
+
+ virtual double Convert( double fVal, const ConvertData& rTo,
+ sal_Int16 nMatchLevelFrom, sal_Int16 nMatchLevelTo ) const override;
+ // for cases where f(x) = a + bx applies (e.g. Temperatures)
+
+ // converts fVal from this unit to rFrom unit
+ // throws exception if not from same class
+ // this implementation is for proportional cases only
+ double ConvertToBase( double fVal, sal_Int16 nMatchLevel ) const;
+ virtual double ConvertFromBase( double fVal, sal_Int16 nMatchLevel ) const override;
+};
+
+
+class ConvertDataList
+{
+private:
+ std::vector<std::unique_ptr<ConvertData>> maVector;
+public:
+ ConvertDataList();
+ ~ConvertDataList();
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IllegalArgumentException
+ double Convert( double fVal, const OUString& rFrom, const OUString& rTo );
+};
+
+
+inline bool IsLeapYear( sal_uInt16 n )
+{
+ return ( (( ( n % 4 ) == 0 ) && ( ( n % 100 ) != 0)) || ( ( n % 400 ) == 0 ) );
+}
+
+
+inline sal_Int32 GetDiffDate360( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nDate1, sal_Int32 nDate2, bool bUSAMethod )
+{
+ return GetDiffDate360( GetNullDate( xOpt ), nDate1, nDate2, bUSAMethod );
+}
+
+
+inline sal_Int16 GetDayOfWeek( sal_Int32 n )
+{ // monday = 0, ..., sunday = 6
+ return static_cast< sal_Int16 >( ( n - 1 ) % 7 );
+}
+
+
+inline double GetYearFrac( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode )
+{
+ return GetYearFrac( GetNullDate( xOpt ), nStartDate, nEndDate, nMode );
+}
+
+
+inline const TranslateId& FuncData::GetUINameID() const
+{
+ return pUINameID;
+}
+
+
+inline const TranslateId* FuncData::GetDescrID() const
+{
+ return pDescrID;
+}
+
+
+inline bool FuncData::IsDouble() const
+{
+ return bDouble;
+}
+
+
+inline const OUString& FuncData::GetSuffix() const
+{
+ return aSuffix;
+}
+
+
+inline bool FuncData::Is( std::u16string_view r ) const
+{
+ return aIntName == r;
+}
+
+
+inline const std::vector<OUString> & FuncData::GetCompNameList() const
+{
+ return aCompList;
+}
+
+
+inline FDCategory FuncData::GetCategory() const
+{
+ return eCat;
+}
+
+
+inline Complex::Complex( double fReal, double fImag, sal_Unicode cC ) :
+ r( fReal ), i( fImag ), c( cC )
+{
+}
+
+
+inline double Complex::Real() const
+{
+ return r;
+}
+
+
+inline double Complex::Imag() const
+{
+ return i;
+}
+
+
+inline double Complex::Abs() const
+{
+ return sqrt( r * r + i * i );
+}
+
+
+void Complex::Conjugate()
+{
+ i = -i;
+}
+
+
+inline void Complex::Mult( double f )
+{
+ i *= f;
+ r *= f;
+}
+
+
+inline void Complex::Mult( const Complex& rM )
+{
+ double r_ = r;
+ double i_ = i;
+
+ r = r_ * rM.r - i_ * rM.i;
+ i = r_ * rM.i + i_ * rM.r;
+
+ if( !c ) c = rM.c;
+}
+
+
+inline void Complex::Sub( const Complex& rC )
+{
+ r -= rC.r;
+ i -= rC.i;
+ if( !c ) c = rC.c;
+}
+
+
+inline void Complex::Add( const Complex& rAdd )
+{
+ r += rAdd.r;
+ i += rAdd.i;
+ if( !c ) c = rAdd.c;
+}
+
+
+inline const Complex& ComplexList::Get( sal_uInt32 n ) const
+{
+ return maVector[n];
+}
+
+
+inline void ComplexList::Append( Complex&& p )
+{
+ maVector.emplace_back(p);
+}
+
+
+inline ConvertDataClass ConvertData::Class() const
+{
+ return eClass;
+}
+
+inline ConvertDataLinear::ConvertDataLinear( const char p[], double fC, double fO, ConvertDataClass e,
+ bool bPrefSupport ) :
+ ConvertData( p, fC, e, bPrefSupport ),
+ fOffs( fO )
+{
+}
+
+
+/// Helper class for date calculation for various financial functions
+class ScaDate
+{
+private:
+ sal_uInt16 nOrigDay; /// is the day of the original date.
+ sal_uInt16 nDay; /// is the calculated day depending on the current month/year.
+ sal_uInt16 nMonth; /// is the current month (one-based).
+ sal_uInt16 nYear; /// is the current year.
+ bool bLastDayMode : 1; /// if true, recalculate nDay after every calculation.
+ bool bLastDay : 1; /// is true, if original date was the last day in month.
+ bool b30Days : 1; /// is true, if every month has 30 days in calculations.
+ bool bUSMode : 1; /// is true, if the US method of 30-day-calculations is used.
+
+ /// Calculates nDay from nOrigDay and current date.
+ void setDay();
+
+ /// @return count of days in current month
+ inline sal_uInt16 getDaysInMonth() const;
+ /// @return count of days in given month
+ inline sal_uInt16 getDaysInMonth( sal_uInt16 _nMon ) const;
+
+ /// @ return count of days in the given month range
+ sal_Int32 getDaysInMonthRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const;
+ /// @ return count of days in the given year range
+ sal_Int32 getDaysInYearRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const;
+
+ /// Adds/subtracts the given count of years, does not adjust day.
+ ///
+ /// @throws css::lang::IllegalArgumentException
+ void doAddYears( sal_Int32 nYearCount );
+
+public:
+ ScaDate();
+ /** @param nBase
+ date handling mode (days in month / days in year):
+ 0 = 30 days / 360 days (US NASD)
+ 1 = exact / exact
+ 2 = exact / 360
+ 3 = exact / 365
+ 4 = 30 days / 360 days (Europe)
+ 5 = exact / exact (no last day adjustment) */
+ ScaDate( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nBase );
+ ScaDate( const ScaDate& rCopy );
+ ScaDate& operator=( const ScaDate& rCopy );
+
+ /// @return the current month.
+ sal_uInt16 getMonth() const { return nMonth; };
+ /// @return the current year.
+ sal_uInt16 getYear() const { return nYear; };
+
+ /// adds/subtracts the given count of months, adjusts day
+ ///
+ /// @throws css::lang::IllegalArgumentException
+ void addMonths( sal_Int32 nMonthCount );
+
+ /// sets the given year, adjusts day
+ inline void setYear( sal_uInt16 nNewYear );
+ /// adds/subtracts the given count of years, adjusts day
+ ///
+ /// @throws css::lang::IllegalArgumentException
+ inline void addYears( sal_Int32 nYearCount );
+
+ /// @return the internal number of the current date
+ sal_Int32 getDate( sal_Int32 nNullDate ) const;
+ /// @return the number of days between the two dates
+ ///
+ /// @throws css::lang::IllegalArgumentException
+ static sal_Int32 getDiff( const ScaDate& rFrom, const ScaDate& rTo );
+
+ bool operator<( const ScaDate& rCmp ) const;
+ bool operator<=( const ScaDate& rCmp ) const { return !(rCmp < *this); }
+ bool operator>( const ScaDate& rCmp ) const { return rCmp < *this; }
+ bool operator>=( const ScaDate& rCmp ) const { return !(*this < rCmp); }
+};
+
+inline sal_uInt16 ScaDate::getDaysInMonth() const
+{
+ return getDaysInMonth( nMonth );
+}
+
+inline sal_uInt16 ScaDate::getDaysInMonth( sal_uInt16 _nMon ) const
+{
+ return b30Days ? 30 : DaysInMonth( _nMon, nYear );
+}
+
+inline void ScaDate::setYear( sal_uInt16 nNewYear )
+{
+ nYear = nNewYear;
+ setDay();
+}
+
+inline void ScaDate::addYears( sal_Int32 nYearCount )
+{
+ doAddYears( nYearCount );
+ setDay();
+}
+
+
+/// Helper class for Any->double conversion, using current language settings
+class ScaAnyConverter
+{
+private:
+ css::uno::Reference< css::util::XNumberFormatter2 > xFormatter;
+ sal_Int32 nDefaultFormat;
+ bool bHasValidFormat;
+
+ /** Converts a string to double using the number formatter. If the formatter is not
+ valid, ::rtl::math::stringToDouble() with english separators will be used.
+ @throws css::lang::IllegalArgumentException
+ on strings not representing any double value.
+ @return the converted double value. */
+ double convertToDouble(
+ const OUString& rString ) const;
+
+public:
+ explicit ScaAnyConverter(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext );
+ ~ScaAnyConverter();
+
+ /// Initializing with current language settings
+ ///
+ /// @throws css::uno::RuntimeException
+ void init(
+ const css::uno::Reference< css::beans::XPropertySet >& xPropSet );
+
+ /** Converts an Any to double (without initialization).
+ The Any can be empty or contain a double or string.
+ @throws css::lang::IllegalArgumentException
+ on other Any types or on invalid strings.
+ @return true if the Any contains a double or a non-empty valid string,
+ false if the Any is empty or the string is empty */
+ bool getDouble(
+ double& rfResult,
+ const css::uno::Any& rAny ) const;
+
+ /** Converts an Any to double (with initialization).
+ The Any can be empty or contain a double or string.
+ @throws css::lang::IllegalArgumentException
+ on other Any types or on invalid strings.
+ @return true if the Any contains a double or a non-empty valid string,
+ false if the Any is empty or the string is empty */
+ bool getDouble(
+ double& rfResult,
+ const css::uno::Reference< css::beans::XPropertySet >& xPropSet,
+ const css::uno::Any& rAny );
+
+ /** Converts an Any to double (with initialization).
+ The Any can be empty or contain a double or string.
+ @throws css::lang::IllegalArgumentException
+ on other Any types or on invalid strings.
+ @return the value of the double or string or fDefault if the Any or string is empty */
+ double getDouble(
+ const css::uno::Reference< css::beans::XPropertySet >& xPropSet,
+ const css::uno::Any& rAny,
+ double fDefault );
+
+ /** Converts an Any to sal_Int32 (with initialization).
+ The Any can be empty or contain a double or string.
+ @throws css::lang::IllegalArgumentException
+ on other Any types or on invalid values or strings.
+ @return true if the Any contains a double or a non-empty valid string,
+ false if the Any is empty or the string is empty */
+ bool getInt32(
+ sal_Int32& rnResult,
+ const css::uno::Reference< css::beans::XPropertySet >& xPropSet,
+ const css::uno::Any& rAny );
+
+ /** Converts an Any to sal_Int32 (with initialization).
+ The Any can be empty or contain a double or string.
+ @throws css::lang::IllegalArgumentException
+ on other Any types or on invalid values or strings.
+ @return the truncated value of the double or string or nDefault if the Any or string is empty */
+ sal_Int32 getInt32(
+ const css::uno::Reference< css::beans::XPropertySet >& xPropSet,
+ const css::uno::Any& rAny,
+ sal_Int32 nDefault );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/analysis/bessel.cxx b/scaddins/source/analysis/bessel.cxx
new file mode 100644
index 000000000..44b79e798
--- /dev/null
+++ b/scaddins/source/analysis/bessel.cxx
@@ -0,0 +1,452 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "bessel.hxx"
+#include <cmath>
+#include <rtl/math.hxx>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/sheet/NoConvergenceException.hpp>
+
+using ::com::sun::star::lang::IllegalArgumentException;
+using ::com::sun::star::sheet::NoConvergenceException;
+
+namespace sca::analysis {
+
+// BESSEL J
+
+
+/* The BESSEL function, first kind, unmodified:
+ The algorithm follows
+ http://www.reference-global.com/isbn/978-3-11-020354-7
+ Numerical Mathematics 1 / Numerische Mathematik 1,
+ An algorithm-based introduction / Eine algorithmisch orientierte Einfuehrung
+ Deuflhard, Peter; Hohmann, Andreas
+ Berlin, New York (Walter de Gruyter) 2008
+ 4. ueberarb. u. erw. Aufl. 2008
+ eBook ISBN: 978-3-11-020355-4
+ Chapter 6.3.2 , algorithm 6.24
+ The source is in German.
+ The BesselJ-function is a special case of the adjoint summation with
+ a_k = 2*(k-1)/x for k=1,...
+ b_k = -1, for all k, directly substituted
+ m_0=1, m_k=2 for k even, and m_k=0 for k odd, calculated on the fly
+ alpha_k=1 for k=N and alpha_k=0 otherwise
+*/
+
+double BesselJ( double x, sal_Int32 N )
+
+{
+ if( N < 0 )
+ throw IllegalArgumentException();
+ if (x==0.0)
+ return (N==0) ? 1.0 : 0.0;
+
+ /* The algorithm works only for x>0, therefore remember sign. BesselJ
+ with integer order N is an even function for even N (means J(-x)=J(x))
+ and an odd function for odd N (means J(-x)=-J(x)).*/
+ double fSign = (N % 2 == 1 && x < 0) ? -1.0 : 1.0;
+ double fX = fabs(x);
+
+ const double fMaxIteration = 9000000.0; //experimental, for to return in < 3 seconds
+ double fEstimateIteration = fX * 1.5 + N;
+ bool bAsymptoticPossible = pow(fX,0.4) > N;
+ if (fEstimateIteration > fMaxIteration)
+ {
+ if (!bAsymptoticPossible)
+ throw NoConvergenceException();
+ return fSign * sqrt(M_2_PI/fX)* cos(fX-N*M_PI_2-M_PI_4);
+ }
+
+ double const epsilon = 1.0e-15; // relative error
+ bool bHasfound = false;
+ double k= 0.0;
+ // e_{-1} = 0; e_0 = alpha_0 / b_2
+ double u ; // u_0 = e_0/f_0 = alpha_0/m_0 = alpha_0
+
+ // first used with k=1
+ double m_bar; // m_bar_k = m_k * f_bar_{k-1}
+ double g_bar; // g_bar_k = m_bar_k - a_{k+1} + g_{k-1}
+ double g_bar_delta_u; // g_bar_delta_u_k = f_bar_{k-1} * alpha_k
+ // - g_{k-1} * delta_u_{k-1} - m_bar_k * u_{k-1}
+ // f_{-1} = 0.0; f_0 = m_0 / b_2 = 1/(-1) = -1
+ double g = 0.0; // g_0= f_{-1} / f_0 = 0/(-1) = 0
+ double delta_u = 0.0; // dummy initialize, first used with * 0
+ double f_bar = -1.0; // f_bar_k = 1/f_k, but only used for k=0
+
+ if (N==0)
+ {
+ //k=0; alpha_0 = 1.0
+ u = 1.0; // u_0 = alpha_0
+ // k = 1.0; at least one step is necessary
+ // m_bar_k = m_k * f_bar_{k-1} ==> m_bar_1 = 0.0
+ g_bar_delta_u = 0.0; // alpha_k = 0.0, m_bar = 0.0; g= 0.0
+ g_bar = - 2.0/fX; // k = 1.0, g = 0.0
+ delta_u = g_bar_delta_u / g_bar;
+ u = u + delta_u ; // u_k = u_{k-1} + delta_u_k
+ g = -1.0 / g_bar; // g_k=b_{k+2}/g_bar_k
+ f_bar = f_bar * g; // f_bar_k = f_bar_{k-1}* g_k
+ k = 2.0;
+ // From now on all alpha_k = 0.0 and k > N+1
+ }
+ else
+ { // N >= 1 and alpha_k = 0.0 for k<N
+ u=0.0; // u_0 = alpha_0
+ for (k =1.0; k<= N-1; k = k + 1.0)
+ {
+ m_bar=2.0 * fmod(k-1.0, 2.0) * f_bar;
+ g_bar_delta_u = - g * delta_u - m_bar * u; // alpha_k = 0.0
+ g_bar = m_bar - 2.0*k/fX + g;
+ delta_u = g_bar_delta_u / g_bar;
+ u = u + delta_u;
+ g = -1.0/g_bar;
+ f_bar=f_bar * g;
+ }
+ // Step alpha_N = 1.0
+ m_bar=2.0 * fmod(k-1.0, 2.0) * f_bar;
+ g_bar_delta_u = f_bar - g * delta_u - m_bar * u; // alpha_k = 1.0
+ g_bar = m_bar - 2.0*k/fX + g;
+ delta_u = g_bar_delta_u / g_bar;
+ u = u + delta_u;
+ g = -1.0/g_bar;
+ f_bar = f_bar * g;
+ k = k + 1.0;
+ }
+ // Loop until desired accuracy, always alpha_k = 0.0
+ do
+ {
+ m_bar = 2.0 * fmod(k-1.0, 2.0) * f_bar;
+ g_bar_delta_u = - g * delta_u - m_bar * u;
+ g_bar = m_bar - 2.0*k/fX + g;
+ delta_u = g_bar_delta_u / g_bar;
+ u = u + delta_u;
+ g = -1.0/g_bar;
+ f_bar = f_bar * g;
+ bHasfound = (fabs(delta_u)<=fabs(u)*epsilon);
+ k = k + 1.0;
+ }
+ while (!bHasfound && k <= fMaxIteration);
+ if (!bHasfound)
+ throw NoConvergenceException(); // unlikely to happen
+
+ return u * fSign;
+}
+
+
+// BESSEL I
+
+
+/* The BESSEL function, first kind, modified:
+
+ inf (x/2)^(n+2k)
+ I_n(x) = SUM TERM(n,k) with TERM(n,k) := --------------
+ k=0 k! (n+k)!
+
+ No asymptotic approximation used, see issue 43040.
+ */
+
+double BesselI( double x, sal_Int32 n )
+{
+ const sal_Int32 nMaxIteration = 2000;
+ const double fXHalf = x / 2.0;
+ if( n < 0 )
+ throw IllegalArgumentException();
+
+ double fResult = 0.0;
+
+ /* Start the iteration without TERM(n,0), which is set here.
+
+ TERM(n,0) = (x/2)^n / n!
+ */
+ sal_Int32 nK = 0;
+ double fTerm = 1.0;
+ // avoid overflow in Fak(n)
+ for( nK = 1; nK <= n; ++nK )
+ {
+ fTerm = fTerm / static_cast< double >( nK ) * fXHalf;
+ }
+ fResult = fTerm; // Start result with TERM(n,0).
+ if( fTerm != 0.0 )
+ {
+ nK = 1;
+ const double fEpsilon = 1.0E-15;
+ do
+ {
+ /* Calculation of TERM(n,k) from TERM(n,k-1):
+
+ (x/2)^(n+2k)
+ TERM(n,k) = --------------
+ k! (n+k)!
+
+ (x/2)^2 (x/2)^(n+2(k-1))
+ = --------------------------
+ k (k-1)! (n+k) (n+k-1)!
+
+ (x/2)^2 (x/2)^(n+2(k-1))
+ = --------- * ------------------
+ k(n+k) (k-1)! (n+k-1)!
+
+ x^2/4
+ = -------- TERM(n,k-1)
+ k(n+k)
+ */
+ fTerm = fTerm * fXHalf / static_cast<double>(nK) * fXHalf / static_cast<double>(nK+n);
+ fResult += fTerm;
+ nK++;
+ }
+ while( (fabs( fTerm ) > fabs(fResult) * fEpsilon) && (nK < nMaxIteration) );
+
+ }
+ return fResult;
+}
+
+/// @throws IllegalArgumentException
+/// @throws NoConvergenceException
+static double Besselk0( double fNum )
+{
+ double fRet;
+
+ if( fNum <= 2.0 )
+ {
+ double fNum2 = fNum * 0.5;
+ double y = fNum2 * fNum2;
+
+ fRet = -log( fNum2 ) * BesselI( fNum, 0 ) +
+ ( -0.57721566 + y * ( 0.42278420 + y * ( 0.23069756 + y * ( 0.3488590e-1 +
+ y * ( 0.262698e-2 + y * ( 0.10750e-3 + y * 0.74e-5 ) ) ) ) ) );
+ }
+ else
+ {
+ double y = 2.0 / fNum;
+
+ fRet = exp( -fNum ) / sqrt( fNum ) * ( 1.25331414 + y * ( -0.7832358e-1 +
+ y * ( 0.2189568e-1 + y * ( -0.1062446e-1 + y * ( 0.587872e-2 +
+ y * ( -0.251540e-2 + y * 0.53208e-3 ) ) ) ) ) );
+ }
+
+ return fRet;
+}
+
+/// @throws IllegalArgumentException
+/// @throws NoConvergenceException
+static double Besselk1( double fNum )
+{
+ double fRet;
+
+ if( fNum <= 2.0 )
+ {
+ double fNum2 = fNum * 0.5;
+ double y = fNum2 * fNum2;
+
+ fRet = log( fNum2 ) * BesselI( fNum, 1 ) +
+ ( 1.0 + y * ( 0.15443144 + y * ( -0.67278579 + y * ( -0.18156897 + y * ( -0.1919402e-1 +
+ y * ( -0.110404e-2 + y * -0.4686e-4 ) ) ) ) ) )
+ / fNum;
+ }
+ else
+ {
+ double y = 2.0 / fNum;
+
+ fRet = exp( -fNum ) / sqrt( fNum ) * ( 1.25331414 + y * ( 0.23498619 +
+ y * ( -0.3655620e-1 + y * ( 0.1504268e-1 + y * ( -0.780353e-2 +
+ y * ( 0.325614e-2 + y * -0.68245e-3 ) ) ) ) ) );
+ }
+
+ return fRet;
+}
+
+
+double BesselK( double fNum, sal_Int32 nOrder )
+{
+ switch( nOrder )
+ {
+ case 0: return Besselk0( fNum );
+ case 1: return Besselk1( fNum );
+ default:
+ {
+ double fTox = 2.0 / fNum;
+ double fBkm = Besselk0( fNum );
+ double fBk = Besselk1( fNum );
+
+ for( sal_Int32 n = 1 ; n < nOrder ; n++ )
+ {
+ const double fBkp = fBkm + double( n ) * fTox * fBk;
+ fBkm = fBk;
+ fBk = fBkp;
+ }
+
+ return fBk;
+ }
+ }
+}
+
+
+// BESSEL Y
+
+
+/* The BESSEL function, second kind, unmodified:
+ The algorithm for order 0 and for order 1 follows
+ http://www.reference-global.com/isbn/978-3-11-020354-7
+ Numerical Mathematics 1 / Numerische Mathematik 1,
+ An algorithm-based introduction / Eine algorithmisch orientierte Einfuehrung
+ Deuflhard, Peter; Hohmann, Andreas
+ Berlin, New York (Walter de Gruyter) 2008
+ 4. ueberarb. u. erw. Aufl. 2008
+ eBook ISBN: 978-3-11-020355-4
+ Chapter 6.3.2 , algorithm 6.24
+ The source is in German.
+ See #i31656# for a commented version of the implementation, attachment #desc6
+ https://bz.apache.org/ooo/attachment.cgi?id=63609
+*/
+
+/// @throws IllegalArgumentException
+/// @throws NoConvergenceException
+static double Bessely0( double fX )
+{
+ // If fX > 2^64 then sin and cos fail
+ if (fX <= 0 || !rtl::math::isValidArcArg(fX))
+ throw IllegalArgumentException();
+ const double fMaxIteration = 9000000.0; // should not be reached
+ if (fX > 5.0e+6) // iteration is not considerable better then approximation
+ return sqrt(1/M_PI/fX)
+ *(std::sin(fX)-std::cos(fX));
+ const double epsilon = 1.0e-15;
+ const double EulerGamma = 0.57721566490153286060;
+ double alpha = log(fX/2.0)+EulerGamma;
+ double u = alpha;
+
+ double k = 1.0;
+ double g_bar_delta_u = 0.0;
+ double g_bar = -2.0 / fX;
+ double delta_u = g_bar_delta_u / g_bar;
+ double g = -1.0/g_bar;
+ double f_bar = -1 * g;
+
+ double sign_alpha = 1.0;
+ bool bHasFound = false;
+ k = k + 1;
+ do
+ {
+ double km1mod2 = fmod(k-1.0, 2.0);
+ double m_bar = (2.0*km1mod2) * f_bar;
+ if (km1mod2 == 0.0)
+ alpha = 0.0;
+ else
+ {
+ alpha = sign_alpha * (4.0/k);
+ sign_alpha = -sign_alpha;
+ }
+ g_bar_delta_u = f_bar * alpha - g * delta_u - m_bar * u;
+ g_bar = m_bar - (2.0*k)/fX + g;
+ delta_u = g_bar_delta_u / g_bar;
+ u = u+delta_u;
+ g = -1.0 / g_bar;
+ f_bar = f_bar*g;
+ bHasFound = (fabs(delta_u)<=fabs(u)*epsilon);
+ k=k+1;
+ }
+ while (!bHasFound && k<fMaxIteration);
+ if (!bHasFound)
+ throw NoConvergenceException(); // not likely to happen
+ return u*M_2_PI;
+}
+
+// See #i31656# for a commented version of this implementation, attachment #desc6
+// https://bz.apache.org/ooo/attachment.cgi?id=63609
+/// @throws IllegalArgumentException
+/// @throws NoConvergenceException
+static double Bessely1( double fX )
+{
+ // If fX > 2^64 then sin and cos fail
+ if (fX <= 0 || !rtl::math::isValidArcArg(fX))
+ throw IllegalArgumentException();
+ const double fMaxIteration = 9000000.0; // should not be reached
+ if (fX > 5.0e+6) // iteration is not considerable better then approximation
+ return - sqrt(1/M_PI/fX)
+ *(std::sin(fX)+std::cos(fX));
+ const double epsilon = 1.0e-15;
+ const double EulerGamma = 0.57721566490153286060;
+ double alpha = 1.0/fX;
+ double f_bar = -1.0;
+ double u = alpha;
+ double k = 1.0;
+ alpha = 1.0 - EulerGamma - log(fX/2.0);
+ double g_bar_delta_u = -alpha;
+ double g_bar = -2.0 / fX;
+ double delta_u = g_bar_delta_u / g_bar;
+ u = u + delta_u;
+ double g = -1.0/g_bar;
+ f_bar = f_bar * g;
+ double sign_alpha = -1.0;
+ bool bHasFound = false;
+ k = k + 1.0;
+ do
+ {
+ double km1mod2 = fmod(k-1.0,2.0);
+ double m_bar = (2.0*km1mod2) * f_bar;
+ double q = (k-1.0)/2.0;
+ if (km1mod2 == 0.0) // k is odd
+ {
+ alpha = sign_alpha * (1.0/q + 1.0/(q+1.0));
+ sign_alpha = -sign_alpha;
+ }
+ else
+ alpha = 0.0;
+ g_bar_delta_u = f_bar * alpha - g * delta_u - m_bar * u;
+ g_bar = m_bar - (2.0*k)/fX + g;
+ delta_u = g_bar_delta_u / g_bar;
+ u = u+delta_u;
+ g = -1.0 / g_bar;
+ f_bar = f_bar*g;
+ bHasFound = (fabs(delta_u)<=fabs(u)*epsilon);
+ k=k+1;
+ }
+ while (!bHasFound && k<fMaxIteration);
+ if (!bHasFound)
+ throw NoConvergenceException();
+ return -u*2.0/M_PI;
+}
+
+double BesselY( double fNum, sal_Int32 nOrder )
+{
+ switch( nOrder )
+ {
+ case 0: return Bessely0( fNum );
+ case 1: return Bessely1( fNum );
+ default:
+ {
+ double fTox = 2.0 / fNum;
+ double fBym = Bessely0( fNum );
+ double fBy = Bessely1( fNum );
+
+ for( sal_Int32 n = 1 ; n < nOrder ; n++ )
+ {
+ const double fByp = double( n ) * fTox * fBy - fBym;
+ fBym = fBy;
+ fBy = fByp;
+ }
+
+ return fBy;
+ }
+ }
+}
+
+} // namespace sca::analysis
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/analysis/bessel.hxx b/scaddins/source/analysis/bessel.hxx
new file mode 100644
index 000000000..d42725432
--- /dev/null
+++ b/scaddins/source/analysis/bessel.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+namespace sca::analysis
+{
+// BESSEL functions
+
+/** Returns the result for the unmodified BESSEL function of first kind (J), n-th order, at point x.
+
+ @throws css::lang::IllegalArgumentException
+ @throws css::sheet::NoConvergenceException
+*/
+double BesselJ(double x, sal_Int32 n);
+
+/** Returns the result for the modified BESSEL function of first kind (I), n-th order, at point x.
+
+ @throws css::lang::IllegalArgumentException
+ @throws css::sheet::NoConvergenceException
+*/
+double BesselI(double x, sal_Int32 n);
+
+/** Returns the result for the unmodified BESSEL function of second kind (Y), n-th order, at point x.
+
+ @throws css::lang::IllegalArgumentException
+ @throws css::sheet::NoConvergenceException
+*/
+double BesselY(double x, sal_Int32 n);
+
+/** Returns the result for the modified BESSEL function of second kind (K), n-th order, at point x.
+
+ @throws css::lang::IllegalArgumentException
+ @throws css::sheet::NoConvergenceException
+*/
+double BesselK(double x, sal_Int32 n);
+
+} // namespace sca::analysis
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/analysis/deffuncname.hxx b/scaddins/source/analysis/deffuncname.hxx
new file mode 100644
index 000000000..2e92394e6
--- /dev/null
+++ b/scaddins/source/analysis/deffuncname.hxx
@@ -0,0 +1,628 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+static const char* ANALYSIS_DEFFUNCNAME_Workday[2] =
+{
+ reinterpret_cast<char const *>(u8"ARBEITSTAG"),
+ reinterpret_cast<char const *>(u8"WORKDAY")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Yearfrac[2] =
+{
+ reinterpret_cast<char const *>(u8"BRTEILJAHRE"),
+ reinterpret_cast<char const *>(u8"YEARFRAC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Edate[2] =
+{
+ reinterpret_cast<char const *>(u8"EDATUM"),
+ reinterpret_cast<char const *>(u8"EDATE")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Weeknum[2] =
+{
+ reinterpret_cast<char const *>(u8"KALENDERWOCHE"),
+ reinterpret_cast<char const *>(u8"WEEKNUM")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Eomonth[2] =
+{
+ reinterpret_cast<char const *>(u8"MONATSENDE"),
+ reinterpret_cast<char const *>(u8"EOMONTH")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Networkdays[2] =
+{
+ reinterpret_cast<char const *>(u8"NETTOARBEITSTAGE"),
+ reinterpret_cast<char const *>(u8"NETWORKDAYS")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Amordegrc[2] =
+{
+ reinterpret_cast<char const *>(u8"AMORDEGRK"),
+ reinterpret_cast<char const *>(u8"AMORDEGRC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Amorlinc[2] =
+{
+ reinterpret_cast<char const *>(u8"AMORLINEARK"),
+ reinterpret_cast<char const *>(u8"AMORLINC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Accrint[2] =
+{
+ reinterpret_cast<char const *>(u8"AUFGELZINS"),
+ reinterpret_cast<char const *>(u8"ACCRINT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Accrintm[2] =
+{
+ reinterpret_cast<char const *>(u8"AUFGELZINSF"),
+ reinterpret_cast<char const *>(u8"ACCRINTM")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Received[2] =
+{
+ reinterpret_cast<char const *>(u8"AUSZAHLUNG"),
+ reinterpret_cast<char const *>(u8"RECEIVED")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Disc[2] =
+{
+ reinterpret_cast<char const *>(u8"DISAGIO"),
+ reinterpret_cast<char const *>(u8"DISC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Duration[2] =
+{
+ reinterpret_cast<char const *>(u8"DURATION"),
+ reinterpret_cast<char const *>(u8"DURATION")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Effect[2] =
+{
+ reinterpret_cast<char const *>(u8"EFFEKTIV"),
+ reinterpret_cast<char const *>(u8"EFFECT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Cumprinc[2] =
+{
+ reinterpret_cast<char const *>(u8"KUMKAPITAL"),
+ reinterpret_cast<char const *>(u8"CUMPRINC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Cumipmt[2] =
+{
+ reinterpret_cast<char const *>(u8"KUMZINSZ"),
+ reinterpret_cast<char const *>(u8"CUMIPMT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Price[2] =
+{
+ reinterpret_cast<char const *>(u8"KURS"),
+ reinterpret_cast<char const *>(u8"PRICE")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Pricedisc[2] =
+{
+ reinterpret_cast<char const *>(u8"KURSDISAGIO"),
+ reinterpret_cast<char const *>(u8"PRICEDISC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Pricemat[2] =
+{
+ reinterpret_cast<char const *>(u8"KURSFÄLLIG"),
+ reinterpret_cast<char const *>(u8"PRICEMAT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Mduration[2] =
+{
+ reinterpret_cast<char const *>(u8"MDURATION"),
+ reinterpret_cast<char const *>(u8"MDURATION")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Nominal[2] =
+{
+ reinterpret_cast<char const *>(u8"NOMINAL"),
+ reinterpret_cast<char const *>(u8"NOMINAL")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Dollarfr[2] =
+{
+ reinterpret_cast<char const *>(u8"NOTIERUNGBRU"),
+ reinterpret_cast<char const *>(u8"DOLLARFR")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Dollarde[2] =
+{
+ reinterpret_cast<char const *>(u8"NOTIERUNGDEZ"),
+ reinterpret_cast<char const *>(u8"DOLLARDE")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Yield[2] =
+{
+ reinterpret_cast<char const *>(u8"RENDITE"),
+ reinterpret_cast<char const *>(u8"YIELD")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Yielddisc[2] =
+{
+ reinterpret_cast<char const *>(u8"RENDITEDIS"),
+ reinterpret_cast<char const *>(u8"YIELDDISC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Yieldmat[2] =
+{
+ reinterpret_cast<char const *>(u8"RENDITEFÄLL"),
+ reinterpret_cast<char const *>(u8"YIELDMAT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Tbilleq[2] =
+{
+ reinterpret_cast<char const *>(u8"TBILLÄQUIV"),
+ reinterpret_cast<char const *>(u8"TBILLEQ")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Tbillprice[2] =
+{
+ reinterpret_cast<char const *>(u8"TBILLKURS"),
+ reinterpret_cast<char const *>(u8"TBILLPRICE")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Tbillyield[2] =
+{
+ reinterpret_cast<char const *>(u8"TBILLRENDITE"),
+ reinterpret_cast<char const *>(u8"TBILLYIELD")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Oddfprice[2] =
+{
+ reinterpret_cast<char const *>(u8"UNREGER.KURS"),
+ reinterpret_cast<char const *>(u8"ODDFPRICE")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Oddfyield[2] =
+{
+ reinterpret_cast<char const *>(u8"UNREGER.REND"),
+ reinterpret_cast<char const *>(u8"ODDFYIELD")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Oddlprice[2] =
+{
+ reinterpret_cast<char const *>(u8"UNREGLE.KURS"),
+ reinterpret_cast<char const *>(u8"ODDLPRICE")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Oddlyield[2] =
+{
+ reinterpret_cast<char const *>(u8"UNREGLE.REND"),
+ reinterpret_cast<char const *>(u8"ODDLYIELD")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Xirr[2] =
+{
+ reinterpret_cast<char const *>(u8"XINTZINSFUSS"),
+ reinterpret_cast<char const *>(u8"XIRR")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Xnpv[2] =
+{
+ reinterpret_cast<char const *>(u8"XKAPITALWERT"),
+ reinterpret_cast<char const *>(u8"XNPV")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Intrate[2] =
+{
+ reinterpret_cast<char const *>(u8"ZINSSATZ"),
+ reinterpret_cast<char const *>(u8"INTRATE")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Coupncd[2] =
+{
+ reinterpret_cast<char const *>(u8"ZINSTERMNZ"),
+ reinterpret_cast<char const *>(u8"COUPNCD")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Coupdays[2] =
+{
+ reinterpret_cast<char const *>(u8"ZINSTERMTAGE"),
+ reinterpret_cast<char const *>(u8"COUPDAYS")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Coupdaysnc[2] =
+{
+ reinterpret_cast<char const *>(u8"ZINSTERMTAGNZ"),
+ reinterpret_cast<char const *>(u8"COUPDAYSNC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Coupdaybs[2] =
+{
+ reinterpret_cast<char const *>(u8"ZINSTERMTAGVA"),
+ reinterpret_cast<char const *>(u8"COUPDAYBS")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Couppcd[2] =
+{
+ reinterpret_cast<char const *>(u8"ZINSTERMVZ"),
+ reinterpret_cast<char const *>(u8"COUPPCD")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Coupnum[2] =
+{
+ reinterpret_cast<char const *>(u8"ZINSTERMZAHL"),
+ reinterpret_cast<char const *>(u8"COUPNUM")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Fvschedule[2] =
+{
+ reinterpret_cast<char const *>(u8"ZW2"),
+ reinterpret_cast<char const *>(u8"FVSCHEDULE")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Iseven[2] =
+{
+ reinterpret_cast<char const *>(u8"ISTGERADE"),
+ reinterpret_cast<char const *>(u8"ISEVEN")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Isodd[2] =
+{
+ reinterpret_cast<char const *>(u8"ISTUNGERADE"),
+ reinterpret_cast<char const *>(u8"ISODD")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Gcd[2] =
+{
+ reinterpret_cast<char const *>(u8"GGT"),
+ reinterpret_cast<char const *>(u8"GCD")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Lcm[2] =
+{
+ reinterpret_cast<char const *>(u8"KGV"),
+ reinterpret_cast<char const *>(u8"LCM")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Multinomial[2] =
+{
+ reinterpret_cast<char const *>(u8"POLYNOMIAL"),
+ reinterpret_cast<char const *>(u8"MULTINOMIAL")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Seriessum[2] =
+{
+ reinterpret_cast<char const *>(u8"POTENZREIHE"),
+ reinterpret_cast<char const *>(u8"SERIESSUM")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Quotient[2] =
+{
+ reinterpret_cast<char const *>(u8"QUOTIENT"),
+ reinterpret_cast<char const *>(u8"QUOTIENT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Mround[2] =
+{
+ reinterpret_cast<char const *>(u8"VRUNDEN"),
+ reinterpret_cast<char const *>(u8"MROUND")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Sqrtpi[2] =
+{
+ reinterpret_cast<char const *>(u8"WURZELPI"),
+ reinterpret_cast<char const *>(u8"SQRTPI")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Randbetween[2] =
+{
+ reinterpret_cast<char const *>(u8"ZUFALLSBEREICH"),
+ reinterpret_cast<char const *>(u8"RANDBETWEEN")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Besseli[2] =
+{
+ reinterpret_cast<char const *>(u8"BESSELI"),
+ reinterpret_cast<char const *>(u8"BESSELI")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Besselj[2] =
+{
+ reinterpret_cast<char const *>(u8"BESSELJ"),
+ reinterpret_cast<char const *>(u8"BESSELJ")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Besselk[2] =
+{
+ reinterpret_cast<char const *>(u8"BESSELK"),
+ reinterpret_cast<char const *>(u8"BESSELK")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Bessely[2] =
+{
+ reinterpret_cast<char const *>(u8"BESSELY"),
+ reinterpret_cast<char const *>(u8"BESSELY")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Bin2Dec[2] =
+{
+ reinterpret_cast<char const *>(u8"BININDEZ"),
+ reinterpret_cast<char const *>(u8"BIN2DEC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Bin2Hex[2] =
+{
+ reinterpret_cast<char const *>(u8"BININHEX"),
+ reinterpret_cast<char const *>(u8"BIN2HEX")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Bin2Oct[2] =
+{
+ reinterpret_cast<char const *>(u8"BININOKT"),
+ reinterpret_cast<char const *>(u8"BIN2OCT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Delta[2] =
+{
+ reinterpret_cast<char const *>(u8"DELTA"),
+ reinterpret_cast<char const *>(u8"DELTA")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Dec2Bin[2] =
+{
+ reinterpret_cast<char const *>(u8"DEZINBIN"),
+ reinterpret_cast<char const *>(u8"DEC2BIN")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Dec2Hex[2] =
+{
+ reinterpret_cast<char const *>(u8"DEZINHEX"),
+ reinterpret_cast<char const *>(u8"DEC2HEX")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Dec2Oct[2] =
+{
+ reinterpret_cast<char const *>(u8"DEZINOKT"),
+ reinterpret_cast<char const *>(u8"DEC2OCT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Erf[2] =
+{
+ reinterpret_cast<char const *>(u8"GAUSSFEHLER"),
+ reinterpret_cast<char const *>(u8"ERF")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Erfc[2] =
+{
+ reinterpret_cast<char const *>(u8"GAUSSFKOMPL"),
+ reinterpret_cast<char const *>(u8"ERFC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Gestep[2] =
+{
+ reinterpret_cast<char const *>(u8"GGANZZAHL"),
+ reinterpret_cast<char const *>(u8"GESTEP")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Hex2Bin[2] =
+{
+ reinterpret_cast<char const *>(u8"HEXINBIN"),
+ reinterpret_cast<char const *>(u8"HEX2BIN")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Hex2Dec[2] =
+{
+ reinterpret_cast<char const *>(u8"HEXINDEZ"),
+ reinterpret_cast<char const *>(u8"HEX2DEC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Hex2Oct[2] =
+{
+ reinterpret_cast<char const *>(u8"HEXINOKT"),
+ reinterpret_cast<char const *>(u8"HEX2OCT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imabs[2] =
+{
+ reinterpret_cast<char const *>(u8"IMABS"),
+ reinterpret_cast<char const *>(u8"IMABS")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imaginary[2] =
+{
+ reinterpret_cast<char const *>(u8"IMAGINÄRTEIL"),
+ reinterpret_cast<char const *>(u8"IMAGINARY")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Impower[2] =
+{
+ reinterpret_cast<char const *>(u8"IMAPOTENZ"),
+ reinterpret_cast<char const *>(u8"IMPOWER")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imargument[2] =
+{
+ reinterpret_cast<char const *>(u8"IMARGUMENT"),
+ reinterpret_cast<char const *>(u8"IMARGUMENT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imcos[2] =
+{
+ reinterpret_cast<char const *>(u8"IMCOS"),
+ reinterpret_cast<char const *>(u8"IMCOS")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imdiv[2] =
+{
+ reinterpret_cast<char const *>(u8"IMDIV"),
+ reinterpret_cast<char const *>(u8"IMDIV")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imexp[2] =
+{
+ reinterpret_cast<char const *>(u8"IMEXP"),
+ reinterpret_cast<char const *>(u8"IMEXP")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imconjugate[2] =
+{
+ reinterpret_cast<char const *>(u8"IMKONJUGIERTE"),
+ reinterpret_cast<char const *>(u8"IMCONJUGATE")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imln[2] =
+{
+ reinterpret_cast<char const *>(u8"IMLN"),
+ reinterpret_cast<char const *>(u8"IMLN")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imlog10[2] =
+{
+ reinterpret_cast<char const *>(u8"IMLOG10"),
+ reinterpret_cast<char const *>(u8"IMLOG10")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imlog2[2] =
+{
+ reinterpret_cast<char const *>(u8"IMLOG2"),
+ reinterpret_cast<char const *>(u8"IMLOG2")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Improduct[2] =
+{
+ reinterpret_cast<char const *>(u8"IMPRODUKT"),
+ reinterpret_cast<char const *>(u8"IMPRODUCT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imreal[2] =
+{
+ reinterpret_cast<char const *>(u8"IMREALTEIL"),
+ reinterpret_cast<char const *>(u8"IMREAL")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imsin[2] =
+{
+ reinterpret_cast<char const *>(u8"IMSIN"),
+ reinterpret_cast<char const *>(u8"IMSIN")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imsub[2] =
+{
+ reinterpret_cast<char const *>(u8"IMSUB"),
+ reinterpret_cast<char const *>(u8"IMSUB")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imsum[2] =
+{
+ reinterpret_cast<char const *>(u8"IMSUMME"),
+ reinterpret_cast<char const *>(u8"IMSUM")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imsqrt[2] =
+{
+ reinterpret_cast<char const *>(u8"IMWURZEL"),
+ reinterpret_cast<char const *>(u8"IMSQRT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imtan[2] =
+{
+ reinterpret_cast<char const *>(u8"IMTAN"),
+ reinterpret_cast<char const *>(u8"IMTAN")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imsec[2] =
+{
+ reinterpret_cast<char const *>(u8"IMSEC"),
+ reinterpret_cast<char const *>(u8"IMSEC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imcsc[2] =
+{
+ reinterpret_cast<char const *>(u8"IMCSC"),
+ reinterpret_cast<char const *>(u8"IMCSC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imcot[2] =
+{
+ reinterpret_cast<char const *>(u8"IMCOT"),
+ reinterpret_cast<char const *>(u8"IMCOT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imsinh[2] =
+{
+ reinterpret_cast<char const *>(u8"IMSINH"),
+ reinterpret_cast<char const *>(u8"IMSINH")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imcosh[2] =
+{
+ reinterpret_cast<char const *>(u8"IMCOSH"),
+ reinterpret_cast<char const *>(u8"IMCOSH")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imsech[2] =
+{
+ reinterpret_cast<char const *>(u8"IMSECH"),
+ reinterpret_cast<char const *>(u8"IMSECH")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Imcsch[2] =
+{
+ reinterpret_cast<char const *>(u8"IMCSCH"),
+ reinterpret_cast<char const *>(u8"IMCSCH")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Complex[2] =
+{
+ reinterpret_cast<char const *>(u8"KOMPLEXE"),
+ reinterpret_cast<char const *>(u8"COMPLEX")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Oct2Bin[2] =
+{
+ reinterpret_cast<char const *>(u8"OKTINBIN"),
+ reinterpret_cast<char const *>(u8"OCT2BIN")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Oct2Dec[2] =
+{
+ reinterpret_cast<char const *>(u8"OKTINDEZ"),
+ reinterpret_cast<char const *>(u8"OCT2DEC")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Oct2Hex[2] =
+{
+ reinterpret_cast<char const *>(u8"OKTINHEX"),
+ reinterpret_cast<char const *>(u8"OCT2HEX")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Convert[2] =
+{
+ reinterpret_cast<char const *>(u8"UMWANDELN"),
+ reinterpret_cast<char const *>(u8"CONVERT")
+};
+
+static const char* ANALYSIS_DEFFUNCNAME_Factdouble[2] =
+{
+ reinterpret_cast<char const *>(u8"ZWEIFAKULTÄT"),
+ reinterpret_cast<char const *>(u8"FACTDOUBLE")
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/analysis/financial.cxx b/scaddins/source/analysis/financial.cxx
new file mode 100644
index 000000000..5f40e86e3
--- /dev/null
+++ b/scaddins/source/analysis/financial.cxx
@@ -0,0 +1,675 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "analysisdefs.hxx"
+#include "analysis.hxx"
+#include "analysishelper.hxx"
+#include <o3tl/temporary.hxx>
+
+using namespace sca::analysis;
+
+double SAL_CALL AnalysisAddIn::getAmordegrc( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ double fCost, sal_Int32 nDate, sal_Int32 nFirstPer, double fRestVal,
+ double fPer, double fRate, const css::uno::Any& rOB )
+{
+ if( nDate > nFirstPer || fRate <= 0.0 || fRestVal > fCost ||
+ fCost <= 0.0 || fRestVal < 0 || fPer < 0 )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = GetAmordegrc( GetNullDate( xOpt ), fCost, nDate, nFirstPer, fRestVal, fPer, fRate, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getAmorlinc( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ double fCost, sal_Int32 nDate, sal_Int32 nFirstPer, double fRestVal,
+ double fPer, double fRate, const css::uno::Any& rOB )
+{
+ if ( nDate > nFirstPer || fRate <= 0.0 || fRestVal > fCost ||
+ fCost <= 0.0 || fRestVal < 0 || fPer < 0 )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = GetAmorlinc( GetNullDate( xOpt ), fCost, nDate, nFirstPer, fRestVal, fPer, fRate, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getAccrint( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nIssue, sal_Int32 /*nFirstInter*/, sal_Int32 nSettle, double fRate,
+ const css::uno::Any &rVal, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ double fVal = aAnyConv.getDouble( xOpt, rVal, 1000.0 );
+
+ if( fRate <= 0.0 || fVal <= 0.0 || CHK_Freq || nIssue >= nSettle )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = fVal * fRate * GetYearDiff( GetNullDate( xOpt ), nIssue, nSettle, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getAccrintm( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nIssue, sal_Int32 nSettle, double fRate, const css::uno::Any& rVal, const css::uno::Any& rOB )
+{
+ double fVal = aAnyConv.getDouble( xOpt, rVal, 1000.0 );
+
+ if( fRate <= 0.0 || fVal <= 0.0 || nIssue >= nSettle )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = fVal * fRate * GetYearDiff( GetNullDate( xOpt ), nIssue, nSettle, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getReceived( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, double fInvest, double fDisc, const css::uno::Any& rOB )
+{
+ if( fInvest <= 0.0 || fDisc <= 0.0 || nSettle >= nMat )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = fInvest / ( 1.0 - ( fDisc * GetYearDiff( GetNullDate( xOpt ), nSettle, nMat, getDateMode( xOpt, rOB ) ) ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getDisc( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, double fPrice, double fRedemp, const css::uno::Any& rOB )
+{
+ if( fPrice <= 0.0 || fRedemp <= 0.0 || nSettle >= nMat )
+ throw css::lang::IllegalArgumentException();
+ double fRet = ( 1.0 - fPrice / fRedemp ) / GetYearFrac( xOpt, nSettle, nMat, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getDuration( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fYield, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ if( fCoup < 0.0 || fYield < 0.0 || CHK_Freq || nSettle >= nMat )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = GetDuration( GetNullDate( xOpt ), nSettle, nMat, fCoup, fYield, nFreq, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getEffect( double fNominal, sal_Int32 nPeriods )
+{
+ if( nPeriods < 1 || fNominal <= 0.0 )
+ throw css::lang::IllegalArgumentException();
+
+ double fPeriods = nPeriods;
+
+ double fRet = pow( 1.0 + fNominal / fPeriods, fPeriods ) - 1.0;
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getCumprinc( double fRate, sal_Int32 nNumPeriods, double fVal,
+ sal_Int32 nStartPer, sal_Int32 nEndPer, sal_Int32 nPayType )
+{
+ double fPmt, fPpmt;
+
+ if( nStartPer < 1 || nEndPer < nStartPer || fRate <= 0.0 || nEndPer > nNumPeriods ||
+ fVal <= 0.0 || ( nPayType != 0 && nPayType != 1 ) )
+ throw css::lang::IllegalArgumentException();
+
+ fPmt = GetPmt( fRate, nNumPeriods, fVal, 0.0, nPayType );
+
+ fPpmt = 0.0;
+
+ sal_uInt32 nStart = sal_uInt32( nStartPer );
+ sal_uInt32 nEnd = sal_uInt32( nEndPer );
+
+ if( nStart == 1 )
+ {
+ if( nPayType <= 0 )
+ fPpmt = fPmt + fVal * fRate;
+ else
+ fPpmt = fPmt;
+
+ nStart++;
+ }
+
+ for( sal_uInt32 i = nStart ; i <= nEnd ; i++ )
+ {
+ if( nPayType > 0 )
+ fPpmt += fPmt - ( GetFv( fRate, double( i - 2 ), fPmt, fVal, 1 ) - fPmt ) * fRate;
+ else
+ fPpmt += fPmt - GetFv( fRate, double( i - 1 ), fPmt, fVal, 0 ) * fRate;
+ }
+
+ RETURN_FINITE( fPpmt );
+}
+
+
+double SAL_CALL AnalysisAddIn::getCumipmt( double fRate, sal_Int32 nNumPeriods, double fVal,
+ sal_Int32 nStartPer, sal_Int32 nEndPer, sal_Int32 nPayType )
+{
+ double fPmt, fIpmt;
+
+ if( nStartPer < 1 || nEndPer < nStartPer || fRate <= 0.0 || nEndPer > nNumPeriods ||
+ fVal <= 0.0 || ( nPayType != 0 && nPayType != 1 ) )
+ throw css::lang::IllegalArgumentException();
+
+ fPmt = GetPmt( fRate, nNumPeriods, fVal, 0.0, nPayType );
+
+ fIpmt = 0.0;
+
+ sal_uInt32 nStart = sal_uInt32( nStartPer );
+ sal_uInt32 nEnd = sal_uInt32( nEndPer );
+
+ if( nStart == 1 )
+ {
+ if( nPayType <= 0 )
+ fIpmt = -fVal;
+
+ nStart++;
+ }
+
+ for( sal_uInt32 i = nStart ; i <= nEnd ; i++ )
+ {
+ if( nPayType > 0 )
+ fIpmt += GetFv( fRate, double( i - 2 ), fPmt, fVal, 1 ) - fPmt;
+ else
+ fIpmt += GetFv( fRate, double( i - 1 ), fPmt, fVal, 0 );
+ }
+
+ fIpmt *= fRate;
+
+ RETURN_FINITE( fIpmt );
+}
+
+
+double SAL_CALL AnalysisAddIn::getPrice( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield, double fRedemp, sal_Int32 nFreq,
+ const css::uno::Any& rOB )
+{
+ if( fYield < 0.0 || fRate < 0.0 || fRedemp <= 0.0 || CHK_Freq || nSettle >= nMat )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = getPrice_( GetNullDate( xOpt ), nSettle, nMat, fRate, fYield, fRedemp, nFreq, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getPricedisc( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, double fDisc, double fRedemp, const css::uno::Any& rOB )
+{
+ if( fDisc <= 0.0 || fRedemp <= 0.0 || nSettle >= nMat )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = fRedemp * ( 1.0 - fDisc * GetYearDiff( GetNullDate( xOpt ), nSettle, nMat, getDateMode( xOpt, rOB ) ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getPricemat( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, double fRate, double fYield, const css::uno::Any& rOB )
+{
+ if( fRate < 0.0 || fYield < 0.0 || nSettle >= nMat )
+ throw css::lang::IllegalArgumentException();
+
+ sal_Int32 nNullDate = GetNullDate( xOpt );
+ sal_Int32 nBase = getDateMode( xOpt, rOB );
+
+ double fIssMat = GetYearFrac( nNullDate, nIssue, nMat, nBase );
+ double fIssSet = GetYearFrac( nNullDate, nIssue, nSettle, nBase );
+ double fSetMat = GetYearFrac( nNullDate, nSettle, nMat, nBase );
+
+ double fRet = 1.0 + fIssMat * fRate;
+ fRet /= 1.0 + fSetMat * fYield;
+ fRet -= fIssSet * fRate;
+ fRet *= 100.0;
+
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getMduration( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fYield, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ if( fCoup < 0.0 || fYield < 0.0 || CHK_Freq )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = GetDuration( GetNullDate( xOpt ), nSettle, nMat, fCoup, fYield, nFreq, getDateMode( xOpt, rOB ) );
+ fRet /= 1.0 + ( fYield / double( nFreq ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getNominal( double fRate, sal_Int32 nPeriods )
+{
+ if( fRate <= 0.0 || nPeriods < 0 )
+ throw css::lang::IllegalArgumentException();
+
+ double fPeriods = nPeriods;
+ double fRet = ( pow( fRate + 1.0, 1.0 / fPeriods ) - 1.0 ) * fPeriods;
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getDollarfr( double fDollarDec, sal_Int32 nFrac )
+{
+ if( nFrac <= 0 )
+ throw css::lang::IllegalArgumentException();
+
+ double fInt;
+ double fFrac = nFrac;
+
+ double fRet = modf( fDollarDec, &fInt );
+
+ fRet *= fFrac;
+
+ fRet *= pow( 10.0, -ceil( log10( fFrac ) ) );
+
+ fRet += fInt;
+
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getDollarde( double fDollarFrac, sal_Int32 nFrac )
+{
+ if( nFrac <= 0 )
+ throw css::lang::IllegalArgumentException();
+
+ double fInt;
+ double fFrac = nFrac;
+
+ double fRet = modf( fDollarFrac, &fInt );
+
+ fRet /= fFrac;
+
+ fRet *= pow( 10.0, ceil( log10( fFrac ) ) );
+
+ fRet += fInt;
+
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getYield( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice, double fRedemp, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ if( fCoup < 0.0 || fPrice <= 0.0 || fRedemp <= 0.0 || CHK_Freq || nSettle >= nMat )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = getYield_( GetNullDate( xOpt ), nSettle, nMat, fCoup, fPrice, fRedemp, nFreq, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getYielddisc( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, double fPrice, double fRedemp, const css::uno::Any& rOB )
+{
+ if( fPrice <= 0.0 || fRedemp <= 0.0 || nSettle >= nMat )
+ throw css::lang::IllegalArgumentException();
+
+ sal_Int32 nNullDate = GetNullDate( xOpt );
+
+ double fRet = ( fRedemp / fPrice ) - 1.0;
+ fRet /= GetYearFrac( nNullDate, nSettle, nMat, getDateMode( xOpt, rOB ) );
+
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getYieldmat( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, double fRate, double fPrice, const css::uno::Any& rOB )
+{
+ if( fPrice <= 0.0 || fRate < 0.0 || nSettle >= nMat || nSettle < nIssue)
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = GetYieldmat( GetNullDate( xOpt ), nSettle, nMat, nIssue, fRate, fPrice, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getTbilleq( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, double fDisc )
+{
+ nMat++;
+
+ sal_Int32 nDiff = GetDiffDate360( xOpt, nSettle, nMat, true );
+
+ if( fDisc <= 0.0 || nSettle >= nMat || nDiff > 360 )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = ( 365 * fDisc ) / ( 360 - ( fDisc * double( nDiff ) ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getTbillprice( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, double fDisc )
+{
+ if( fDisc <= 0.0 || nSettle > nMat )
+ throw css::lang::IllegalArgumentException();
+
+ nMat++;
+
+ double fFraction = GetYearFrac( xOpt, nSettle, nMat, 0 ); // method: USA 30/360
+
+ if( modf( fFraction, &o3tl::temporary(double()) ) == 0.0 )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = 100.0 * ( 1.0 - fDisc * fFraction );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getTbillyield( const css::uno::Reference< css::beans::XPropertySet >& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fPrice )
+{
+ sal_Int32 nDiff = GetDiffDate360( xOpt, nSettle, nMat, true );
+ nDiff++;
+
+ if( fPrice <= 0.0 || nSettle >= nMat || nDiff > 360 )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = 100.0;
+ fRet /= fPrice;
+ fRet--;
+ fRet /= double( nDiff );
+ fRet *= 360.0;
+
+ RETURN_FINITE( fRet );
+}
+
+// Encapsulation violation: We *know* that GetOddfprice() always
+// throws.
+
+SAL_WNOUNREACHABLE_CODE_PUSH
+
+double SAL_CALL AnalysisAddIn::getOddfprice( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, sal_Int32 nFirstCoup,
+ double fRate, double fYield, double fRedemp, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ if( fRate < 0.0 || fYield < 0.0 || CHK_Freq || nMat <= nFirstCoup || nFirstCoup <= nSettle || nSettle <= nIssue )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = GetOddfprice( GetNullDate( xOpt ), nSettle, nMat, nIssue, nFirstCoup, fRate, fYield, fRedemp, nFreq, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+SAL_WNOUNREACHABLE_CODE_POP
+
+// Encapsulation violation: We *know* that Getoddfyield() always
+// throws.
+
+SAL_WNOUNREACHABLE_CODE_PUSH
+
+double SAL_CALL AnalysisAddIn::getOddfyield( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, sal_Int32 nFirstCoup,
+ double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ if( fRate < 0.0 || fPrice <= 0.0 || CHK_Freq || nMat <= nFirstCoup || nFirstCoup <= nSettle || nSettle <= nIssue )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = GetOddfyield( GetNullDate( xOpt ), nSettle, nMat, nIssue, nFirstCoup, fRate, fPrice, fRedemp, nFreq,
+ getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+SAL_WNOUNREACHABLE_CODE_POP
+
+double SAL_CALL AnalysisAddIn::getOddlprice( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastInterest,
+ double fRate, double fYield, double fRedemp, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ if( fRate <= 0.0 || fYield < 0.0 || fRedemp <= 0.0 || CHK_Freq || nMat <= nSettle || nSettle <= nLastInterest )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = GetOddlprice( GetNullDate( xOpt ), nSettle, nMat, nLastInterest, fRate, fYield, fRedemp, nFreq,
+ getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getOddlyield( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastInterest,
+ double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ if( fRate <= 0.0 || fPrice <= 0.0 || fRedemp <= 0.0 || CHK_Freq || nMat <= nSettle || nSettle <= nLastInterest )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = GetOddlyield( GetNullDate( xOpt ), nSettle, nMat, nLastInterest, fRate, fPrice, fRedemp, nFreq,
+ getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+// XIRR helper functions
+
+#define V_(i) (rValues.Get(i))
+#define D_(i) (rDates.Get(i))
+
+/** Calculates the resulting amount for the passed interest rate and the given XIRR parameters. */
+static double lcl_sca_XirrResult( const ScaDoubleList& rValues, const ScaDoubleList& rDates, double fRate )
+{
+ /* V_0 ... V_n = input values.
+ D_0 ... D_n = input dates.
+ R = input interest rate.
+
+ r := R+1
+ E_i := (D_i-D_0) / 365
+
+ n V_i n V_i
+ f(R) = SUM ------- = V_0 + SUM ------- .
+ i=0 r^E_i i=1 r^E_i
+ */
+ double D_0 = D_(0);
+ double r = fRate + 1.0;
+ double fResult = V_(0);
+ for( sal_uInt32 i = 1, nCount = rValues.Count(); i < nCount; ++i )
+ fResult += V_(i) / pow( r, (D_(i) - D_0) / 365.0 );
+ return fResult;
+}
+
+/** Calculates the first derivation of lcl_sca_XirrResult(). */
+static double lcl_sca_XirrResult_Deriv1( const ScaDoubleList& rValues, const ScaDoubleList& rDates, double fRate )
+{
+ /* V_0 ... V_n = input values.
+ D_0 ... D_n = input dates.
+ R = input interest rate.
+
+ r := R+1
+ E_i := (D_i-D_0) / 365
+
+ n V_i
+ f'(R) = [ V_0 + SUM ------- ]'
+ i=1 r^E_i
+
+ n V_i n E_i V_i
+ = 0 + SUM -E_i ----------- r' = - SUM ----------- .
+ i=1 r^(E_i+1) i=1 r^(E_i+1)
+ */
+ double D_0 = D_(0);
+ double r = fRate + 1.0;
+ double fResult = 0.0;
+ for( sal_uInt32 i = 1, nCount = rValues.Count(); i < nCount; ++i )
+ {
+ double E_i = (D_(i) - D_0) / 365.0;
+ fResult -= E_i * V_(i) / pow( r, E_i + 1.0 );
+ }
+ return fResult;
+}
+
+#undef V_
+#undef D_
+
+// XIRR calculation
+
+double SAL_CALL AnalysisAddIn::getXirr(
+ const css::uno::Reference< css::beans::XPropertySet >& xOpt, const css::uno::Sequence< css::uno::Sequence< double > >& rValues, const css::uno::Sequence< css::uno::Sequence< sal_Int32 > >& rDates, const css::uno::Any& rGuessRate )
+{
+ ScaDoubleList aValues, aDates;
+ aValues.Append( rValues );
+ aDates.Append( rDates );
+
+ if( (aValues.Count() < 2) || (aValues.Count() != aDates.Count()) )
+ throw css::lang::IllegalArgumentException();
+
+ // result interest rate, initialized with passed guessed rate, or 10%
+ double fResultRate = aAnyConv.getDouble( xOpt, rGuessRate, 0.1 );
+ if( fResultRate <= -1 )
+ throw css::lang::IllegalArgumentException();
+
+ // maximum epsilon for end of iteration
+ static const double fMaxEps = 1e-10;
+ // maximum number of iterations
+ static const sal_Int32 nMaxIter = 50;
+
+ // Newton's method - try to find a fResultRate, so that lcl_sca_XirrResult() returns 0.
+ sal_Int32 nIter = 0;
+ double fResultValue;
+ sal_Int32 nIterScan = 0;
+ bool bContLoop = false;
+ bool bResultRateScanEnd = false;
+
+ // First the inner while-loop will be executed using the default Value fResultRate
+ // or the user guessed fResultRate if those do not deliver a solution for the
+ // Newton's method then the range from -0.99 to +0.99 will be scanned with a
+ // step size of 0.01 to find fResultRate's value which can deliver a solution
+ do
+ {
+ if (nIterScan >=1)
+ fResultRate = -0.99 + (nIterScan -1)* 0.01;
+ do
+ {
+ fResultValue = lcl_sca_XirrResult( aValues, aDates, fResultRate );
+ double fNewRate = fResultRate - fResultValue / lcl_sca_XirrResult_Deriv1( aValues, aDates, fResultRate );
+ double fRateEps = fabs( fNewRate - fResultRate );
+ fResultRate = fNewRate;
+ bContLoop = (fRateEps > fMaxEps) && (fabs( fResultValue ) > fMaxEps);
+ }
+ while( bContLoop && (++nIter < nMaxIter) );
+ nIter = 0;
+ if ( std::isnan(fResultRate) || std::isinf(fResultRate)
+ ||std::isnan(fResultValue) || std::isinf(fResultValue))
+ bContLoop = true;
+
+ ++nIterScan;
+ bResultRateScanEnd = (nIterScan >= 200);
+ }
+ while(bContLoop && !bResultRateScanEnd);
+
+ if( bContLoop )
+ throw css::lang::IllegalArgumentException();
+ RETURN_FINITE( fResultRate );
+}
+
+
+double SAL_CALL AnalysisAddIn::getXnpv(
+ double fRate, const css::uno::Sequence< css::uno::Sequence< double > >& rValues, const css::uno::Sequence< css::uno::Sequence< sal_Int32 > >& rDates )
+{
+ ScaDoubleList aValList;
+ ScaDoubleList aDateList;
+
+ aValList.Append( rValues );
+ aDateList.Append( rDates );
+
+ sal_uInt32 nNum = aValList.Count();
+
+ if( nNum != aDateList.Count() || nNum < 2 )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = 0.0;
+ double fNull = aDateList.Get( 0 );
+ fRate++;
+
+ for( sal_uInt32 i = 0 ; i < nNum ; i++ )
+ fRet += aValList.Get( i ) / ( pow( fRate, ( aDateList.Get( i ) - fNull ) / 365.0 ) );
+
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getIntrate( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, double fInvest, double fRedemp, const css::uno::Any& rOB )
+{
+ if( fInvest <= 0.0 || fRedemp <= 0.0 || nSettle >= nMat )
+ throw css::lang::IllegalArgumentException();
+
+ double fRet = ( ( fRedemp / fInvest ) - 1.0 ) / GetYearDiff( GetNullDate( xOpt ), nSettle, nMat, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getCoupncd( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ double fRet = GetCoupncd( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getCoupdays( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ double fRet = GetCoupdays( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getCoupdaysnc( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ double fRet = GetCoupdaysnc( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getCoupdaybs( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ double fRet = GetCoupdaybs( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getCouppcd( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ double fRet = GetCouppcd( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getCoupnum( const css::uno::Reference< css::beans::XPropertySet >& xOpt,
+ sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const css::uno::Any& rOB )
+{
+ double fRet = GetCoupnum( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
+ RETURN_FINITE( fRet );
+}
+
+
+double SAL_CALL AnalysisAddIn::getFvschedule( double fPrinc, const css::uno::Sequence< css::uno::Sequence< double > >& rSchedule )
+{
+ ScaDoubleList aSchedList;
+
+ aSchedList.Append( rSchedule );
+
+ for( sal_uInt32 i = 0; i < aSchedList.Count(); ++i )
+ fPrinc *= 1.0 + aSchedList.Get(i);
+
+ RETURN_FINITE( fPrinc );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/datefunc/date.component b/scaddins/source/datefunc/date.component
new file mode 100644
index 000000000..7337d98c9
--- /dev/null
+++ b/scaddins/source/datefunc/date.component
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.sheet.addin.DateFunctionsImpl"
+ constructor="scaddins_ScaDateAddIn_get_implementation" single-instance="true">
+ <service name="com.sun.star.sheet.AddIn"/>
+ <service name="com.sun.star.sheet.addin.DateFunctions"/>
+ </implementation>
+</component>
diff --git a/scaddins/source/datefunc/datefunc.cxx b/scaddins/source/datefunc/datefunc.cxx
new file mode 100644
index 000000000..92492b29d
--- /dev/null
+++ b/scaddins/source/datefunc/datefunc.cxx
@@ -0,0 +1,688 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "datefunc.hxx"
+#include <datefunc.hrc>
+#include <strings.hrc>
+#include <com/sun/star/util/Date.hpp>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <unotools/resmgr.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <algorithm>
+#include <cmath>
+#include "deffuncname.hxx"
+
+using namespace ::com::sun::star;
+
+constexpr OUStringLiteral ADDIN_SERVICE = u"com.sun.star.sheet.AddIn";
+constexpr OUStringLiteral MY_SERVICE = u"com.sun.star.sheet.addin.DateFunctions";
+constexpr OUStringLiteral MY_IMPLNAME = u"com.sun.star.sheet.addin.DateFunctionsImpl";
+
+#define UNIQUE false // function name does not exist in Calc
+
+#define STDPAR false // all parameters are described
+#define INTPAR true // first parameter is internal
+
+#define FUNCDATA( FuncName, ParamCount, Category, Double, IntPar ) \
+ { "get" #FuncName, DATE_FUNCNAME_##FuncName, DATE_FUNCDESC_##FuncName, DATE_DEFFUNCNAME_##FuncName, ParamCount, Category, Double, IntPar }
+
+const ScaFuncDataBase pFuncDataArr[] =
+{
+ FUNCDATA( DiffWeeks, 3, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( DiffMonths, 3, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( DiffYears, 3, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( IsLeapYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( DaysInMonth, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( DaysInYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( WeeksInYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( Rot13, 1, ScaCategory::Text, UNIQUE, STDPAR )
+};
+
+#undef FUNCDATA
+
+ScaFuncData::ScaFuncData(const ScaFuncDataBase& rBaseData) :
+ aIntName( OUString::createFromAscii( rBaseData.pIntName ) ),
+ pUINameID( rBaseData.pUINameID ),
+ pDescrID( rBaseData.pDescrID ),
+ nParamCount( rBaseData.nParamCount ),
+ eCat( rBaseData.eCat ),
+ bDouble( rBaseData.bDouble ),
+ bWithOpt( rBaseData.bWithOpt )
+{
+ aCompList.push_back(OUString::createFromAscii(rBaseData.pCompListID[0]));
+ aCompList.push_back(OUString::createFromAscii(rBaseData.pCompListID[1]));
+}
+
+sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const
+{
+ if( !bWithOpt )
+ nParam++;
+ return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2);
+}
+
+static void InitScaFuncDataList(ScaFuncDataList& rList)
+{
+ for (const auto & nIndex : pFuncDataArr)
+ rList.push_back(ScaFuncData(nIndex));
+}
+
+// entry points for service registration / instantiation
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scaddins_ScaDateAddIn_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ScaDateAddIn());
+}
+
+
+// "normal" service implementation
+ScaDateAddIn::ScaDateAddIn()
+{
+}
+
+static const char* pLang[] = { "de", "en" };
+static const char* pCoun[] = { "DE", "US" };
+const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang );
+
+void ScaDateAddIn::InitDefLocales()
+{
+ pDefLocales.reset(new lang::Locale[ nNumOfLoc ]);
+
+ for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ )
+ {
+ pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] );
+ pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] );
+ }
+}
+
+const lang::Locale& ScaDateAddIn::GetLocale( sal_uInt32 nIndex )
+{
+ if( !pDefLocales )
+ InitDefLocales();
+
+ return (nIndex < nNumOfLoc) ? pDefLocales[ nIndex ] : aFuncLoc;
+}
+
+void ScaDateAddIn::InitData()
+{
+ aResLocale = Translate::Create("sca", LanguageTag(aFuncLoc));
+ pFuncDataList.reset();
+
+ pFuncDataList.reset(new ScaFuncDataList);
+ InitScaFuncDataList(*pFuncDataList);
+
+ if( pDefLocales )
+ {
+ pDefLocales.reset();
+ }
+}
+
+OUString ScaDateAddIn::GetFuncDescrStr(const TranslateId* pResId, sal_uInt16 nStrIndex)
+{
+ return ScaResId(pResId[nStrIndex - 1]);
+}
+
+// XServiceName
+OUString SAL_CALL ScaDateAddIn::getServiceName()
+{
+ // name of specific AddIn service
+ return MY_SERVICE;
+}
+
+// XServiceInfo
+OUString SAL_CALL ScaDateAddIn::getImplementationName()
+{
+ return MY_IMPLNAME;
+}
+
+sal_Bool SAL_CALL ScaDateAddIn::supportsService( const OUString& aServiceName )
+{
+ return cppu::supportsService(this, aServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL ScaDateAddIn::getSupportedServiceNames()
+{
+ return { ADDIN_SERVICE, MY_SERVICE };
+}
+
+// XLocalizable
+void SAL_CALL ScaDateAddIn::setLocale( const lang::Locale& eLocale )
+{
+ aFuncLoc = eLocale;
+ InitData(); // change of locale invalidates resources!
+}
+
+lang::Locale SAL_CALL ScaDateAddIn::getLocale()
+{
+ return aFuncLoc;
+}
+
+OUString SAL_CALL ScaDateAddIn::getProgrammaticFuntionName( const OUString& )
+{
+ // not used by calc
+ // (but should be implemented for other uses of the AddIn service)
+ return OUString();
+}
+
+OUString SAL_CALL ScaDateAddIn::getDisplayFunctionName( const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() )
+ {
+ aRet = ScaResId(fDataIt->GetUINameID());
+ if( fDataIt->IsDouble() )
+ aRet += "_ADD";
+ }
+ else
+ {
+ aRet = "UNKNOWNFUNC_" + aProgrammaticName;
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaDateAddIn::getFunctionDescription( const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), 1 );
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaDateAddIn::getDisplayArgumentName(
+ const OUString& aProgrammaticName, sal_Int32 nArgument )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) )
+ {
+ sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
+ if( nStr )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr );
+ else
+ aRet = "internal";
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaDateAddIn::getArgumentDescription(
+ const OUString& aProgrammaticName, sal_Int32 nArgument )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) )
+ {
+ sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
+ if( nStr )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr + 1 );
+ else
+ aRet = "for internal use only";
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaDateAddIn::getProgrammaticCategoryName(
+ const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() )
+ {
+ switch( fDataIt->GetCategory() )
+ {
+ case ScaCategory::DateTime: aRet = "Date&Time"; break;
+ case ScaCategory::Text: aRet = "Text"; break;
+ case ScaCategory::Finance: aRet = "Financial"; break;
+ case ScaCategory::Inf: aRet = "Information"; break;
+ case ScaCategory::Math: aRet = "Mathematical"; break;
+ case ScaCategory::Tech: aRet = "Technical"; break;
+ }
+ }
+
+ if( aRet.isEmpty() )
+ aRet = "Add-In";
+ return aRet;
+}
+
+OUString SAL_CALL ScaDateAddIn::getDisplayCategoryName(
+ const OUString& aProgrammaticName )
+{
+ return getProgrammaticCategoryName( aProgrammaticName );
+}
+
+// XCompatibilityNames
+uno::Sequence< sheet::LocalizedName > SAL_CALL ScaDateAddIn::getCompatibilityNames(
+ const OUString& aProgrammaticName )
+{
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt == pFuncDataList->end() )
+ return uno::Sequence< sheet::LocalizedName >( 0 );
+
+ const std::vector<OUString>& rStrList = fDataIt->GetCompNameList();
+ sal_uInt32 nCount = rStrList.size();
+
+ uno::Sequence< sheet::LocalizedName > aRet( nCount );
+ sheet::LocalizedName* pArray = aRet.getArray();
+
+ for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
+ pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), rStrList.at( nIndex ) );
+
+ return aRet;
+}
+
+namespace {
+
+// auxiliary functions
+bool IsLeapYear( sal_uInt16 nYear )
+{
+ return ((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0));
+}
+
+sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
+{
+ static const sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31 };
+
+ if ( nMonth != 2 )
+ return aDaysInMonth[nMonth-1];
+ else
+ {
+ if ( IsLeapYear(nYear) )
+ return aDaysInMonth[nMonth-1] + 1;
+ else
+ return aDaysInMonth[nMonth-1];
+ }
+}
+
+/**
+ * Convert a date to a count of days starting from 01/01/0001
+ *
+ * The internal representation of a Date used in this Addin
+ * is the number of days between 01/01/0001 and the date
+ * this function converts a Day , Month, Year representation
+ * to this internal Date value.
+ */
+
+sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
+{
+ sal_Int32 nDays = (static_cast<sal_Int32>(nYear)-1) * 365;
+ nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
+
+ for( sal_uInt16 i = 1; i < nMonth; i++ )
+ nDays += DaysInMonth(i,nYear);
+ nDays += nDay;
+
+ return nDays;
+}
+
+/**
+ * Convert a count of days starting from 01/01/0001 to a date
+ *
+ * The internal representation of a Date used in this Addin
+ * is the number of days between 01/01/0001 and the date
+ * this function converts this internal Date value
+ * to a Day , Month, Year representation of a Date.
+ *
+ * @throws lang::IllegalArgumentException
+ */
+
+void DaysToDate( sal_Int32 nDays,
+ sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
+{
+ if( nDays < 0 )
+ throw lang::IllegalArgumentException();
+
+ sal_Int32 nTempDays;
+ sal_Int32 i = 0;
+ bool bCalc;
+
+ do
+ {
+ nTempDays = nDays;
+ rYear = static_cast<sal_uInt16>((nTempDays / 365) - i);
+ nTempDays -= (static_cast<sal_Int32>(rYear) -1) * 365;
+ nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
+ bCalc = false;
+ if ( nTempDays < 1 )
+ {
+ i++;
+ bCalc = true;
+ }
+ else
+ {
+ if ( nTempDays > 365 )
+ {
+ if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
+ {
+ i--;
+ bCalc = true;
+ }
+ }
+ }
+ }
+ while ( bCalc );
+
+ rMonth = 1;
+ while ( nTempDays > DaysInMonth( rMonth, rYear ) )
+ {
+ nTempDays -= DaysInMonth( rMonth, rYear );
+ rMonth++;
+ }
+ rDay = static_cast<sal_uInt16>(nTempDays);
+}
+
+/**
+ * Get the null date used by the spreadsheet document
+ *
+ * The internal representation of a Date used in this Addin
+ * is the number of days between 01/01/0001 and the date
+ * this function returns this internal Date value for the document null date
+ *
+ * @throws uno::RuntimeException
+ */
+sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOptions )
+{
+ if (xOptions.is())
+ {
+ try
+ {
+ uno::Any aAny = xOptions->getPropertyValue( "NullDate" );
+ util::Date aDate;
+ if ( aAny >>= aDate )
+ return DateToDays( aDate.Day, aDate.Month, aDate.Year );
+ }
+ catch (uno::Exception&)
+ {
+ }
+ }
+
+ // no null date available -> no calculations possible
+ throw uno::RuntimeException();
+}
+
+}
+// XDateFunctions
+
+/**
+ * Get week difference between 2 dates
+ *
+ * new Weeks(date1,date2,mode) function for StarCalc
+ *
+ * Two modes of operation are provided.
+ * mode 0 is just a simple division by 7 calculation.
+ *
+ * mode 1 calculates the difference by week adhering to ISO8601.
+ *
+ * The International Standard IS-8601 states that Monday is the first
+ * day of the week. The Gregorian Calendar is used for all dates,
+ * proleptic in case of dates before 1582-10-15.
+ *
+ * The (consecutive) week number of a date is
+ * std::floor( (date + NullDate - 1), 7.0 ),
+ * with weeks starting on Monday, and week 0
+ * starting on Monday, 0001-01-01 Gregorian.
+ *
+ * Weeks(d2,d1,m) is defined as -Weeks(d1,d2,m).
+ *
+ */
+
+sal_Int32 SAL_CALL ScaDateAddIn::getDiffWeeks(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nStartDate, sal_Int32 nEndDate,
+ sal_Int32 nMode )
+{
+ if ( nMode == 0 )
+ {
+ return ( nEndDate - nStartDate ) / 7;
+ }
+ else if ( nMode == 1 )
+ {
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+ sal_Int32 nDays1 = nStartDate + nNullDate - 1;
+ sal_Int32 nDays2 = nEndDate + nNullDate - 1;
+
+ return ( std::floor( nDays2 / 7.0 ) - std::floor( nDays1 / 7.0 ) );
+ }
+ else
+ throw lang::IllegalArgumentException();
+}
+
+/**
+ * Get month difference between 2 dates
+ * =Month(start, end, mode) Function for StarCalc
+ *
+ * two modes are provided
+ *
+ * mode 0 is the interval between the dates in month
+ *
+ * mode 1 is the difference in calendar month
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getDiffMonths(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nStartDate, sal_Int32 nEndDate,
+ sal_Int32 nMode )
+{
+ if (nMode != 0 && nMode != 1)
+ throw lang::IllegalArgumentException();
+
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+
+ sal_Int32 nDays1 = nStartDate + nNullDate;
+ sal_Int32 nDays2 = nEndDate + nNullDate;
+
+ sal_uInt16 nDay1,nMonth1,nYear1;
+ sal_uInt16 nDay2,nMonth2,nYear2;
+ DaysToDate(nDays1,nDay1,nMonth1,nYear1);
+ DaysToDate(nDays2,nDay2,nMonth2,nYear2);
+
+ sal_Int32 nRet = nMonth2 - nMonth1 + (nYear2 - nYear1) * 12;
+ if ( nMode == 1 || nDays1 == nDays2 ) return nRet;
+
+ if ( nDays1 < nDays2 )
+ {
+ if ( nDay1 > nDay2 )
+ {
+ nRet -= 1;
+ }
+ }
+ else
+ {
+ if ( nDay1 < nDay2 )
+ {
+ nRet += 1;
+ }
+ }
+
+ return nRet;
+}
+
+/**
+ * Get Year difference between 2 dates
+ *
+ * two modes are provided
+ *
+ * mode 0 is the interval between the dates in years
+ *
+ * mode 1 is the difference in calendar years
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getDiffYears(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nStartDate, sal_Int32 nEndDate,
+ sal_Int32 nMode )
+{
+ if (nMode != 0 && nMode != 1)
+ throw lang::IllegalArgumentException();
+
+ if ( nMode != 1 )
+ return getDiffMonths( xOptions, nStartDate, nEndDate, nMode ) / 12;
+
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+
+ sal_Int32 nDays1 = nStartDate + nNullDate;
+ sal_Int32 nDays2 = nEndDate + nNullDate;
+
+ sal_uInt16 nDay1,nMonth1,nYear1;
+ sal_uInt16 nDay2,nMonth2,nYear2;
+ DaysToDate(nDays1,nDay1,nMonth1,nYear1);
+ DaysToDate(nDays2,nDay2,nMonth2,nYear2);
+
+ return nYear2 - nYear1;
+}
+
+/**
+ * Check if a Date is in a leap year in the Gregorian calendar
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getIsLeapYear(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nDate )
+{
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+ sal_Int32 nDays = nDate + nNullDate;
+
+ sal_uInt16 nDay, nMonth, nYear;
+ DaysToDate(nDays,nDay,nMonth,nYear);
+
+ return static_cast<sal_Int32>(IsLeapYear(nYear));
+}
+
+/**
+ * Get the Number of Days in the month for a date
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getDaysInMonth(
+ const uno::Reference<beans::XPropertySet>& xOptions,
+ sal_Int32 nDate )
+{
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+ sal_Int32 nDays = nDate + nNullDate;
+
+ sal_uInt16 nDay, nMonth, nYear;
+ DaysToDate(nDays,nDay,nMonth,nYear);
+
+ return DaysInMonth( nMonth, nYear );
+}
+
+/**
+ * Get number of days in the year of a date specified
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getDaysInYear(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nDate )
+{
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+ sal_Int32 nDays = nDate + nNullDate;
+
+ sal_uInt16 nDay, nMonth, nYear;
+ DaysToDate(nDays,nDay,nMonth,nYear);
+
+ return ( IsLeapYear(nYear) ? 366 : 365 );
+}
+
+/**
+ * Get number of weeks in the year for a date
+ *
+ * Most years have 52 weeks, but years that start on a Thursday
+ * and leap years that start on a Wednesday have 53 weeks
+ *
+ * The International Standard IS-8601 has decreed that Monday
+ * shall be the first day of the week.
+ *
+ * A WeekDay can be calculated by subtracting 1 and calculating the rest of
+ * a division by 7 from the internal date representation
+ * which gives a 0 - 6 value for Monday - Sunday
+ *
+ * @see #IsLeapYear #WeekNumber
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getWeeksInYear(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nDate )
+{
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+ sal_Int32 nDays = nDate + nNullDate;
+
+ sal_uInt16 nDay, nMonth, nYear;
+ DaysToDate(nDays,nDay,nMonth,nYear);
+
+ sal_Int32 nJan1WeekDay = ( DateToDays(1,1,nYear) - 1) % 7;
+
+ sal_Int32 nRet;
+ if ( nJan1WeekDay == 3 ) /* Thursday */
+ nRet = 53;
+ else if ( nJan1WeekDay == 2 ) /* Wednesday */
+ nRet = ( IsLeapYear(nYear) ? 53 : 52 );
+ else
+ nRet = 52;
+
+ return nRet;
+}
+
+/**
+ * Encrypt or decrypt a string using ROT13 algorithm
+ *
+ * This function rotates each character by 13 in the alphabet.
+ * Only the characters 'a' ... 'z' and 'A' ... 'Z' are modified.
+ */
+OUString SAL_CALL ScaDateAddIn::getRot13( const OUString& aSrcString )
+{
+ OUStringBuffer aBuffer( aSrcString );
+ for( sal_Int32 nIndex = 0; nIndex < aBuffer.getLength(); nIndex++ )
+ {
+ sal_Unicode cChar = aBuffer[nIndex];
+ if( (cChar >= 'a') && (cChar <= 'z'))
+ {
+ cChar += 13;
+ if (cChar > 'z')
+ cChar -= 26;
+ }
+ else if( (cChar >= 'A') && (cChar <= 'Z') )
+ {
+ cChar += 13;
+ if (cChar > 'Z')
+ cChar -= 26;
+ }
+ aBuffer[nIndex] = cChar;
+ }
+ return aBuffer.makeStringAndClear();
+}
+
+OUString ScaDateAddIn::ScaResId(TranslateId aId)
+{
+ return Translate::get(aId, aResLocale);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/datefunc/datefunc.hxx b/scaddins/source/datefunc/datefunc.hxx
new file mode 100644
index 000000000..0dd6b5fa2
--- /dev/null
+++ b/scaddins/source/datefunc/datefunc.hxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// date functions add in
+
+#pragma once
+
+#include <vector>
+#include <memory>
+#include <com/sun/star/lang/XServiceName.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sheet/XAddIn.hpp>
+#include <com/sun/star/sheet/XCompatibilityNames.hpp>
+#include <com/sun/star/sheet/addin/XDateFunctions.hpp>
+#include <com/sun/star/sheet/addin/XMiscFunctions.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <unotools/resmgr.hxx>
+
+namespace com::sun::star::lang { class XMultiServiceFactory; }
+
+enum class ScaCategory
+{
+ DateTime,
+ Text,
+ Finance,
+ Inf,
+ Math,
+ Tech
+};
+
+struct ScaFuncDataBase
+{
+ const char* pIntName; // internal name (get***)
+ TranslateId pUINameID; // resource ID to UI name
+ const TranslateId* pDescrID; // resource ID to description, parameter names and ~ description
+ const char** pCompListID; // list of valid names
+ sal_uInt16 nParamCount; // number of named / described parameters
+ ScaCategory eCat; // function category
+ bool bDouble; // name already exist in Calc
+ bool bWithOpt; // first parameter is internal
+};
+
+class ScaFuncData final
+{
+private:
+ OUString aIntName; // internal name (get***)
+ TranslateId pUINameID; // resource ID to UI name
+ const TranslateId* pDescrID; // leads also to parameter descriptions!
+ sal_uInt16 nParamCount; // num of parameters
+ std::vector<OUString> aCompList; // list of all valid names
+ ScaCategory eCat; // function category
+ bool bDouble; // name already exist in Calc
+ bool bWithOpt; // first parameter is internal
+
+public:
+ ScaFuncData(const ScaFuncDataBase& rBaseData);
+
+ const TranslateId & GetUINameID() const { return pUINameID; }
+ const TranslateId* GetDescrID() const { return pDescrID; }
+ ScaCategory GetCategory() const { return eCat; }
+ bool IsDouble() const { return bDouble; }
+
+ sal_uInt16 GetStrIndex( sal_uInt16 nParam ) const;
+ bool Is( std::u16string_view rCompare ) const
+ { return aIntName == rCompare; }
+
+ const std::vector<OUString>& GetCompNameList() const { return aCompList; }
+};
+
+typedef std::vector<ScaFuncData> ScaFuncDataList;
+
+// Predicate for use with std::find_if
+struct FindScaFuncData
+{
+ const OUString& m_rId;
+ explicit FindScaFuncData( const OUString& rId ) : m_rId(rId) {}
+ bool operator() ( ScaFuncData const & rCandidate ) const { return rCandidate.Is(m_rId); }
+};
+
+
+// THE AddIn class for date functions
+
+class ScaDateAddIn : public ::cppu::WeakImplHelper<
+ css::sheet::XAddIn,
+ css::sheet::XCompatibilityNames,
+ css::sheet::addin::XDateFunctions,
+ css::sheet::addin::XMiscFunctions,
+ css::lang::XServiceName,
+ css::lang::XServiceInfo >
+{
+private:
+ css::lang::Locale aFuncLoc;
+ std::unique_ptr< css::lang::Locale[] > pDefLocales;
+ std::locale aResLocale;
+ std::unique_ptr< ScaFuncDataList > pFuncDataList;
+
+
+ void InitDefLocales();
+ const css::lang::Locale& GetLocale( sal_uInt32 nIndex );
+ void InitData();
+
+ /// @throws css::uno::RuntimeException
+ OUString GetFuncDescrStr(const TranslateId* pResId, sal_uInt16 nStrIndex);
+
+public:
+ ScaDateAddIn();
+
+ OUString ScaResId(TranslateId aId);
+
+ // XAddIn
+ virtual OUString SAL_CALL getProgrammaticFuntionName( const OUString& aDisplayName ) override;
+ virtual OUString SAL_CALL getDisplayFunctionName( const OUString& aProgrammaticName ) override;
+ virtual OUString SAL_CALL getFunctionDescription( const OUString& aProgrammaticName ) override;
+ virtual OUString SAL_CALL getDisplayArgumentName( const OUString& aProgrammaticName, sal_Int32 nArgument ) override;
+ virtual OUString SAL_CALL getArgumentDescription( const OUString& aProgrammaticName, sal_Int32 nArgument ) override;
+ virtual OUString SAL_CALL getProgrammaticCategoryName( const OUString& aProgrammaticName ) override;
+ virtual OUString SAL_CALL getDisplayCategoryName( const OUString& aProgrammaticName ) override;
+
+ // XCompatibilityNames
+ virtual css::uno::Sequence< css::sheet::LocalizedName > SAL_CALL getCompatibilityNames( const OUString& aProgrammaticName ) override;
+
+ // XLocalizable
+ virtual void SAL_CALL setLocale( const css::lang::Locale& eLocale ) override;
+ virtual css::lang::Locale SAL_CALL getLocale() override;
+
+ // XServiceName
+ virtual OUString SAL_CALL getServiceName() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // methods from own interfaces start here
+
+ // XDateFunctions
+ virtual sal_Int32 SAL_CALL getDiffWeeks(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nEndDate, sal_Int32 nStartDate,
+ sal_Int32 nMode ) override;
+
+ virtual sal_Int32 SAL_CALL getDiffMonths(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nEndDate, sal_Int32 nStartDate,
+ sal_Int32 nMode ) override;
+
+ virtual sal_Int32 SAL_CALL getDiffYears(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nEndDate, sal_Int32 nStartDate,
+ sal_Int32 nMode ) override;
+
+ virtual sal_Int32 SAL_CALL getIsLeapYear(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nDate ) override;
+
+ virtual sal_Int32 SAL_CALL getDaysInMonth(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nDate ) override;
+
+ virtual sal_Int32 SAL_CALL getDaysInYear(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nDate ) override;
+
+ virtual sal_Int32 SAL_CALL getWeeksInYear(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nDate ) override;
+
+ // XMiscFunctions
+ virtual OUString SAL_CALL getRot13(
+ const OUString& aSrcText ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/datefunc/deffuncname.hxx b/scaddins/source/datefunc/deffuncname.hxx
new file mode 100644
index 000000000..493ef9393
--- /dev/null
+++ b/scaddins/source/datefunc/deffuncname.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+static const char* DATE_DEFFUNCNAME_DiffWeeks[2] =
+{
+ "WOCHEN",
+ "WEEKS"
+};
+
+static const char* DATE_DEFFUNCNAME_DiffMonths[2] =
+{
+ "MONATE",
+ "MONTHS"
+};
+
+static const char* DATE_DEFFUNCNAME_DiffYears[2] =
+{
+ "JAHRE",
+ "YEARS"
+};
+
+static const char* DATE_DEFFUNCNAME_IsLeapYear[2] =
+{
+ "ISTSCHALTJAHR",
+ "ISLEAPYEAR"
+};
+
+static const char* DATE_DEFFUNCNAME_DaysInMonth[2] =
+{
+ "TAGEIMMONAT",
+ "DAYSINMONTH"
+};
+
+static const char* DATE_DEFFUNCNAME_DaysInYear[2] =
+{
+ "TAGEIMJAHR",
+ "DAYSINYEAR"
+};
+
+static const char* DATE_DEFFUNCNAME_WeeksInYear[2] =
+{
+ "WOCHENIMJAHR",
+ "WEEKSINYEAR"
+};
+
+static const char* DATE_DEFFUNCNAME_Rot13[2] =
+{
+ "ROT13",
+ "ROT13"
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/pricing/black_scholes.cxx b/scaddins/source/pricing/black_scholes.cxx
new file mode 100644
index 000000000..88bdfc999
--- /dev/null
+++ b/scaddins/source/pricing/black_scholes.cxx
@@ -0,0 +1,939 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Copyright (C) 2012 Tino Kluge <tino.kluge@hrz.tu-chemnitz.de>
+ *
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <cmath>
+#include <cassert>
+#include <algorithm>
+#include <rtl/math.hxx>
+#include "black_scholes.hxx"
+
+// options prices and greeks in the Black-Scholes model
+// also known as TV (theoretical value)
+
+// the code is structured as follows:
+
+// (1) basic assets
+// - cash-or-nothing option: bincash()
+// - asset-or-nothing option: binasset()
+
+// (2) derived basic assets, can all be priced based on (1)
+// - vanilla put/call: putcall() = +/- ( binasset() - K*bincash() )
+// - truncated put/call (barriers active at maturity only)
+
+// (3) write a wrapper function to include all vanilla prices
+// - this is so we don't duplicate code when pricing barriers
+// as this is derived from vanillas
+
+// (4) single barrier options (knock-out), priced based on truncated vanillas
+// - it follows from the reflection principle that the price W(S) of a
+// single barrier option is given by
+// W(S) = V(S) - (B/S)^a V(B^2/S), a = 2(rd-rf)/vol^2 - 1
+// where V(S) is the price of the corresponding truncated vanilla
+// option
+// - to reduce code duplication and in anticipation of double barrier
+// options we write the following function
+// barrier_term(S,c) = V(c*S) - (B/S)^a V(c*B^2/S)
+
+// (5) double barrier options (knock-out)
+// - value is an infinite sum over option prices of the corresponding
+// truncated vanillas (truncated at both barriers):
+
+// W(S)=sum (B2/B1)^(i*a) (V(S(B2/B1)^(2i)) - (B1/S)^a V(B1^2/S (B2/B1)^(2i))
+
+// (6) write routines for put/call barriers and touch options which
+// mainly call the general double barrier pricer
+// the main routines are touch() and barrier()
+// both can price in/out barriers, double/single barriers as well as
+// vanillas
+
+
+// the framework allows any barriers to be priced as long as we define
+// the value/greek functions for the corresponding truncated vanilla
+// and wrap them into internal::vanilla() and internal::vanilla_trunc()
+
+// disadvantage of that approach is that due to the rules of
+// differentiations the formulas for greeks become long and possible
+// simplifications in the formulas won't be made
+
+// other code inefficiency due to multiplication with pm (+/- 1)
+// cvtsi2sd: int-->double, 6/3 cycles
+// mulsd: double-double multiplication, 5/1 cycles
+// with -O3, however, it compiles 2 versions with pm=1, and pm=-1
+// which are efficient
+// note this is tiny anyway as compared to exp/log (100 cycles),
+// pow (200 cycles), erf (70 cycles)
+
+// this code is not tested for numerical instability, ie overruns,
+// underruns, accuracy, etc
+
+
+namespace sca::pricing::bs {
+
+
+// helper functions
+
+static double sqr(double x) {
+ return x*x;
+}
+// normal density (see also ScInterpreter::phi)
+static double dnorm(double x) {
+ //return (1.0/sqrt(2.0*M_PI))*exp(-0.5*x*x); // windows may not have M_PI
+ return 0.39894228040143268*exp(-0.5*x*x);
+}
+// cumulative normal distribution (see also ScInterpreter::integralPhi)
+static double pnorm(double x) {
+ return 0.5 * std::erfc(-x * 0.7071067811865475);
+}
+
+// binary option cash (domestic)
+// call - pays 1 if S_T is above strike K
+// put - pays 1 if S_T is below strike K
+double bincash(double S, double vol, double rd, double rf,
+ double tau, double K,
+ types::PutCall pc, types::Greeks greeks) {
+ assert(tau>=0.0);
+ assert(S>0.0);
+ assert(vol>0.0);
+ assert(K>=0.0);
+
+ double val=0.0;
+
+ if(tau<=0.0) {
+ // special case tau=0 (expiry)
+ switch(greeks) {
+ case types::Value:
+ if( (pc==types::Call && S>=K) || (pc==types::Put && S<=K) ) {
+ val = 1.0;
+ } else {
+ val = 0.0;
+ }
+ break;
+ default:
+ val = 0.0;
+ }
+ } else if(K==0.0) {
+ // special case with zero strike
+ if(pc==types::Put) {
+ // up-and-out (put) with K=0
+ val=0.0;
+ } else {
+ // down-and-out (call) with K=0 (zero coupon bond)
+ switch(greeks) {
+ case types::Value:
+ val = 1.0;
+ break;
+ case types::Theta:
+ val = rd;
+ break;
+ case types::Rho_d:
+ val = -tau;
+ break;
+ default:
+ val = 0.0;
+ }
+ }
+ } else {
+ // standard case with K>0, tau>0
+ double d1 = ( log(S/K)+(rd-rf+0.5*vol*vol)*tau ) / (vol*sqrt(tau));
+ double d2 = d1 - vol*sqrt(tau);
+ int pm = (pc==types::Call) ? 1 : -1;
+
+ switch(greeks) {
+ case types::Value:
+ val = pnorm(pm*d2);
+ break;
+ case types::Delta:
+ val = pm*dnorm(d2)/(S*vol*sqrt(tau));
+ break;
+ case types::Gamma:
+ val = -pm*dnorm(d2)*d1/(sqr(S*vol)*tau);
+ break;
+ case types::Theta:
+ val = rd*pnorm(pm*d2)
+ + pm*dnorm(d2)*(log(S/K)/(vol*sqrt(tau))-0.5*d2)/tau;
+ break;
+ case types::Vega:
+ val = -pm*dnorm(d2)*d1/vol;
+ break;
+ case types::Volga:
+ val = pm*dnorm(d2)/(vol*vol)*(-d1*d1*d2+d1+d2);
+ break;
+ case types::Vanna:
+ val = pm*dnorm(d2)/(S*vol*vol*sqrt(tau))*(d1*d2-1.0);
+ break;
+ case types::Rho_d:
+ val = -tau*pnorm(pm*d2) + pm*dnorm(d2)*sqrt(tau)/vol;
+ break;
+ case types::Rho_f:
+ val = -pm*dnorm(d2)*sqrt(tau)/vol;
+ break;
+ default:
+ printf("bincash: greek %d not implemented\n", greeks );
+ abort();
+ }
+ }
+ return exp(-rd*tau)*val;
+}
+
+// binary option asset (foreign)
+// call - pays S_T if S_T is above strike K
+// put - pays S_T if S_T is below strike K
+double binasset(double S, double vol, double rd, double rf,
+ double tau, double K,
+ types::PutCall pc, types::Greeks greeks) {
+ assert(tau>=0.0);
+ assert(S>0.0);
+ assert(vol>0.0);
+ assert(K>=0.0);
+
+ double val=0.0;
+ if(tau<=0.0) {
+ // special case tau=0 (expiry)
+ switch(greeks) {
+ case types::Value:
+ if( (pc==types::Call && S>=K) || (pc==types::Put && S<=K) ) {
+ val = S;
+ } else {
+ val = 0.0;
+ }
+ break;
+ case types::Delta:
+ if( (pc==types::Call && S>=K) || (pc==types::Put && S<=K) ) {
+ val = 1.0;
+ } else {
+ val = 0.0;
+ }
+ break;
+ default:
+ val = 0.0;
+ }
+ } else if(K==0.0) {
+ // special case with zero strike (forward with zero strike)
+ if(pc==types::Put) {
+ // up-and-out (put) with K=0
+ val = 0.0;
+ } else {
+ // down-and-out (call) with K=0 (type of forward)
+ switch(greeks) {
+ case types::Value:
+ val = S;
+ break;
+ case types::Delta:
+ val = 1.0;
+ break;
+ case types::Theta:
+ val = rf*S;
+ break;
+ case types::Rho_f:
+ val = -tau*S;
+ break;
+ default:
+ val = 0.0;
+ }
+ }
+ } else {
+ // normal case
+ double d1 = ( log(S/K)+(rd-rf+0.5*vol*vol)*tau ) / (vol*sqrt(tau));
+ double d2 = d1 - vol*sqrt(tau);
+ int pm = (pc==types::Call) ? 1 : -1;
+
+ switch(greeks) {
+ case types::Value:
+ val = S*pnorm(pm*d1);
+ break;
+ case types::Delta:
+ val = pnorm(pm*d1) + pm*dnorm(d1)/(vol*sqrt(tau));
+ break;
+ case types::Gamma:
+ val = -pm*dnorm(d1)*d2/(S*sqr(vol)*tau);
+ break;
+ case types::Theta:
+ val = rf*S*pnorm(pm*d1)
+ + pm*S*dnorm(d1)*(log(S/K)/(vol*sqrt(tau))-0.5*d1)/tau;
+ break;
+ case types::Vega:
+ val = -pm*S*dnorm(d1)*d2/vol;
+ break;
+ case types::Volga:
+ val = pm*S*dnorm(d1)/(vol*vol)*(-d1*d2*d2+d1+d2);
+ break;
+ case types::Vanna:
+ val = pm*dnorm(d1)/(vol*vol*sqrt(tau))*(d2*d2-1.0);
+ break;
+ case types::Rho_d:
+ val = pm*S*dnorm(d1)*sqrt(tau)/vol;
+ break;
+ case types::Rho_f:
+ val = -tau*S*pnorm(pm*d1) - pm*S*dnorm(d1)*sqrt(tau)/vol;
+ break;
+ default:
+ printf("binasset: greek %d not implemented\n", greeks );
+ abort();
+ }
+ }
+ return exp(-rf*tau)*val;
+}
+
+// just for convenience we can combine bincash and binasset into
+// one function binary
+// using bincash() if fd==types::Domestic
+// using binasset() if fd==types::Foreign
+static double binary(double S, double vol, double rd, double rf,
+ double tau, double K,
+ types::PutCall pc, types::ForDom fd,
+ types::Greeks greek) {
+ double val=0.0;
+ switch(fd) {
+ case types::Domestic:
+ val = bincash(S,vol,rd,rf,tau,K,pc,greek);
+ break;
+ case types::Foreign:
+ val = binasset(S,vol,rd,rf,tau,K,pc,greek);
+ break;
+ default:
+ // never get here
+ assert(false);
+ }
+ return val;
+}
+
+// further wrapper to combine single/double barrier binary options
+// into one function
+// B1<=0 - it is assumed lower barrier not set
+// B2<=0 - it is assumed upper barrier not set
+static double binary(double S, double vol, double rd, double rf,
+ double tau, double B1, double B2,
+ types::ForDom fd, types::Greeks greek) {
+ assert(tau>=0.0);
+ assert(S>0.0);
+ assert(vol>0.0);
+
+ double val=0.0;
+
+ if(B1<=0.0 && B2<=0.0) {
+ // no barriers set, payoff 1.0 (domestic) or S_T (foreign)
+ val = binary(S,vol,rd,rf,tau,0.0,types::Call,fd,greek);
+ } else if(B1<=0.0 && B2>0.0) {
+ // upper barrier (put)
+ val = binary(S,vol,rd,rf,tau,B2,types::Put,fd,greek);
+ } else if(B1>0.0 && B2<=0.0) {
+ // lower barrier (call)
+ val = binary(S,vol,rd,rf,tau,B1,types::Call,fd,greek);
+ } else if(B1>0.0 && B2>0.0) {
+ // double barrier
+ if(B2<=B1) {
+ val = 0.0;
+ } else {
+ val = binary(S,vol,rd,rf,tau,B2,types::Put,fd,greek)
+ - binary(S,vol,rd,rf,tau,B1,types::Put,fd,greek);
+ }
+ } else {
+ // never get here
+ assert(false);
+ }
+
+ return val;
+}
+
+// vanilla put/call option
+// call pays (S_T-K)^+
+// put pays (K-S_T)^+
+// this is the same as: +/- (binasset - K*bincash)
+double putcall(double S, double vol, double rd, double rf,
+ double tau, double K,
+ types::PutCall putcall, types::Greeks greeks) {
+
+ assert(tau>=0.0);
+ assert(S>0.0);
+ assert(vol>0.0);
+ assert(K>=0.0);
+
+ double val = 0.0;
+ int pm = (putcall==types::Call) ? 1 : -1;
+
+ if(K==0 || tau==0.0) {
+ // special cases, simply refer to binasset() and bincash()
+ val = pm * ( binasset(S,vol,rd,rf,tau,K,putcall,greeks)
+ - K*bincash(S,vol,rd,rf,tau,K,putcall,greeks) );
+ } else {
+ // general case
+ // we could just use pm*(binasset-K*bincash), however
+ // since the formula for delta and gamma simplify we write them
+ // down here
+ double d1 = ( log(S/K)+(rd-rf+0.5*vol*vol)*tau ) / (vol*sqrt(tau));
+ double d2 = d1 - vol*sqrt(tau);
+
+ switch(greeks) {
+ case types::Value:
+ val = pm * ( exp(-rf*tau)*S*pnorm(pm*d1)-exp(-rd*tau)*K*pnorm(pm*d2) );
+ break;
+ case types::Delta:
+ val = pm*exp(-rf*tau)*pnorm(pm*d1);
+ break;
+ case types::Gamma:
+ val = exp(-rf*tau)*dnorm(d1)/(S*vol*sqrt(tau));
+ break;
+ default:
+ // too lazy for the other greeks, so simply refer to binasset/bincash
+ val = pm * ( binasset(S,vol,rd,rf,tau,K,putcall,greeks)
+ - K*bincash(S,vol,rd,rf,tau,K,putcall,greeks) );
+ }
+ }
+ return val;
+}
+
+// truncated put/call option, single barrier
+// need to specify whether it's down-and-out or up-and-out
+// regular (keeps monotonicity): down-and-out for call, up-and-out for put
+// reverse (destroys monoton): up-and-out for call, down-and-out for put
+// call pays (S_T-K)^+
+// put pays (K-S_T)^+
+double putcalltrunc(double S, double vol, double rd, double rf,
+ double tau, double K, double B,
+ types::PutCall pc, types::KOType kotype,
+ types::Greeks greeks) {
+
+ assert(tau>=0.0);
+ assert(S>0.0);
+ assert(vol>0.0);
+ assert(K>=0.0);
+ assert(B>=0.0);
+
+ int pm = (pc==types::Call) ? 1 : -1;
+ double val = 0.0;
+
+ switch(kotype) {
+ case types::Regular:
+ if( (pc==types::Call && B<=K) || (pc==types::Put && B>=K) ) {
+ // option degenerates to standard plain vanilla call/put
+ val = putcall(S,vol,rd,rf,tau,K,pc,greeks);
+ } else {
+ // normal case with truncation
+ val = pm * ( binasset(S,vol,rd,rf,tau,B,pc,greeks)
+ - K*bincash(S,vol,rd,rf,tau,B,pc,greeks) );
+ }
+ break;
+ case types::Reverse:
+ if( (pc==types::Call && B<=K) || (pc==types::Put && B>=K) ) {
+ // option degenerates to zero payoff
+ val = 0.0;
+ } else {
+ // normal case with truncation
+ val = binasset(S,vol,rd,rf,tau,K,types::Call,greeks)
+ - binasset(S,vol,rd,rf,tau,B,types::Call,greeks)
+ - K * ( bincash(S,vol,rd,rf,tau,K,types::Call,greeks)
+ - bincash(S,vol,rd,rf,tau,B,types::Call,greeks) );
+ }
+ break;
+ default:
+ assert(false);
+ }
+ return val;
+}
+
+// wrapper function for put/call option which combines
+// double/single/no truncation barrier
+// B1<=0 - assume no lower barrier
+// B2<=0 - assume no upper barrier
+double putcalltrunc(double S, double vol, double rd, double rf,
+ double tau, double K, double B1, double B2,
+ types::PutCall pc, types::Greeks greek) {
+
+ assert(tau>=0.0);
+ assert(S>0.0);
+ assert(vol>0.0);
+ assert(K>=0.0);
+
+ double val=0.0;
+
+ if(B1<=0.0 && B2<=0.0) {
+ // no barriers set, plain vanilla
+ val = putcall(S,vol,rd,rf,tau,K,pc,greek);
+ } else if(B1<=0.0 && B2>0.0) {
+ // upper barrier: reverse barrier for call, regular barrier for put
+ if(pc==types::Call) {
+ val = putcalltrunc(S,vol,rd,rf,tau,K,B2,pc,types::Reverse,greek);
+ } else {
+ val = putcalltrunc(S,vol,rd,rf,tau,K,B2,pc,types::Regular,greek);
+ }
+ } else if(B1>0.0 && B2<=0.0) {
+ // lower barrier: regular barrier for call, reverse barrier for put
+ if(pc==types::Call) {
+ val = putcalltrunc(S,vol,rd,rf,tau,K,B1,pc,types::Regular,greek);
+ } else {
+ val = putcalltrunc(S,vol,rd,rf,tau,K,B1,pc,types::Reverse,greek);
+ }
+ } else if(B1>0.0 && B2>0.0) {
+ // double barrier
+ if(B2<=B1) {
+ val = 0.0;
+ } else {
+ int pm = (pc==types::Call) ? 1 : -1;
+ val = pm * (
+ putcalltrunc(S,vol,rd,rf,tau,K,B1,pc,types::Regular,greek)
+ - putcalltrunc(S,vol,rd,rf,tau,K,B2,pc,types::Regular,greek)
+ );
+ }
+ } else {
+ // never get here
+ assert(false);
+ }
+ return val;
+}
+
+namespace internal {
+
+// wrapper function for all non-path dependent options
+// this is only an internal function, used to avoid code duplication when
+// going to path-dependent barrier options,
+// K<0 - assume binary option
+// K>=0 - assume put/call option
+static double vanilla(double S, double vol, double rd, double rf,
+ double tau, double K, double B1, double B2,
+ types::PutCall pc, types::ForDom fd,
+ types::Greeks greek) {
+ double val = 0.0;
+ if(K<0.0) {
+ // binary option if K<0
+ val = binary(S,vol,rd,rf,tau,B1,B2,fd,greek);
+ } else {
+ val = putcall(S,vol,rd,rf,tau,K,pc,greek);
+ }
+ return val;
+}
+static double vanilla_trunc(double S, double vol, double rd, double rf,
+ double tau, double K, double B1, double B2,
+ types::PutCall pc, types::ForDom fd,
+ types::Greeks greek) {
+ double val = 0.0;
+ if(K<0.0) {
+ // binary option if K<0
+ // truncated is actually the same as the vanilla binary
+ val = binary(S,vol,rd,rf,tau,B1,B2,fd,greek);
+ } else {
+ val = putcalltrunc(S,vol,rd,rf,tau,K,B1,B2,pc,greek);
+ }
+ return val;
+}
+
+} // namespace internal
+
+// path dependent options
+
+
+namespace internal {
+
+// helper term for any type of options with continuously monitored barriers,
+// internal, should not be called from outside
+// calculates value and greeks based on
+// V(S) = V1(sc*S) - (B/S)^a V1(sc*B^2/S)
+// (a=2 mu/vol^2, mu drift in logspace, ie. mu=(rd-rf-1/2vol^2))
+// with sc=1 and V1() being the price of the respective truncated
+// vanilla option, V() would be the price of the respective barrier
+// option if only one barrier is present
+static double barrier_term(double S, double vol, double rd, double rf,
+ double tau, double K, double B1, double B2, double sc,
+ types::PutCall pc, types::ForDom fd,
+ types::Greeks greek) {
+
+ assert(tau>=0.0);
+ assert(S>0.0);
+ assert(vol>0.0);
+
+ // V(S) = V1(sc*S) - (B/S)^a V1(sc*B^2/S)
+ double val = 0.0;
+ double B = (B1>0.0) ? B1 : B2;
+ double a = 2.0*(rd-rf)/(vol*vol)-1.0; // helper variable
+ double b = 4.0*(rd-rf)/(vol*vol*vol); // helper variable -da/dvol
+ double c = 12.0*(rd-rf)/(vol*vol*vol*vol); // helper -db/dvol
+ switch(greek) {
+ case types::Value:
+ val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ - pow(B/S,a)*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+ break;
+ case types::Delta:
+ val = sc*vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ + pow(B/S,a) * (
+ a/S*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value)
+ + sqr(B/S)*sc*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ );
+ break;
+ case types::Gamma:
+ val = sc*sc*vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ - pow(B/S,a) * (
+ a*(a+1.0)/(S*S)*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value)
+ + (2.0*a+2.0)*B*B/(S*S*S)*sc*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Delta)
+ + sqr(sqr(B/S))*sc*sc*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Gamma)
+ );
+ break;
+ case types::Theta:
+ val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ - pow(B/S,a)*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+ break;
+ case types::Vega:
+ val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ - pow(B/S,a) * (
+ - b*log(B/S)*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value)
+ + 1.0*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ );
+ break;
+ case types::Volga:
+ val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ - pow(B/S,a) * (
+ log(B/S)*(b*b*log(B/S)+c)*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value)
+ - 2.0*b*log(B/S)*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Vega)
+ + 1.0*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Volga)
+ );
+ break;
+ case types::Vanna:
+ val = sc*vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ - pow(B/S,a) * (
+ b/S*(log(B/S)*a+1.0)*
+ vanilla_trunc(B*B/S*sc,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value)
+ + b*log(B/S)*sqr(B/S)*sc*
+ vanilla_trunc(B*B/S*sc,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Delta)
+ - a/S*
+ vanilla_trunc(B*B/S*sc,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Vega)
+ - sqr(B/S)*sc*
+ vanilla_trunc(B*B/S*sc,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Vanna)
+ );
+ break;
+ case types::Rho_d:
+ val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ - pow(B/S,a) * (
+ 2.0*log(B/S)/(vol*vol)*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value)
+ + 1.0*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ );
+ break;
+ case types::Rho_f:
+ val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ - pow(B/S,a) * (
+ - 2.0*log(B/S)/(vol*vol)*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value)
+ + 1.0*
+ vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ );
+ break;
+ default:
+ printf("barrier_term: greek %d not implemented\n", greek );
+ abort();
+ }
+ return val;
+}
+
+// one term of the infinite sum for the valuation of double barriers
+static double barrier_double_term( double S, double vol, double rd, double rf,
+ double tau, double K, double B1, double B2,
+ double fac, double sc, int i,
+ types::PutCall pc, types::ForDom fd, types::Greeks greek) {
+
+ double val = 0.0;
+ double b = 4.0*i*(rd-rf)/(vol*vol*vol); // helper variable -da/dvol
+ double c = 12.0*i*(rd-rf)/(vol*vol*vol*vol); // helper -db/dvol
+ switch(greek) {
+ case types::Value:
+ val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek);
+ break;
+ case types::Delta:
+ val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek);
+ break;
+ case types::Gamma:
+ val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek);
+ break;
+ case types::Theta:
+ val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek);
+ break;
+ case types::Vega:
+ val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek)
+ - b*log(B2/B1)*fac *
+ barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Value);
+ break;
+ case types::Volga:
+ val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek)
+ - 2.0*b*log(B2/B1)*fac *
+ barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Vega)
+ + log(B2/B1)*fac*(c+b*b*log(B2/B1)) *
+ barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Value);
+ break;
+ case types::Vanna:
+ val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek)
+ - b*log(B2/B1)*fac *
+ barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Delta);
+ break;
+ case types::Rho_d:
+ val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek)
+ + 2.0*i/(vol*vol)*log(B2/B1)*fac *
+ barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Value);
+ break;
+ case types::Rho_f:
+ val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek)
+ - 2.0*i/(vol*vol)*log(B2/B1)*fac *
+ barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Value);
+ break;
+ default:
+ printf("barrier_double_term: greek %d not implemented\n", greek );
+ abort();
+ }
+ return val;
+}
+
+// general pricer for any type of options with continuously monitored barriers
+// allows two, one or zero barriers, only knock-out style
+// payoff profiles allowed based on vanilla_trunc()
+static double barrier_ko(double S, double vol, double rd, double rf,
+ double tau, double K, double B1, double B2,
+ types::PutCall pc, types::ForDom fd,
+ types::Greeks greek) {
+
+ assert(tau>=0.0);
+ assert(S>0.0);
+ assert(vol>0.0);
+
+ double val = 0.0;
+
+ if(B1<=0.0 && B2<=0.0) {
+ // no barriers --> vanilla case
+ val = vanilla(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+ } else if(B1>0.0 && B2<=0.0) {
+ // lower barrier
+ if(S<=B1) {
+ val = 0.0; // knocked out
+ } else {
+ val = barrier_term(S,vol,rd,rf,tau,K,B1,B2,1.0,pc,fd,greek);
+ }
+ } else if(B1<=0.0 && B2>0.0) {
+ // upper barrier
+ if(S>=B2) {
+ val = 0.0; // knocked out
+ } else {
+ val = barrier_term(S,vol,rd,rf,tau,K,B1,B2,1.0,pc,fd,greek);
+ }
+ } else if(B1>0.0 && B2>0.0) {
+ // double barrier
+ if(S<=B1 || S>=B2) {
+ val = 0.0; // knocked out (always true if wrong input B1>B2)
+ } else {
+ // more complex calculation as we have to evaluate an infinite
+ // sum
+ // to reduce very costly pow() calls we define some variables
+ double a = 2.0*(rd-rf)/(vol*vol)-1.0; // 2 (mu-1/2vol^2)/sigma^2
+ double BB2=sqr(B2/B1);
+ double BBa=pow(B2/B1,a);
+ double BB2inv=1.0/BB2;
+ double BBainv=1.0/BBa;
+ double fac=1.0;
+ double facinv=1.0;
+ double sc=1.0;
+ double scinv=1.0;
+
+ // initial term i=0
+ val=barrier_double_term(S,vol,rd,rf,tau,K,B1,B2,fac,sc,0,pc,fd,greek);
+ // infinite loop, 10 should be plenty, normal would be 2
+ for(int i=1; i<10; i++) {
+ fac*=BBa;
+ facinv*=BBainv;
+ sc*=BB2;
+ scinv*=BB2inv;
+ double add =
+ barrier_double_term(S,vol,rd,rf,tau,K,B1,B2,fac,sc,i,pc,fd,greek) +
+ barrier_double_term(S,vol,rd,rf,tau,K,B1,B2,facinv,scinv,-i,pc,fd,greek);
+ val += add;
+ //printf("%i: val=%e (add=%e)\n",i,val,add);
+ if(fabs(add) <= 1e-12*fabs(val)) {
+ break;
+ }
+ }
+ // not knocked-out double barrier end
+ }
+ // double barrier end
+ } else {
+ // no such barrier combination exists
+ assert(false);
+ }
+
+ return val;
+}
+
+// knock-in style barrier
+static double barrier_ki(double S, double vol, double rd, double rf,
+ double tau, double K, double B1, double B2,
+ types::PutCall pc, types::ForDom fd,
+ types::Greeks greek) {
+ return vanilla(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ -barrier_ko(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+}
+
+// general barrier
+static double barrier(double S, double vol, double rd, double rf,
+ double tau, double K, double B1, double B2,
+ types::PutCall pc, types::ForDom fd,
+ types::BarrierKIO kio, types::BarrierActive bcont,
+ types::Greeks greek) {
+
+ double val = 0.0;
+ if( kio==types::KnockOut && bcont==types::Maturity ) {
+ // truncated vanilla option
+ val = vanilla_trunc(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+ } else if ( kio==types::KnockOut && bcont==types::Continuous ) {
+ // standard knock-out barrier
+ val = barrier_ko(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+ } else if ( kio==types::KnockIn && bcont==types::Maturity ) {
+ // inverse truncated vanilla
+ val = vanilla(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek)
+ - vanilla_trunc(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+ } else if ( kio==types::KnockIn && bcont==types::Continuous ) {
+ // standard knock-in barrier
+ val = barrier_ki(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+ } else {
+ // never get here
+ assert(false);
+ }
+ return val;
+}
+
+} // namespace internal
+
+
+// touch/no-touch options (cash/asset or nothing payoff profile)
+double touch(double S, double vol, double rd, double rf,
+ double tau, double B1, double B2, types::ForDom fd,
+ types::BarrierKIO kio, types::BarrierActive bcont,
+ types::Greeks greek) {
+
+ double K=-1.0; // dummy
+ types::PutCall pc = types::Call; // dummy
+ double val = 0.0;
+ if( kio==types::KnockOut && bcont==types::Maturity ) {
+ // truncated vanilla option
+ val = internal::vanilla_trunc(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+ } else if ( kio==types::KnockOut && bcont==types::Continuous ) {
+ // standard knock-out barrier
+ val = internal::barrier_ko(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+ } else if ( kio==types::KnockIn && bcont==types::Maturity ) {
+ // inverse truncated vanilla
+ val = internal::vanilla(S,vol,rd,rf,tau,K,-1.0,-1.0,pc,fd,greek)
+ - internal::vanilla_trunc(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+ } else if ( kio==types::KnockIn && bcont==types::Continuous ) {
+ // standard knock-in barrier
+ val = internal::vanilla(S,vol,rd,rf,tau,K,-1.0,-1.0,pc,fd,greek)
+ - internal::barrier_ko(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek);
+ } else {
+ // never get here
+ assert(false);
+ }
+ return val;
+}
+
+// barrier option (put/call payoff profile)
+double barrier(double S, double vol, double rd, double rf,
+ double tau, double K, double B1, double B2,
+ double rebate,
+ types::PutCall pc, types::BarrierKIO kio,
+ types::BarrierActive bcont,
+ types::Greeks greek) {
+ assert(tau>=0.0);
+ assert(S>0.0);
+ assert(vol>0.0);
+ assert(K>=0.0);
+ types::ForDom fd = types::Domestic;
+ double val=internal::barrier(S,vol,rd,rf,tau,K,B1,B2,pc,fd,kio,bcont,greek);
+ if(rebate!=0.0) {
+ // opposite of barrier knock-in/out type
+ types::BarrierKIO kio2 = (kio==types::KnockIn) ? types::KnockOut
+ : types::KnockIn;
+ val += rebate*touch(S,vol,rd,rf,tau,B1,B2,fd,kio2,bcont,greek);
+ }
+ return val;
+}
+
+// probability of hitting a barrier
+// this is almost the same as the price of a touch option (domestic)
+// as it pays one if a barrier is hit; we only have to offset the
+// discounting and we get the probability
+double prob_hit(double S, double vol, double mu,
+ double tau, double B1, double B2) {
+ double const rd=0.0;
+ double rf=-mu;
+ return 1.0 - touch(S,vol,rd,rf,tau,B1,B2,types::Domestic,types::KnockOut,
+ types::Continuous, types::Value);
+}
+
+// probability of being in-the-money, ie payoff is greater zero,
+// assuming payoff(S_T) > 0 iff S_T in [B1, B2]
+// this the same as the price of a cash or nothing option
+// with no discounting
+double prob_in_money(double S, double vol, double mu,
+ double tau, double B1, double B2) {
+ assert(S>0.0);
+ assert(vol>0.0);
+ assert(tau>=0.0);
+ double val = 0.0;
+ if( B1<B2 || B1<=0.0 || B2<=0.0 ) {
+ val = binary(S,vol,0.0,-mu,tau,B1,B2,types::Domestic,types::Value);
+ }
+ return val;
+}
+double prob_in_money(double S, double vol, double mu,
+ double tau, double K, double B1, double B2,
+ types::PutCall pc) {
+ assert(S>0.0);
+ assert(vol>0.0);
+ assert(tau>=0.0);
+
+ // if K<0 we assume a binary option is given
+ if(K<0.0) {
+ return prob_in_money(S,vol,mu,tau,B1,B2);
+ }
+
+ double val = 0.0;
+ double BM1, BM2; // range of in the money [BM1, BM2]
+ // non-sense parameters with no positive payoff
+ if( (B1>B2 && B1>0.0 && B2>0.0) ||
+ (K>=B2 && B2>0.0 && pc==types::Call) ||
+ (K<=B1 && pc==types::Put) ) {
+ val = 0.0;
+ // need to figure out between what barriers payoff is greater 0
+ } else if(pc==types::Call) {
+ BM1=std::max(B1, K);
+ BM2=B2;
+ val = prob_in_money(S,vol,mu,tau,BM1,BM2);
+ } else if (pc==types::Put) {
+ BM1=B1;
+ BM2= (B2>0.0) ? std::min(B2,K) : K;
+ val = prob_in_money(S,vol,mu,tau,BM1,BM2);
+ } else {
+ // don't get here
+ assert(false);
+ }
+ return val;
+}
+
+} // namespace sca
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/pricing/black_scholes.hxx b/scaddins/source/pricing/black_scholes.hxx
new file mode 100644
index 000000000..9e82857e0
--- /dev/null
+++ b/scaddins/source/pricing/black_scholes.hxx
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Copyright (C) 2012 Tino Kluge <tino.kluge@hrz.tu-chemnitz.de>
+ *
+ */
+
+
+#pragma once
+
+// options prices and greeks in the Black-Scholes model
+// also known as TV (theoretical value)
+
+namespace sca {
+namespace pricing {
+
+namespace bs {
+
+namespace types {
+enum Greeks {
+ Value = 0,
+ Delta = 1, // d/dS
+ Gamma = 2, // d^2/dS^2
+ Theta = 3, // d/dt
+ Vega = 4, // d/dsigma
+ Volga = 5, // d^2/dsigma^2
+ Vanna = 6, // d^2/dsigma dS
+ Rho_d = 7, // d/dr_d
+ Rho_f = 8 // d/dr_f
+};
+
+enum PutCall {
+ Call = 1,
+ Put = -1
+};
+
+enum KOType {
+ Regular = 0,
+ Reverse = 1
+};
+
+enum BarrierKIO {
+ KnockIn = -1,
+ KnockOut = 1
+};
+
+// barrier observed continuously or just at maturity (truncated payoff)
+enum BarrierActive {
+ Continuous = 0,
+ Maturity = 1
+};
+
+enum ForDom {
+ Domestic = 0,
+ Foreign = 1
+};
+
+} // namespace types
+
+
+// binary option cash (domestic)
+// call - pays 1 if S_T is above strike K
+// put - pays 1 if S_T is below strike K
+double bincash(double S, double vol, double rd, double rf,
+ double tau, double K,
+ types::PutCall pc, types::Greeks greeks);
+
+// binary option asset (foreign)
+// call - pays S_T if S_T is above strike K
+// put - pays S_T if S_T is below strike K
+double binasset(double S, double vol, double rd, double rf,
+ double tau, double K,
+ types::PutCall pc, types::Greeks greeks);
+
+// vanilla put/call option
+// call pays (S_T-K)^+
+// put pays (K-S_T)^+
+// this is the same as: +/- (binasset - K*bincash)
+double putcall(double S, double vol, double rd, double rf,
+ double tau, double K,
+ types::PutCall putcall, types::Greeks greeks);
+
+
+// truncated put/call option, single barrier
+// need to specify whether it's down-and-out or up-and-out
+// regular (keeps monotonicity): down-and-out for call, up-and-out for put
+// reverse (destroys monoton): up-and-out for call, down-and-out for put
+// call pays (S_T-K)^+
+// put pays (K-S_T)^+
+double putcalltrunc(double S, double vol, double rd, double rf,
+ double tau, double K, double B,
+ types::PutCall pc, types::KOType kotype,
+ types::Greeks greeks);
+
+
+// wrapper function for put/call option which combines
+// double/single/no truncation barrier
+// B1<=0 - assume no lower barrier
+// B2<=0 - assume no upper barrier
+double putcalltrunc(double S, double vol, double rd, double rf,
+ double tau, double K, double B1, double B2,
+ types::PutCall pc, types::Greeks greek);
+
+// barrier
+// touch/no-touch options (cash/asset or nothing payoff profile)
+double touch(double S, double vol, double rd, double rf,
+ double tau, double B1, double B2, types::ForDom fd,
+ types::BarrierKIO kio, types::BarrierActive bcont,
+ types::Greeks greek);
+
+// barrier
+// barrier option (put/call payoff profile)
+double barrier(double S, double vol, double rd, double rf,
+ double tau, double K, double B1, double B2,
+ double rebate,
+ types::PutCall pc, types::BarrierKIO kio,
+ types::BarrierActive bcont,
+ types::Greeks greek);
+
+
+// probability of hitting a barrier
+double prob_hit(double S, double vol, double mu,
+ double tau, double B1, double B2);
+
+
+// probability of being in-the-money, ie payoff is greater zero,
+// assuming payoff(S_T) > 0 iff S_T in [B1, B2]
+double prob_in_money(double S, double vol, double mu,
+ double tau, double B1, double B2);
+double prob_in_money(double S, double vol, double mu,
+ double tau, double K, double B1, double B2,
+ types::PutCall pc);
+
+
+} // namespace bs
+
+} // namespace pricing
+} // namespace sca
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/pricing/pricing.component b/scaddins/source/pricing/pricing.component
new file mode 100644
index 000000000..fbabf1fb6
--- /dev/null
+++ b/scaddins/source/pricing/pricing.component
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.sheet.addin.PricingFunctionsImpl"
+ constructor="scaddins_ScaPricingAddIn_get_implementation" single-instance="true">
+ <service name="com.sun.star.sheet.AddIn"/>
+ <service name="com.sun.star.sheet.addin.PricingFunctions"/>
+ </implementation>
+</component>
diff --git a/scaddins/source/pricing/pricing.cxx b/scaddins/source/pricing/pricing.cxx
new file mode 100644
index 000000000..f4e9e53f4
--- /dev/null
+++ b/scaddins/source/pricing/pricing.cxx
@@ -0,0 +1,510 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// pricing functions add in
+
+// all of the UNO add-in technical details have been copied from
+// ../datefunc/datefunc.cxx
+
+#include "pricing.hxx"
+#include "black_scholes.hxx"
+#include <pricing.hrc>
+#include <strings.hrc>
+
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <algorithm>
+#include <cmath>
+#include <string_view>
+#include <unotools/resmgr.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace ::com::sun::star;
+using namespace sca::pricing;
+
+
+constexpr OUStringLiteral ADDIN_SERVICE = u"com.sun.star.sheet.AddIn";
+constexpr OUStringLiteral MY_SERVICE = u"com.sun.star.sheet.addin.PricingFunctions";
+constexpr OUStringLiteral MY_IMPLNAME = u"com.sun.star.sheet.addin.PricingFunctionsImpl";
+
+#define UNIQUE false // function name does not exist in Calc
+
+#define STDPAR false // all parameters are described
+
+#define FUNCDATA( FuncName, CompName, ParamCount, Category, Double, IntPar ) \
+ { "get" #FuncName, PRICING_FUNCNAME_##FuncName, PRICING_FUNCDESC_##FuncName, CompName, ParamCount, Category, Double, IntPar }
+
+const ScaFuncDataBase pFuncDataArr[] =
+{
+ FUNCDATA(OptBarrier, "OPT_BARRIER", 13, ScaCategory::Finance, UNIQUE, STDPAR),
+ FUNCDATA(OptTouch, "OPT_TOUCH", 11, ScaCategory::Finance, UNIQUE, STDPAR),
+ FUNCDATA(OptProbHit, "OPT_PROB_HIT", 6, ScaCategory::Finance, UNIQUE, STDPAR),
+ FUNCDATA(OptProbInMoney, "OPT_PROB_INMONEY", 8, ScaCategory::Finance, UNIQUE, STDPAR)
+};
+
+#undef FUNCDATA
+
+ScaFuncData::ScaFuncData( const ScaFuncDataBase& rBaseData ) :
+ aIntName( OUString::createFromAscii( rBaseData.pIntName ) ),
+ pUINameID( rBaseData.pUINameID ),
+ pDescrID( rBaseData.pDescrID ),
+ nParamCount( rBaseData.nParamCount ),
+ eCat( rBaseData.eCat ),
+ bDouble( rBaseData.bDouble ),
+ bWithOpt( rBaseData.bWithOpt )
+{
+ aCompList.push_back(OUString::createFromAscii(rBaseData.pCompName));
+}
+
+sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const
+{
+ if( !bWithOpt )
+ nParam++;
+ return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2);
+}
+
+void sca::pricing::InitScaFuncDataList(ScaFuncDataList& rList)
+{
+ for (const auto & nIndex : pFuncDataArr)
+ rList.push_back(ScaFuncData(nIndex));
+}
+
+// entry points for service registration / instantiation
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scaddins_ScaPricingAddIn_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ScaPricingAddIn());
+}
+
+// "normal" service implementation
+ScaPricingAddIn::ScaPricingAddIn()
+{
+}
+
+ScaPricingAddIn::~ScaPricingAddIn()
+{
+}
+
+static const char* pLang[] = { "en" };
+static const char* pCoun[] = { "US" };
+const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang );
+
+void ScaPricingAddIn::InitDefLocales()
+{
+ pDefLocales.reset( new lang::Locale[ nNumOfLoc ] );
+
+ for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ )
+ {
+ pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] );
+ pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] );
+ }
+}
+
+const lang::Locale& ScaPricingAddIn::GetLocale( sal_uInt32 nIndex )
+{
+ if( !pDefLocales )
+ InitDefLocales();
+
+ return (nIndex < nNumOfLoc) ? pDefLocales[ nIndex ] : aFuncLoc;
+}
+
+void ScaPricingAddIn::InitData()
+{
+ aResLocale = Translate::Create("sca", LanguageTag(aFuncLoc));
+ pFuncDataList.reset(new ScaFuncDataList);
+ InitScaFuncDataList(*pFuncDataList);
+ pDefLocales.reset();
+}
+
+OUString ScaPricingAddIn::GetFuncDescrStr(const TranslateId* pResId, sal_uInt16 nStrIndex)
+{
+ return ScaResId(pResId[nStrIndex - 1]);
+}
+
+// XServiceName
+OUString SAL_CALL ScaPricingAddIn::getServiceName()
+{
+ // name of specific AddIn service
+ return MY_SERVICE;
+}
+
+// XServiceInfo
+OUString SAL_CALL ScaPricingAddIn::getImplementationName()
+{
+ return MY_IMPLNAME;
+}
+
+sal_Bool SAL_CALL ScaPricingAddIn::supportsService( const OUString& aServiceName )
+{
+ return cppu::supportsService(this, aServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL ScaPricingAddIn::getSupportedServiceNames()
+{
+ return { ADDIN_SERVICE, MY_SERVICE };
+}
+
+// XLocalizable
+void SAL_CALL ScaPricingAddIn::setLocale( const lang::Locale& eLocale )
+{
+ aFuncLoc = eLocale;
+ InitData(); // change of locale invalidates resources!
+}
+
+lang::Locale SAL_CALL ScaPricingAddIn::getLocale()
+{
+ return aFuncLoc;
+}
+
+// function descriptions start here
+// XAddIn
+OUString SAL_CALL ScaPricingAddIn::getProgrammaticFuntionName( const OUString& )
+{
+ // not used by calc
+ // (but should be implemented for other uses of the AddIn service)
+ return OUString();
+}
+
+OUString SAL_CALL ScaPricingAddIn::getDisplayFunctionName( const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if (fDataIt != pFuncDataList->end() )
+ {
+ aRet = ScaResId(fDataIt->GetUINameID());
+ if( fDataIt->IsDouble() )
+ aRet += "_ADD";
+ }
+ else
+ {
+ aRet = "UNKNOWNFUNC_" + aProgrammaticName;
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaPricingAddIn::getFunctionDescription( const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if( pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), 1 );
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaPricingAddIn::getDisplayArgumentName(
+ const OUString& aProgrammaticName, sal_Int32 nArgument )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if( pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) )
+ {
+ sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
+ if( nStr )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr );
+ else
+ aRet = "internal";
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaPricingAddIn::getArgumentDescription(
+ const OUString& aProgrammaticName, sal_Int32 nArgument )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if( pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) )
+ {
+ sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
+ if( nStr )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr + 1 );
+ else
+ aRet = "for internal use only";
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaPricingAddIn::getProgrammaticCategoryName(
+ const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if( pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() )
+ {
+ switch( fDataIt->GetCategory() )
+ {
+ case ScaCategory::DateTime: aRet = "Date&Time"; break;
+ case ScaCategory::Text: aRet = "Text"; break;
+ case ScaCategory::Finance: aRet = "Financial"; break;
+ case ScaCategory::Inf: aRet = "Information"; break;
+ case ScaCategory::Math: aRet = "Mathematical"; break;
+ case ScaCategory::Tech: aRet = "Technical"; break;
+ }
+ }
+
+ if( aRet.isEmpty() )
+ aRet = "Add-In";
+ return aRet;
+}
+
+OUString SAL_CALL ScaPricingAddIn::getDisplayCategoryName(
+ const OUString& aProgrammaticName )
+{
+ return getProgrammaticCategoryName( aProgrammaticName );
+}
+
+// XCompatibilityNames
+uno::Sequence< sheet::LocalizedName > SAL_CALL ScaPricingAddIn::getCompatibilityNames(
+ const OUString& aProgrammaticName )
+{
+ auto fDataIt = std::find_if( pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt == pFuncDataList->end() )
+ return uno::Sequence< sheet::LocalizedName >( 0 );
+
+ const std::vector<OUString>& rStrList = fDataIt->GetCompNameList();
+ sal_uInt32 nCount = rStrList.size();
+
+ uno::Sequence< sheet::LocalizedName > aRet( nCount );
+ sheet::LocalizedName* pArray = aRet.getArray();
+
+ for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
+ pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), rStrList[nIndex] );
+
+ return aRet;
+}
+
+// actual function implementation starts here
+// auxiliary input handling functions
+namespace {
+
+bool getinput_putcall(bs::types::PutCall& pc, std::u16string_view str) {
+ if(o3tl::starts_with(str, u"c")) {
+ pc=bs::types::Call;
+ } else if(o3tl::starts_with(str, u"p")) {
+ pc=bs::types::Put;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool getinput_putcall(bs::types::PutCall& pc, const uno::Any& anyval) {
+ OUString str;
+ if(anyval.getValueTypeClass() == uno::TypeClass_STRING) {
+ anyval >>= str;
+ } else if(anyval.getValueTypeClass() == uno::TypeClass_VOID) {
+ str="c"; // call as default
+ } else {
+ return false;
+ }
+ return getinput_putcall(pc, str);
+}
+
+bool getinput_strike(double& strike, const uno::Any& anyval) {
+ if(anyval.getValueTypeClass() == uno::TypeClass_DOUBLE) {
+ anyval >>= strike;
+ } else if(anyval.getValueTypeClass() == uno::TypeClass_VOID) {
+ strike=-1.0; // -1 as default (means not set)
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool getinput_inout(bs::types::BarrierKIO& kio, std::u16string_view str) {
+ if(o3tl::starts_with(str, u"i")) {
+ kio=bs::types::KnockIn;
+ } else if(o3tl::starts_with(str, u"o")) {
+ kio=bs::types::KnockOut;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool getinput_barrier(bs::types::BarrierActive& cont, std::u16string_view str) {
+ if(o3tl::starts_with(str, u"c")) {
+ cont=bs::types::Continuous;
+ } else if(o3tl::starts_with(str, u"e")) {
+ cont=bs::types::Maturity;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool getinput_fordom(bs::types::ForDom& fd, std::u16string_view str) {
+ if(o3tl::starts_with(str, u"f")) {
+ fd=bs::types::Foreign;
+ } else if(o3tl::starts_with(str, u"d")) {
+ fd=bs::types::Domestic;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool getinput_greek(bs::types::Greeks& greek, const uno::Any& anyval) {
+ OUString str;
+ if(anyval.getValueTypeClass() == uno::TypeClass_STRING) {
+ anyval >>= str;
+ } else if(anyval.getValueTypeClass() == uno::TypeClass_VOID) {
+ str="value";
+ } else {
+ return false;
+ }
+
+ if(str == "value" || str == "price" || str == "v" || str == "p") {
+ greek=bs::types::Value;
+ } else if(str == "delta" || str == "d") {
+ greek=bs::types::Delta;
+ } else if(str == "gamma" || str == "g") {
+ greek=bs::types::Gamma;
+ } else if(str == "theta" || str == "t") {
+ greek=bs::types::Theta;
+ } else if(str == "vega" || str == "e") {
+ greek=bs::types::Vega;
+ } else if(str == "volga" || str == "o") {
+ greek=bs::types::Volga;
+ } else if(str == "vanna" || str == "a") {
+ greek=bs::types::Vanna;
+ } else if(str == "rho" || str == "r") {
+ greek=bs::types::Rho_d;
+ } else if(str == "rhof" || str == "f") {
+ greek=bs::types::Rho_f;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+} // namespace for auxiliary functions
+
+// OPT_BARRIER(...)
+double SAL_CALL ScaPricingAddIn::getOptBarrier( double spot, double vol,
+ double r, double rf, double T, double strike,
+ double barrier_low, double barrier_up, double rebate,
+ const OUString& put_call, const OUString& in_out,
+ const OUString& barriercont, const uno::Any& greekstr )
+{
+ bs::types::PutCall pc;
+ bs::types::BarrierKIO kio;
+ bs::types::BarrierActive bcont;
+ bs::types::Greeks greek;
+ // read and check input values
+ if( spot<=0.0 || vol<=0.0 || T<0.0 || strike<0.0 ||
+ !getinput_putcall(pc,put_call) ||
+ !getinput_inout(kio,in_out) ||
+ !getinput_barrier(bcont,barriercont) ||
+ !getinput_greek(greek,greekstr) ){
+ throw lang::IllegalArgumentException();
+ }
+
+ double fRet=bs::barrier(spot,vol,r,rf,T,strike, barrier_low,barrier_up,
+ rebate,pc,kio,bcont,greek);
+
+ RETURN_FINITE( fRet );
+}
+
+// OPT_TOUCH(...)
+double SAL_CALL ScaPricingAddIn::getOptTouch( double spot, double vol,
+ double r, double rf, double T,
+ double barrier_low, double barrier_up,
+ const OUString& for_dom, const OUString& in_out,
+ const OUString& barriercont, const uno::Any& greekstr )
+{
+ bs::types::ForDom fd;
+ bs::types::BarrierKIO kio;
+ bs::types::BarrierActive bcont;
+ bs::types::Greeks greek;
+ // read and check input values
+ if( spot<=0.0 || vol<=0.0 || T<0.0 ||
+ !getinput_fordom(fd,for_dom) ||
+ !getinput_inout(kio,in_out) ||
+ !getinput_barrier(bcont,barriercont) ||
+ !getinput_greek(greek,greekstr) ){
+ throw lang::IllegalArgumentException();
+ }
+
+ double fRet=bs::touch(spot,vol,r,rf,T,barrier_low,barrier_up,
+ fd,kio,bcont,greek);
+
+ RETURN_FINITE( fRet );
+}
+
+// OPT_PRB_HIT(...)
+double SAL_CALL ScaPricingAddIn::getOptProbHit( double spot, double vol,
+ double mu, double T,
+ double barrier_low, double barrier_up )
+{
+ // read and check input values
+ if( spot<=0.0 || vol<=0.0 || T<0.0 ) {
+ throw lang::IllegalArgumentException();
+ }
+
+ double fRet=bs::prob_hit(spot,vol,mu,T,barrier_low,barrier_up);
+
+ RETURN_FINITE( fRet );
+}
+
+// OPT_PROB_INMONEY(...)
+double SAL_CALL ScaPricingAddIn::getOptProbInMoney( double spot, double vol,
+ double mu, double T,
+ double barrier_low, double barrier_up,
+ const uno::Any& strikeval, const uno::Any& put_call )
+{
+ bs::types::PutCall pc=bs::types::Call;
+ double K = 0;
+
+ // read and check input values
+ if( spot<=0.0 || vol<=0.0 || T<0.0 ||
+ !getinput_putcall(pc,put_call) ||
+ !getinput_strike(K,strikeval) ) {
+ throw lang::IllegalArgumentException();
+ }
+
+ double fRet=bs::prob_in_money(spot,vol,mu,T,K,barrier_low,barrier_up,pc);
+
+ RETURN_FINITE( fRet );
+}
+
+OUString ScaPricingAddIn::ScaResId(TranslateId aResId)
+{
+ return Translate::get(aResId, aResLocale);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/pricing/pricing.hxx b/scaddins/source/pricing/pricing.hxx
new file mode 100644
index 000000000..6c6ad7d1d
--- /dev/null
+++ b/scaddins/source/pricing/pricing.hxx
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// option pricing functions add in
+
+// most parts of this files are technical UNO details which are
+// all copied from ../datefunc/datefunc.hxx
+// to avoid having to rename all classes to do with UNO
+// technicalities we use our own namespace
+
+#pragma once
+
+
+#include <vector>
+#include <memory>
+#include <com/sun/star/lang/XServiceName.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sheet/XAddIn.hpp>
+#include <com/sun/star/sheet/XCompatibilityNames.hpp>
+#include <com/sun/star/sheet/addin/XPricingFunctions.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <unotools/resmgr.hxx>
+
+namespace com::sun::star::lang { class XMultiServiceFactory; }
+
+#define RETURN_FINITE(d) if( !std::isfinite( d ) ) throw css::lang::IllegalArgumentException(); return d;
+
+
+namespace sca::pricing {
+
+enum class ScaCategory
+{
+ DateTime,
+ Text,
+ Finance,
+ Inf,
+ Math,
+ Tech
+};
+
+struct ScaFuncDataBase
+{
+ const char* pIntName; // internal name (get***)
+ TranslateId pUINameID; // resource ID to UI name
+ const TranslateId* pDescrID; // resource ID to description, parameter names and ~ description
+ // pCompName was originally meant to be able to load Excel documents that for
+ // some time were stored with localized function names.
+ // This is not relevant to this add-in, so we only supply the
+ // English function name.
+ // see also: GetExcelName() or GetCompNames() or getCompatibilityNames()
+ const char* pCompName;
+ sal_uInt16 nParamCount; // number of named / described parameters
+ ScaCategory eCat; // function category
+ bool bDouble; // name already exist in Calc
+ bool bWithOpt; // first parameter is internal
+};
+
+class ScaFuncData final
+{
+private:
+ OUString aIntName; // internal name (get***)
+ TranslateId pUINameID; // resource ID to UI name
+ const TranslateId* pDescrID; // leads also to parameter descriptions!
+ sal_uInt16 nParamCount; // num of parameters
+ std::vector<OUString> aCompList; // list of all valid names
+ ScaCategory eCat; // function category
+ bool bDouble; // name already exist in Calc
+ bool bWithOpt; // first parameter is internal
+
+public:
+ ScaFuncData(const ScaFuncDataBase& rBaseData);
+
+ const TranslateId& GetUINameID() const { return pUINameID; }
+ const TranslateId* GetDescrID() const { return pDescrID; }
+ ScaCategory GetCategory() const { return eCat; }
+ bool IsDouble() const { return bDouble; }
+
+ sal_uInt16 GetStrIndex( sal_uInt16 nParam ) const;
+ bool Is( std::u16string_view rCompare ) const
+ { return aIntName == rCompare; }
+
+ const std::vector<OUString>& GetCompNameList() const { return aCompList; }
+};
+
+
+typedef std::vector<ScaFuncData> ScaFuncDataList;
+
+void InitScaFuncDataList(ScaFuncDataList& rMap);
+
+// Predicate for use with std::find_if
+struct FindScaFuncData
+{
+ const OUString& m_rId;
+ explicit FindScaFuncData( const OUString& rId ) : m_rId(rId) {}
+ bool operator() ( ScaFuncData const & rCandidate ) const { return rCandidate.Is(m_rId); }
+};
+
+} // namespace sca::pricing
+
+
+// AddIn class for pricing functions
+
+class ScaPricingAddIn : public ::cppu::WeakImplHelper<
+ css::sheet::XAddIn,
+ css::sheet::XCompatibilityNames,
+ css::sheet::addin::XPricingFunctions,
+ css::lang::XServiceName,
+ css::lang::XServiceInfo >
+{
+private:
+ css::lang::Locale aFuncLoc;
+ std::unique_ptr<css::lang::Locale[]> pDefLocales;
+ std::locale aResLocale;
+ std::unique_ptr<sca::pricing::ScaFuncDataList> pFuncDataList;
+
+
+ void InitDefLocales();
+ const css::lang::Locale& GetLocale( sal_uInt32 nIndex );
+ void InitData();
+
+ /// @throws css::uno::RuntimeException
+ OUString GetFuncDescrStr(const TranslateId* pResId, sal_uInt16 nStrIndex);
+
+public:
+ ScaPricingAddIn();
+ virtual ~ScaPricingAddIn() override;
+
+ OUString ScaResId(TranslateId aResId);
+
+ // XAddIn
+ virtual OUString SAL_CALL getProgrammaticFuntionName( const OUString& aDisplayName ) override;
+ virtual OUString SAL_CALL getDisplayFunctionName( const OUString& aProgrammaticName ) override;
+ virtual OUString SAL_CALL getFunctionDescription( const OUString& aProgrammaticName ) override;
+ virtual OUString SAL_CALL getDisplayArgumentName( const OUString& aProgrammaticName, sal_Int32 nArgument ) override;
+ virtual OUString SAL_CALL getArgumentDescription( const OUString& aProgrammaticName, sal_Int32 nArgument ) override;
+ virtual OUString SAL_CALL getProgrammaticCategoryName( const OUString& aProgrammaticName ) override;
+ virtual OUString SAL_CALL getDisplayCategoryName( const OUString& aProgrammaticName ) override;
+
+ // XCompatibilityNames
+ virtual css::uno::Sequence< css::sheet::LocalizedName > SAL_CALL getCompatibilityNames( const OUString& aProgrammaticName ) override;
+
+ // XLocalizable
+ virtual void SAL_CALL setLocale( const css::lang::Locale& eLocale ) override;
+ virtual css::lang::Locale SAL_CALL getLocale() override;
+
+ // XServiceName
+ virtual OUString SAL_CALL getServiceName() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+
+ // methods from own interfaces start here
+
+
+ virtual double SAL_CALL getOptBarrier( double spot, double vol,
+ double r, double rf, double T, double strike,
+ double barrier_low, double barrier_up, double rebate,
+ const OUString& put_call, const OUString& in_out,
+ const OUString& continuous, const css::uno::Any& greek ) override;
+
+ virtual double SAL_CALL getOptTouch( double spot, double vol,
+ double r, double rf, double T,
+ double barrier_low, double barrier_up,
+ const OUString& for_dom, const OUString& in_out,
+ const OUString& barriercont, const css::uno::Any& greekstr ) override;
+
+ virtual double SAL_CALL getOptProbHit( double spot, double vol,
+ double mu, double T,
+ double barrier_low, double barrier_up ) override;
+
+ virtual double SAL_CALL getOptProbInMoney( double spot, double vol,
+ double mu, double T,
+ double barrier_low, double barrier_up,
+ const css::uno::Any& strikeval, const css::uno::Any& put_call ) override;
+
+};
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */