From 1f62afae0fd04236005be70736cf7ab059a10778 Mon Sep 17 00:00:00 2001 From: Albert Thuswaldner Date: Wed, 1 Aug 2012 01:26:25 +0200 Subject: fdo#43135 - fix for MULTINOMIAL only supporting parameters up to 170 Change-Id: I9366de24414fa10e292e42df08a9658d90e5c1c1 --- scaddins/source/analysis/analysis.cxx | 19 ++++++---------- scaddins/source/analysis/analysishelper.cxx | 35 ++++++++++++++++------------- scaddins/source/analysis/analysishelper.hxx | 2 +- 3 files changed, 27 insertions(+), 29 deletions(-) (limited to 'scaddins/source/analysis') diff --git a/scaddins/source/analysis/analysis.cxx b/scaddins/source/analysis/analysis.cxx index 00d5e3d78b8b..ca83361714e8 100644 --- a/scaddins/source/analysis/analysis.cxx +++ b/scaddins/source/analysis/analysis.cxx @@ -689,26 +689,21 @@ AnalysisAddIn::getMultinomial( constREFXPS& xOpt, const SEQSEQ( sal_Int32 )& aVL if( aValList.Count() == 0 ) return 0.0; - sal_Int32 nZ = 0; - double fN = 1.0; + double nZ = 0; + double fRet = 1.0; for( const double *p = aValList.First(); p; p = aValList.Next() ) { - double fInt = (*p >= 0.0) ? rtl::math::approxFloor( *p ) : rtl::math::approxCeil( *p ); - if ( fInt < 0.0 || fInt > 170.0 ) + double n = (*p >= 0.0) ? rtl::math::approxFloor( *p ) : rtl::math::approxCeil( *p ); + if ( n < 0.0 ) THROW_IAE; - sal_Int32 n = static_cast< sal_Int32 >( fInt ); - if( n > 0 ) + + if( n > 0.0 ) { nZ += n; - fN *= Fak( n ); + fRet *= BinomialCoefficient(nZ, n); } } - - if( nZ > 170 ) - THROW_IAE; - - double fRet = Fak( nZ ) / fN; RETURN_FINITE( fRet ); } diff --git a/scaddins/source/analysis/analysishelper.cxx b/scaddins/source/analysis/analysishelper.cxx index 6b4309a6f3c7..56064b56f884 100644 --- a/scaddins/source/analysis/analysishelper.cxx +++ b/scaddins/source/analysis/analysishelper.cxx @@ -521,29 +521,32 @@ double GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDat return double( nYears ) + double( nDayDiff ) / double( nDaysInYear ); } - -double Fak( sal_Int32 n ) +double BinomialCoefficient( double n, double k ) { - if( n > 0 ) - { - double fRet = n; - double f = n - 1; + // This method is a copy of BinomKoeff() + // found in sc/source/core/tool/interpr3.cxx - while( f >= 2.0 ) + 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) { - fRet *= f; - f--; + nVal *= n/k; + k--; + n--; } - - return fRet; } - else if( !n ) - return 1.0; - else - return 0.0; + return nVal; } - double GetGcd( double f1, double f2 ) { double f = fmod( f1, f2 ); diff --git a/scaddins/source/analysis/analysishelper.hxx b/scaddins/source/analysis/analysishelper.hxx index bad6e2124dfe..bbbbfc57f245 100644 --- a/scaddins/source/analysis/analysishelper.hxx +++ b/scaddins/source/analysis/analysishelper.hxx @@ -94,7 +94,7 @@ inline double GetYearFrac( constREFXPS& xOpt, sal_Int32 nStartDate, sal_In THROWDEF_RTE_IAE; inline void AlignDate( sal_uInt16& rDay, sal_uInt16 nMonth, sal_uInt16 nYear ); -double Fak( sal_Int32 n ); +double BinomialCoefficient( double n, double k ); double GetGcd( double f1, double f2 ); double ConvertToDec( const STRING& rFromNum, sal_uInt16 nBaseFrom, sal_uInt16 nCharLim ) THROWDEF_RTE_IAE; STRING ConvertFromDec( -- cgit