In a nonlinear model I needed to use the following expression in a model equation:
y=(xk)pk(1−p)(x−k) |
Here x is the only decision variable. The integer version of “n choose k” is well known:
(nk)=n!k!(n−k)! |
For fractional values we can generalize this to:
(xy)=Γ(x+1)Γ(y+1)Γ(x−y+1) |
where Γ(.) indicates the gamma function, defined by
Γ(z)=∫∞0xz−1e−xdx |
In GAMS we have the binomial(x,y) function for this. The problem is that x can become rather large, while k is a small integer, say k=0,…,4. For some values of x this leads to very inaccurate results and even overflows in subsequent calculations.
E.g.:
scalars |
yields the wrong result:
---- 8 PARAMETER y binomial 1.0000E+299, log 6305.520 |
The logarithmic version is correct.
Instead of using the logarithmic version:
(xk)=exp(logΓ(x+1)−logΓ(k+1)−logΓ(x−k+1)) |
we can also exploit that k is a small integer. From:
Γ(z+1)=zΓ(z) |
we have:
(xk)=x(x−1)⋯(x−k+1)Γ(x−k+1)k!Γ(x−k+1)=x(x−1)⋯(x−k+1)k!=k∏i=1(x−i+1)k! |
In GAMS:
scalars x /112.8/ k /2/ ; parameter y; y("binomial") = binomial(x,k); y("log") = exp(loggamma(x+1)-loggamma(k+1)-loggamma(x-k+1)); set i /1*2/; y("prod") = prod(i,x-i.val+1)/fact(k); display y; |
with results:
---- 10 PARAMETER y binomial 1.0000E+299, log 6305.520, prod 6305.520 |
I used this last “product” version in the model.
Note that the overflow in the binomial function does not happen for all (or even most) large values:
scalars x /1112.8/ k /2/ ; parameter y; y("binomial") = binomial(x,k); y("log") = exp(loggamma(x+1)-loggamma(k+1)-loggamma(x-k+1)); set i /1*2/; y("prod") = prod(i,x-i.val+1)/fact(k); display y; |
gives:
---- 10 PARAMETER y binomial 618605.520, log 618605.520, prod 618605.520 |
No comments:
Post a Comment