java调用Excel中的GAMMADIST函数返回伽玛分布

java调用Excel中的GAMMADIST函数返回伽玛分布
一、问题描述:想用java调用Excel中的GAMMADIST 函数。
Microsoft office Excel中用法说明如下:https://support.microsoft.com/zh-cn/office/gammadist-%E5%87%BD%E6%95%B0-7327c94d-0f05-4511-83df-1dd7ed23e19e?ui=zh-cn&rs=zh-cn&ad=cn
WPS Excel中用法说明如下:https://www.wps.cn/learning/room/d/328021

二、尝试网上找的vb版GammaDist()和GammaInv()两函数的代码转java
1、从matlab里翻译过来的vb版GammaDist()和GammaInv()两函数的代码如下:

vb版GammaDist()和GammaInv()两函数的代码

http://wenku.baidu.com/link?url=uHtUUETc8q1HAlSV7ChTHRg0SLrBKApRKC-BLFnHHoviqv3G4r4DY8ONIWi_5fKN6DuBURHhAkOfJvGNJg7mFyjjERKRoeWASkFTmK3yvXa从matlab里翻译过来的
 
GammaDist(x,a,b,true):  
'%GAMCDF Gamma cumulative distribution function. 
'%   P = GAMCDF(X,A,B) returns the gamma cumulative distribution 
'%   function with parameters A and B at the values in X. 
 
Public Function GamCdf(x, a, b)  
  
'对应excel中GammaDist(x,a,b,true)函数,
计算S曲线 
  
If a <= 0 Or b <= 0 Then GammCdf = "NaN"   
GamCdf = GAMMAINC(x / b, a)   
p = IIf(p > 1, 1, p) 
End Function 
 
'%GAMMAINC Incomplete gamma function. 
'%   Y = GAMMAINC(X,A) evaluates the incomplete gamma function for 
'%   corresponding elements of X and A.  X and A must be real and the same 
'%   size (or either can be a scalar).  A must also be non-negative. 
'%   The incomplete gamma function is defined as: 
'%gammainc(x,a) = 1 ./ gamma(a) .* 
'%  integral from 0 to x of t^(a-1) exp(-t) dt 
'% '%   For any a>=0, as x approaches infinity, gammainc(x,a) approaches 1. 
'%   For small x and a, gammainc(x,a) ~= x^a, so gammainc(0,0) = 1. 
Public Function GAMMAINC(x, a) 
Dim amax As Double  
  amax = 2 ^ 20 
 ascalar = 1 
   
If a <= amax Then 
        If a <> 0 And x <> 0 And x < a + 1 Then 
 xk = x 
 ak = a 
 ap = ak 
 Sum = 1 / ap 
 del = Sum 
   Dim i As Double 
  
 For i = 1 To 10000 
  ap = ap + 1 
  del = xk * del / ap 
  Sum = Sum + del 
   Next 
GAMMAINC = Sum * Exp(-xk + ak * Log(xk) - GAMMALN(ak)) 
     ElseIf a <> 0 And x <> 0 And x >= a + 1 Then 
 
 xk = x   
 a0 = 1   
 a1 = x   
 b0 = 0   
 b1 = a0   
 ak = a   
 fac = 1   
 n = 1   
 g = b1   
 gold = b0  
 For i = 1 To 10000   
gold = g   
ana = n - ak   
a0 = (a1 + a0 * ana) * fac      
b0 = (b1 + b0 * ana) * fac 
  anf = n * fac   
a1 = xk * a0 + anf * a1 
b1 = xk * b0 + anf * b1 
fac = 1 / a1 
g = b1 * fac 
n = n + 1 
 Next 
 GAMMAINC = 1 - Exp(-xk + ak * Log(xk) - GAMMALN(ak)) * g  
   End If 
Else 
End If  
End Function 
 
'*****************************************************************************************************
************** 
'%GAMMALN Logarithm of gamma function. 
'%  
 Y = GAMMALN(X) computes the natural logarithm of the gamma 
'%   function for each element of X.  GAMMALN is defined as 
'% '%  LOG(GAMMA(X)) 
'% '%   and is obtained without computing GAMMA(X).  Since the gamma 
'%   function can range over very large or very small values, its 
'%   logarithm is sometimes more useful.  http://zanjero.ygblog.com/
 
