1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: interpr6.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 #include <tools/debug.hxx>
37 #include <rtl/logfile.hxx>
38 #include "interpre.hxx"
40 double const fHalfMachEps
= 0.5 * ::std::numeric_limits
<double>::epsilon();
42 // The idea how this group of gamma functions is calculated, is
43 // based on the Cephes library
44 // online http://www.moshier.net/#Cephes [called 2008-02]
46 /** You must ensure fA>0.0 && fX>0.0
47 valid results only if fX > fA+1.0
48 uses continued fraction with odd items */
49 double ScInterpreter::GetGammaContFraction( double fA
, double fX
)
51 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetGammaContFraction" );
53 double const fBigInv
= ::std::numeric_limits
<double>::epsilon();
54 double const fBig
= 1.0/fBigInv
;
56 double fNum
= 0.0; // dummy value
58 double fDenom
= fX
+ 2.0-fA
;
59 double fPk
= 0.0; // dummy value
60 double fPkm1
= fX
+ 1.0;
62 double fQk
= 1.0; // dummy value
63 double fQkm1
= fDenom
* fX
;
65 double fApprox
= fPkm1
/fQkm1
;
66 bool bFinished
= false;
67 double fR
= 0.0; // dummy value
74 fPk
= fPkm1
* fDenom
- fPkm2
* fNum
;
75 fQk
= fQkm1
* fDenom
- fQkm2
* fNum
;
79 bFinished
= (fabs( (fApprox
- fR
)/fR
) <= fHalfMachEps
);
88 // reduce a fraction does not change the value
89 fPkm2
= fPkm2
* fBigInv
;
90 fPkm1
= fPkm1
* fBigInv
;
91 fQkm2
= fQkm2
* fBigInv
;
92 fQkm1
= fQkm1
* fBigInv
;
94 } while (!bFinished
&& fCount
<10000);
95 // most iterations, if fX==fAlpha+1.0; approx sqrt(fAlpha) iterations then
98 SetError(errNoConvergence
);
103 /** You must ensure fA>0.0 && fX>0.0
104 valid results only if fX <= fA+1.0
106 double ScInterpreter::GetGammaSeries( double fA
, double fX
)
108 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetGammaSeries" );
109 double fDenomfactor
= fA
;
110 double fSummand
= 1.0/fA
;
111 double fSum
= fSummand
;
115 fDenomfactor
= fDenomfactor
+ 1.0;
116 fSummand
= fSummand
* fX
/fDenomfactor
;
117 fSum
= fSum
+ fSummand
;
119 } while ( fSummand
/fSum
> fHalfMachEps
&& nCount
<=10000);
120 // large amount of iterations will be carried out for huge fAlpha, even
121 // if fX <= fAlpha+1.0
124 SetError(errNoConvergence
);
129 /** You must ensure fA>0.0 && fX>0.0) */
130 double ScInterpreter::GetLowRegIGamma( double fA
, double fX
)
132 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetLowRegIGamma" );
133 double fLnFactor
= fA
* log(fX
) - fX
- GetLogGamma(fA
);
134 double fFactor
= exp(fLnFactor
); // Do we need more accuracy than exp(ln()) has?
135 if (fX
>fA
+1.0) // includes fX>1.0; 1-GetUpRegIGamma, continued fraction
136 return 1.0 - fFactor
* GetGammaContFraction(fA
,fX
);
137 else // fX<=1.0 || fX<=fA+1.0, series
138 return fFactor
* GetGammaSeries(fA
,fX
);
141 /** You must ensure fA>0.0 && fX>0.0) */
142 double ScInterpreter::GetUpRegIGamma( double fA
, double fX
)
144 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetUpRegIGamma" );
146 double fLnFactor
= fA
*log(fX
)-fX
-GetLogGamma(fA
);
147 double fFactor
= exp(fLnFactor
); //Do I need more accuracy than exp(ln()) has?;
148 if (fX
>fA
+1.0) // includes fX>1.0
149 return fFactor
* GetGammaContFraction(fA
,fX
);
150 else //fX<=1 || fX<=fA+1, 1-GetLowRegIGamma, series
151 return 1.0 -fFactor
* GetGammaSeries(fA
,fX
);
154 /** Gamma distribution, probability density function.
155 fLambda is "scale" parameter
156 You must ensure fAlpha>0.0 and fLambda>0.0 */
157 double ScInterpreter::GetGammaDistPDF( double fX
, double fAlpha
, double fLambda
)
159 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetGammaDistPDF" );
161 return 0.0; // see ODFF
164 double fXr
= fX
/ fLambda
;
165 // use exp(ln()) only for large arguments because of less accuracy
168 const double fLogDblMax
= log( ::std::numeric_limits
<double>::max());
169 if (log(fXr
) * (fAlpha
-1.0) < fLogDblMax
&& fAlpha
< fMaxGammaArgument
)
171 return pow( fXr
, fAlpha
-1.0) * exp(-fXr
) / fLambda
/ GetGamma(fAlpha
);
175 return exp( (fAlpha
-1.0) * log(fXr
) - fXr
- log(fLambda
) - GetLogGamma(fAlpha
));
178 else // fXr near to zero
180 if (fAlpha
<fMaxGammaArgument
)
182 return pow( fXr
, fAlpha
-1.0) * exp(-fXr
) / fLambda
/ GetGamma(fAlpha
);
186 return pow( fXr
, fAlpha
-1.0) * exp(-fXr
) / fLambda
/ exp( GetLogGamma(fAlpha
));
192 /** Gamma distribution, cumulative distribution function.
193 fLambda is "scale" parameter
194 You must ensure fAlpha>0.0 and fLambda>0.0 */
195 double ScInterpreter::GetGammaDist( double fX
, double fAlpha
, double fLambda
)
197 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetGammaDist" );
201 return GetLowRegIGamma( fAlpha
, fX
/ fLambda
);