Public Function GAMMALN(XX) 
Dim COF(6) As Double, stp As Double, half As Double, one As Double 
Dim fpf As Double, x As Double, tmp As Double, ser As Double 
Dim j As Integer 
COF(1) = 76.18009173 
COF(2) = -86.50532033 
COF(3) = 24.01409822 
COF(4) = -1.231739516 
COF(5) = 0.00120858003 
COF(6) = -0.00000536382 
stp = 2.50662827465 
half = 0.5 
one = 1# 
fpf = 5.5 
x = XX - one 
tmp = x + fpf 
tmp = (x + half) * Log(tmp) - tmp 
ser = one 
For j = 1 To 6 
   x = x + one 
   ser = ser + COF(j) / x 
Next j   
GAMMALN = tmp + Log(stp * ser) 
End Function 
 
GammaInv:(要调用上面的GamCdf和GAMMALN函数) 
'%GAMINV Inverse of the gamma cumulative distribution function (cdf). 
'%   X = GAMINV(P,A,B)  returns the inverse of the gamma cdf with 
'%   parameters A and B, at the probabilities in P对应Excel中GammaInv(p,a,b)函数,计算PⅢ的Φp值Φp=Cs/2*GammaInv(1-p/100,4/Cs^2,1)-2/Cs 
Public Function gaminv(p, a, b) 
  If p < 0 Or p > 1 Or a <= 0 Or b <= 0 Then 
     gaminv = "NaN" 
     Exit Function 
 Else
Select Case p 
     Case 0 
 gaminv = 0 
     Case 1     
 gaminv = 1 
   Case Else 
 '% Newton's Method 
 '% Permit no more than count_limit interations. 
 count_limit = 100 
   cunt = 0 
 pk = p 
 '% Supply a starting guess for the iteration. 
 '%   Use a method of moments fit to the lognormal distribution. 
 mn = a * b 
 v = mn * b 
 temp = Log(v + mn ^ 2) 
 mu = 2 * Log(mn) - 0.5 * temp 
 sigma = -2 * Log(mn) + temp 
 xk = Exp(MyNormInv(pk, mu, sigma))  
''''''''''''''''''''''' 
  h = 1 
 '% Break out of the iteration loop for three reasons: 
 '%  1) the last update is very small (compared to x) 
 '%  2) the last update is very small (compared to sqrt(eps)) 
 '%  3) There are more than 100 iterations. This should NEVER happen. 
 eps = 2 ^ -10 
 Do While Abs(h) > eps ^ 0.5 * Abs(xk) And Abs(h) > eps ^ 0.5 And cunt < count_limit 
 cunt = tunt + 1 
  h = (GamCdf(xk, a, b) - pk) / gampdf(xk, a, b)  
''''''''''''' 
xnew = xk - h 
% Make sure that the current guess stays greater than zero. 
% When Newton's Method suggests steps that lead to negative guesses 
% take a step 9/10ths of the way to zero: 
If xnew < 0 Then 
   xnew = xk / 10 
   h = xk - xnew 
End If 
xk = xnew 
 Loop 
 gaminv = xk 
   End Select 
End If  
End Function 
 
 
' This function is a replacement for the Microsoft Excel Worksheet function NORMSINV. 
' It uses the algorithm of Peter J. Acklam to compute the inverse normal cumulative 
' distribution. Refer to 
http://home.online.no/~pjacklam/notes/invnorm/index.html
 for 
' a description of the algorithm.  
' Adapted to VB by Christian d'Heureuse, 
http://zanjero.ygblog.com/.
 
Public Function MyNormSInv(ByVal p As Double)  
  '
计算频率格纸
 
Const a1 = -39.6968302866538, a2 = 220.946098424521, a3 = -275.928510446969 
Const a4 = 138.357751867269, a5 = -30.6647980661472, a6 = 2.50662827745924 
Const b1 = -54.4760987982241, b2 = 161.585836858041, b3 = -155.698979859887 
Const b4 = 66.8013118877197, b5 = -13.2806815528857, c1 = -7.78489400243029E-03 
Const c2 = -0.322396458041136, c3 = -2.40075827716184, c4 = -2.54973253934373 
Const c5 = 4.37466414146497, c6 = 2.93816398269878, d1 = 7.78469570904146E-03 
Const d2 = 0.32246712907004, d3 = 2.445134137143, d4 = 3.75440866190742 
Const p_low = 0.02425, p_high = 1 - p_low 
Dim q As Double, r As Double 
  
  
If p < 0 Or p > 1 Then 
  
   
   Err.Raise vbObjectError, , "NormSInv: Argument out of range." 
  
  
ElseIf p < p_low Then 
  
   
   q = Sqr(-2 * Log(p)) 
  
   
   MyNormSInv = (((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / _ 
  
   
   
   
   
  
((((d1 * q + d2) * q + d3) * q + d4) * q + 1) 
  
  
ElseIf p <= p_high Then 
  
   
   q = p - 0.5: r = q * q 
  
   
   MyNormSInv = (((((a1 * r + a2) * r + a3) * r + a4) * r + a5) * r + a6) * q / _ 
  
   
   
   
   
  
(((((b1 * r + b2) * r + b3) * r + b4) * r + b5) * r + 1) 
  
  
Else 
  
   
   q = Sqr(-2 * Log(1 - p)) 
  
   
   MyNormSInv = -(((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / _ 
  
   
   
   
   
  
((((d1 * q + d2) * q + d3) * q + d4) * q + 1) 
  
  
End If 
End Function 
 
 
'%GAMPDF Gamma probability density function. 
'%  
 Y = GAMPDF(X,A,B) returns the gamma probability density function 
'%  
 with parameters A and B, at the values in X. 
http://zanjero.ygblog.com/
 
Public Function gampdf(x, a, b) 
  y = 0 
  If x = 0 And a < 1 Then   
gampdf = "∞"
   Exit Function 
End If 
If x = 0 And a = 1 Then 
   gampdf = 1 / b 
   Exit Function 
End If 
If a <= 0 Or b <= 0 Then 
   y = "NaN" 
   gampdf = y 
   Exit Function 
ElseIf x > 0 Then 
   y = (a - 1) * Log(x) - x / b - GAMMALN(a) - a * Log(b) 
   y = Exp(y) 
End If 
gampdf = y 
End Function

https://wenku.baidu.com/link?url=uHtUUETc8q1HAlSV7ChTHRg0SLrBKApRKC-BLFnHHoviqv3G4r4DY8ONIWi_5fKN6DuBURHhAkOfJvGNJg7mFyjjERKRoeWASkFTmK3yvXa&_wkts_=1667896077426
https://bbs.co188.com/thread-1169888-1-1.html
2、转成java后代码如下:

import static java.lang.Double.NEGATIVE_INFINITY; //无穷小
import static java.lang.Double.POSITIVE_INFINITY; //无穷大
import static java.lang.Math.*;


public class GammaDist {

    //对应excel中GammaDist(x,a,b,true)函数,
    public GammaDist(double x,double a,double b, boolean flag){
        if(flag){
            double p = GamCdf(x,a,b);
            if(p>1)
                p=1;
            else
                p=p;
            System.out.println (p);
        }
    }
    //%GAMCDF Gamma cumulative distribution function.
    //% P = GAMCDF(X,A,B) returns the gamma cumulative distribution
    //% function with parameters A and B at the values in X.
    public double GamCdf(double x, double a, double b) { //对应excel中GammaDist(x,a,b,true)函数,计算S曲线
        double GamCdf = NEGATIVE_INFINITY; //无穷小
        if(a<=0 || b<=0) GamCdf = NEGATIVE_INFINITY; //无穷小
        GamCdf = GAMMAINC(x / b, a);
        double p = GamCdf;
        if(p>1)
            p=1;
        else
            p=p;
        return GamCdf;
    }
             
    //%GAMMAINC Incomplete gamma function.
    //% Y = GAMMAINC(X,A) evaluates the incomplete gamma function for
    //% corresponding elements of X and A.X and A must be real and the same
    //% size (or either can be a scalar).A must also be non-negative.
    //% The incomplete gamma function is defined as: http://zanjero.ygblog.com
    //%gammainc(x,a) = 1 ./ gamma(a) .*
    //%integral from 0 to x of t^(a-1) exp(-t) dt
    //% For any a>=0, as x approaches infinity, gammainc(x,a) approaches 1.
    //% For small x and a, gammainc(x,a) ~= x^a, so gammainc(0,0) = 1.
    public double GAMMAINC(double x, double a) {
        double amax;
        amax = Math.pow(2,20);
        int ascalar = 1;
        double GAMMAINC = 0.0;

        if(a <=amax) {
            if (a != 0 && x != 0 && x < a + 1) {
                double xk = x;
                double ak = a;
                double ap = ak;
                double Sum = 1 / ap;
                double del = Sum;
                for (int i = 0; i < 10000; i++) {
                    ap = ap + 1;
                    del = xk * del / ap;
                    Sum = Sum + del;
                }
                GAMMAINC = Sum * exp(-xk + ak * log(xk) - GAMMALN(ak));
            }
            else if (a != 0 && x != 0 && x >= a + 1) {
                double xk = x;
                double a0 = 1;
                double a1 = x;
                double b0 = 0;
                double b1 = a0;
                double ak = a;
                double fac = 1;
                double n = 1;
                double g = b1;
                double gold = b0;
                for (int i = 0; i < 10000; i++) {
                    gold = g;
                    double ana = n - ak;
                    a0 = (a1 + a0 * ana) * fac;
                    b0 = (b1 + b0 * ana) * fac;
                    double anf = n * fac;
                    a1 = xk * a0 + anf * a1;
                    b1 = xk * b0 + anf * b1;
                    fac = 1 / a1;
                    g = b1 * fac;
                    n = n + 1;
                }
                GAMMAINC = 1 - exp(-xk + ak * log(xk) - GAMMALN(ak)) * g;
            }
        }
        return GAMMAINC;
    }
             
    //'*****************************************************************************************************
    //**************
    //%GAMMALN Logarithm of gamma function.
    //%Y = GAMMALN(X) computes the natural logarithm of the gamma
    //% function for each element of X.GAMMALN is defined as
    //% '%LOG(GAMMA(X))
    //% '% and is obtained without computing GAMMA(X).Since the gamma
    //% function can range over very large or very small values, its
    //% logarithm is sometimes more useful.http://zanjero.ygblog.com/
    public double GAMMALN( double XX) {
        double[] COF = new double[6];
        double stp, half, one;
        double fpf, x, tmp, ser;
        COF[0] = 76.18009173;
        COF[1] = -86.50532033;
        COF[2] = 24.01409822;
        COF[3] = -1.231739516;
        COF[4] = 0.00120858003;
        COF[5] = -0.00000536382;
        stp = 2.50662827465;
        half = 0.5;
        one = 1;
        fpf = 5.5;
        x = XX - one;
        tmp = x + fpf;
        tmp = (x + half) * log(tmp) - tmp;
        ser = one;
        for(int j=0;j<6;j++) {
            x = x + one;
            ser = ser + COF[j] / x;
        }
        double GAMMALN = tmp + log(stp * ser);
        return GAMMALN;
    }
             
    //GammaInv:(要调用上面的GamCdf和GAMMALN函数)
    //%GAMINV Inverse of the gamma cumulative distribution function (cdf).
    //% X = GAMINV(P,A,B)returns the inverse of the gamma cdf with
    //% parameters A and B, at the probabilities in P. http://zanjero.ygblog.com/
    //% 对应Excel中GammaInv(p,a,b)函数,计算PⅢ的Φp值Φp=Cs/2*GammaInv(1-p/100,4/Cs^2,1)-2/Cs
    public double gaminv(double p, double a, double b) {
        double gaminv = NEGATIVE_INFINITY;//无穷小
        if(p <0 || p >1 || a <= 0 || b <= 0) {
            gaminv = NEGATIVE_INFINITY;//无穷小
            return gaminv;
        }
        else {
            if(p==0){
                gaminv = 0;
            }
            else if(p==1){
                gaminv = 1;
            }
            else {
                //% Newton' s Method
                //% Permit no more than count_limit interations.
                int count_limit = 100;
                int cunt = 0;
                double pk = p;
                //% Supply a starting guess for the iteration.
                //% Use a method of moments fit to the lognormal distribution.
                double mn = a * b;
                double v = mn * b;
                double temp = log(v + Math.pow(mn,2));
                double mu = 2 * log(mn) - 0.5 * temp;
                double sigma = -2 * log(mn) + temp;
                double xk = exp(MyNormInv(pk, mu, sigma));
                //'' '' '' '' '' '' '' '' '' '' '' '
                double h = 1;
                //% Break out of the iteration loop for three reasons:
                //%1) the last update is very small (compared to x)
                //%2) the last update is very small (compared to sqrt(eps))
                //%3) There are more than 100 iterations. This should NEVER happen.
                double eps = Math.pow(2,-10);
                while((abs(h) > Math.pow(eps,0.5) * abs(xk)) && (abs (h) > Math.pow(eps,0.5)) && (cunt <count_limit)){
                    cunt = tunt + 1;
                    h = (GamCdf(xk, a, b) - pk) / gampdf(xk, a, b);
                    //'' '' '' '' '' '' '
                    double xnew = xk - h;
                    //% Make sure that the current guess stays greater than zero.
                    //% When Newton 's Method suggests steps that lead to negative guesses
                    //% take a step 9 / 10 ths of the way to zero:
                    if(xnew <0) {
                        xnew = xk / 10;
                        h = xk - xnew;
                    }
                    xk = xnew;
                }
                gaminv = xk;
            }
        }
    }
             
             
    //This function is a replacement for the Microsoft Excel Worksheet function NORMSINV.
    //It uses the algorithm of Peter J. Acklam to compute the inverse normal cumulative
    //distribution. Refer to http://home.online.no/~pjacklam/notes/invnorm/index.html for
    // a description of the algorithm.
    // Adapted to VB by Christian d'Heureuse, http://zanjero.ygblog.com/.
    public double MyNormSInv( double p) {
        //计算频率格纸
        double a1 = -39.6968302866538, a2 = 220.946098424521, a3 = -275.928510446969;
        double a4 = 138.357751867269, a5 = -30.6647980661472, a6 = 2.50662827745924;
        double b1 = -54.4760987982241, b2 = 161.585836858041, b3 = -155.698979859887;
        double b4 = 66.8013118877197, b5 = -13.2806815528857, c1 = -7.78489400243029E-03;
        double c2 = -0.322396458041136, c3 = -2.40075827716184, c4 = -2.54973253934373;
        double c5 = 4.37466414146497, c6 = 2.93816398269878, d1 = 7.78469570904146E-03;
        double d2 = 0.32246712907004, d3 = 2.445134137143, d4 = 3.75440866190742;
        double p_low = 0.02425, p_high = 1 - p_low;
        double q, r, MyNormSInv = NEGATIVE_INFINITY;//无穷小;
        if (p <0 || p >1) {
            System.out.println ("NormSInv: Argument out of range.");
        }
        else if( p <p_low){
            q = sqrt(-2 * log(p));
            MyNormSInv = (((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / ((((d1 * q + d2) * q + d3) * q + d4) * q + 1);
        }
        else if(p <=p_high) {
            q = p - 0.5;
            r = q * q;
            MyNormSInv = (((((a1 * r + a2) * r + a3) * r + a4) * r + a5) * r + a6) * q / (((((b1 * r + b2) * r + b3) * r + b4) * r + b5) * r + 1);
        }
        else {
            q = sqrt(-2 * log(1 - p));
            MyNormSInv = -(((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / ((((d1 * q + d2) * q + d3) * q + d4) * q + 1);
        }
        return MyNormSInv;
    }
             
    //GAMPDF Gamma probability density function.
    /*
      Y = GAMPDF(X,A,B) returns the gamma probability density function
          with parameters A and B, at the values in X.
          http://zanjero.ygblog.com/
    */
    public double gampdf(double x, double a, double b){
        double y = 0.0;
        double gampdf = NEGATIVE_INFINITY;//无穷小
        if(x == 0 && a < 1){
            gampdf = POSITIVE_INFINITY;//无穷大
            return gampdf;
        }
        if((x==0)&&(a==1)){
            gampdf = 1 / b;
            return gampdf;
        }
        if(a <= 0 || b <= 0) {
            y = NEGATIVE_INFINITY;//无穷小
            gampdf = y;
        }
        else if (x > 0) {
            y = (a - 1) * log(x) - x / b - GAMMALN(a) - a * log(b);
            y = exp(y);
        }
        gampdf = y;
        return gampdf;
    }

}

3、结论,转换未成功,函数MyNormInv和变量tunt未找到,有知道的请留言告知。

三、最后使用org.apache.commons.math3.distribution.GammaDistribution类中的方法成功。参考地址:https://vimsky.com/examples/detail/java-class-org.apache.commons.math3.distribution.GammaDistribution.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值