File indexing completed on 2024-05-12 17:22:33
0001 /* floatgamma.c: Gamma function, based on floatnum. */ 0002 /* 0003 Copyright (C) 2007, 2008 Wolf Lammen. 0004 0005 This program is free software; you can redistribute it and/or modify 0006 it under the terms of the GNU General Public License as published by 0007 the Free Software Foundation; either version 2 of the License , or 0008 (at your option) any later version. 0009 0010 This program is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 GNU General Public License for more details. 0014 0015 You should have received a copy of the GNU General Public License 0016 along with this program; see the file COPYING. If not, write to: 0017 0018 The Free Software Foundation, Inc. 0019 59 Temple Place, Suite 330 0020 Boston, MA 02111-1307 USA. 0021 0022 0023 You may contact the author by: 0024 e-mail: ookami1 <at> gmx <dot> de 0025 mail: Wolf Lammen 0026 Oertzweg 45 0027 22307 Hamburg 0028 Germany 0029 0030 *************************************************************************/ 0031 0032 #include "floatgamma.h" 0033 #include "floatconst.h" 0034 #include "floatcommon.h" 0035 #include "floatlog.h" 0036 #include "floatexp.h" 0037 #include "floattrig.h" 0038 0039 /* asymptotic series of the Binet function 0040 for x >= 77 and a 100 digit computation, the 0041 relative error is < 9e-100. 0042 the series converges, if x and digits comply to 0043 100 >= digits >= 2 0044 x >= sqrt((digits*ln 10 + 0.5*ln 2)/1.0033). 0045 As a special case, for digits == 1, convergence is guaranteed, 0046 if x >= 1.8. */ 0047 0048 char 0049 binetasymptotic(floatnum x, 0050 int digits) 0051 { 0052 floatstruct recsqr; 0053 floatstruct sum; 0054 floatstruct smd; 0055 floatstruct pwr; 0056 int i, workprec; 0057 0058 if (float_getexponent(x) >= digits) 0059 { 0060 /* if x is very big, ln(gamma(x)) is 0061 dominated by x*ln x and the Binet function 0062 does not contribute anything substantial to 0063 the final result */ 0064 float_setzero(x); 0065 return 1; 0066 } 0067 float_create(&recsqr); 0068 float_create(&sum); 0069 float_create(&smd); 0070 float_create(&pwr); 0071 0072 float_copy(&pwr, &c1, EXACT); 0073 float_setzero(&sum); 0074 float_div(&smd, &c1, &c12, digits+1); 0075 workprec = digits - 2*float_getexponent(x)+3; 0076 i = 1; 0077 if (workprec > 0) 0078 { 0079 float_mul(&recsqr, x, x, workprec); 0080 float_reciprocal(&recsqr, workprec); 0081 while (float_getexponent(&smd) > -digits-1 0082 && ++i <= MAXBERNOULLIIDX) 0083 { 0084 workprec = digits + float_getexponent(&smd) + 3; 0085 float_add(&sum, &sum, &smd, digits+1); 0086 float_mul(&pwr, &recsqr, &pwr, workprec); 0087 float_muli(&smd, &cBernoulliDen[i-1], 2*i*(2*i-1), workprec); 0088 float_div(&smd, &pwr, &smd, workprec); 0089 float_mul(&smd, &smd, &cBernoulliNum[i-1], workprec); 0090 } 0091 } 0092 else 0093 /* sum reduces to the first summand*/ 0094 float_move(&sum, &smd); 0095 if (i > MAXBERNOULLIIDX) 0096 /* x was not big enough for the asymptotic 0097 series to converge sufficiently */ 0098 float_setnan(x); 0099 else 0100 float_div(x, &sum, x, digits); 0101 float_free(&pwr); 0102 float_free(&smd); 0103 float_free(&sum); 0104 float_free(&recsqr); 0105 return i <= MAXBERNOULLIIDX; 0106 } 0107 0108 /* returns the number of summands needed in the asymptotic 0109 series to guarantee <digits> precision. Each extra summand 0110 yields roughly extra 1.8 digits. This is derived under the 0111 assumption, that the costs of an extra factor in the rising 0112 pochhammer symbol are about the same than those of an extra 0113 summand in the series */ 0114 static int 0115 _findorder( 0116 int digits) 0117 { 0118 return (5*digits + 5)/9; 0119 } 0120 0121 /* returns how big x has to be to let the asymptotic series 0122 converge to at least <digits> precision. Derived from 0123 an estimation of the Bernouilli number inserted in the 0124 formula of a summand. */ 0125 static int 0126 _minx( 0127 int digits) 0128 { 0129 return (4657*_findorder(digits)-2750)/5000; 0130 } 0131 0132 /* returns how much x has to be increased to let the 0133 asymptotic series converge to <digits> places */ 0134 static int 0135 _ofs( 0136 floatnum x, 0137 int digits) 0138 { 0139 int result; 0140 0141 if (float_getexponent(x) >= 8) 0142 return 0; 0143 result = _minx(digits) - float_asinteger(x); 0144 return result <= 0? 0 : result; 0145 } 0146 0147 /* evaluates the rising pochhammer symbol x*(x+1)*...*(x+n-1) 0148 (n >= 0) by multiplying. This can be expensive when n is large, 0149 so better restrict n to something sane like n <= 100. 0150 su stands for "small" and "unsigned" n */ 0151 static char 0152 _pochhammer_su( 0153 floatnum x, 0154 int n, 0155 int digits) 0156 { 0157 floatstruct factor; 0158 char result; 0159 0160 /* the rising pochhammer symbol is computed recursively, 0161 observing that 0162 pochhammer(x, n) == pochhammer(x, p) * pochhammer(x+p, n-p). 0163 p is choosen as floor(n/2), so both factors are somehow 0164 "balanced". This pays off, if x has just a few digits, since 0165 only some late multiplications are full scale then and 0166 Karatsuba boosting yields best results, because both factors 0167 are always almost the same size. */ 0168 0169 result = 1; 0170 switch (n) 0171 { 0172 case 0: 0173 float_copy(x, &c1, EXACT); 0174 case 1: 0175 break; 0176 default: 0177 float_create(&factor); 0178 float_addi(&factor, x, n >> 1, digits+2); 0179 result = _pochhammer_su(x, n >> 1, digits) 0180 && _pochhammer_su(&factor, n - (n >> 1), digits) 0181 && float_mul(x, x, &factor, digits+2); 0182 float_free(&factor); 0183 } 0184 return result; 0185 } 0186 0187 /* evaluates ln(Gamma(x)) for all those x big 0188 enough to let the asymptotic series converge directly. 0189 Returns 0, if the result overflows 0190 relative error for a 100 gigit calculation < 5e-100 */ 0191 static char 0192 _lngammabigx( 0193 floatnum x, 0194 int digits) 0195 { 0196 floatstruct tmp1, tmp2; 0197 char result; 0198 0199 result = 0; 0200 float_create(&tmp1); 0201 float_create(&tmp2); 0202 /* compute (ln x-1) * (x-0.5) - 0.5 + ln(sqrt(2*pi)) */ 0203 float_copy(&tmp2, x, digits+1); 0204 _ln(&tmp2, digits+1); 0205 float_sub(&tmp2, &tmp2, &c1, digits+2); 0206 float_sub(&tmp1, x, &c1Div2, digits+2); 0207 if (float_mul(&tmp1, &tmp1, &tmp2, digits+2)) 0208 { 0209 /* no overflow */ 0210 binetasymptotic(x, digits); 0211 float_add(x, &tmp1, x, digits+3); 0212 float_add(x, x, &cLnSqrt2PiMinusHalf, digits+3); 0213 result = 1; 0214 } 0215 float_free(&tmp2); 0216 float_free(&tmp1); 0217 return result; 0218 } 0219 0220 static char 0221 _lngamma_prim_xgt0( 0222 floatnum x, 0223 floatnum revfactor, 0224 int digits) 0225 { 0226 int ofs; 0227 0228 ofs = _ofs(x, digits); 0229 float_copy(revfactor, x, digits+1); 0230 _pochhammer_su(revfactor, ofs, digits); 0231 float_addi(x, x, ofs, digits+2); 0232 return _lngammabigx(x, digits); 0233 } 0234 0235 static char 0236 _lngamma_prim( 0237 floatnum x, 0238 floatnum revfactor, 0239 int* infinity, 0240 int digits) 0241 { 0242 floatstruct tmp; 0243 char result; 0244 char odd; 0245 0246 *infinity = 0; 0247 if (float_getsign(x) > 0) 0248 return _lngamma_prim_xgt0(x, revfactor, digits); 0249 float_copy(revfactor, x, digits + 2); 0250 float_sub(x, &c1, x, digits+2); 0251 float_create(&tmp); 0252 result = _lngamma_prim_xgt0(x, &tmp, digits); 0253 if (result) 0254 { 0255 float_neg(x); 0256 odd = float_isodd(revfactor); 0257 _sinpix(revfactor, digits); 0258 if (float_iszero(revfactor)) 0259 { 0260 *infinity = 1; 0261 float_setinteger(revfactor, odd? -1 : 1); 0262 } 0263 else 0264 float_mul(&tmp, &tmp, &cPi, digits+2); 0265 float_div(revfactor, revfactor, &tmp, digits+2); 0266 } 0267 float_free(&tmp); 0268 return result; 0269 } 0270 0271 char 0272 _lngamma( 0273 floatnum x, 0274 int digits) 0275 { 0276 floatstruct factor; 0277 int infinity; 0278 char result; 0279 0280 if (float_cmp(x, &c1) == 0 || float_cmp(x, &c2) == 0) 0281 return _setzero(x); 0282 float_create(&factor); 0283 result = _lngamma_prim(x, &factor, &infinity, digits) 0284 && infinity == 0; 0285 if (result) 0286 { 0287 float_abs(&factor); 0288 _ln(&factor, digits + 1); 0289 result = float_sub(x, x, &factor, digits+1); 0290 } 0291 float_free(&factor); 0292 if (infinity != 0) 0293 return _seterror(x, ZeroDivide); 0294 if (!result) 0295 float_setnan(x); 0296 return result; 0297 } 0298 0299 char 0300 _gammagtminus20( 0301 floatnum x, 0302 int digits) 0303 { 0304 floatstruct factor; 0305 int ofs; 0306 char result; 0307 0308 float_create(&factor); 0309 ofs = _ofs(x, digits+1); 0310 float_copy(&factor, x, digits+1); 0311 _pochhammer_su(&factor, ofs, digits); 0312 float_addi(x, x, ofs, digits+2); 0313 result = _lngammabigx(x, digits) 0314 && _exp(x, digits) 0315 && float_div(x, x, &factor, digits+1); 0316 float_free(&factor); 0317 if (!result) 0318 float_setnan(x); 0319 return result; 0320 } 0321 0322 char 0323 _gamma( 0324 floatnum x, 0325 int digits) 0326 { 0327 floatstruct tmp; 0328 int infinity; 0329 char result; 0330 0331 if (float_cmp(&cMinus20, x) > 0) 0332 { 0333 float_create(&tmp); 0334 result = _lngamma_prim(x, &tmp, &infinity, digits) 0335 && infinity == 0 0336 && _exp(x, digits) 0337 && float_div(x, x, &tmp, digits + 1); 0338 float_free(&tmp); 0339 if (infinity != 0) 0340 return _seterror(x, ZeroDivide); 0341 if (!result) 0342 float_setnan(x); 0343 return result; 0344 } 0345 return _gammagtminus20(x, digits); 0346 } 0347 0348 char 0349 _gammaint( 0350 floatnum integer, 0351 int digits) 0352 { 0353 int ofs; 0354 0355 if (float_getexponent(integer) >=2) 0356 return _gammagtminus20(integer, digits); 0357 ofs = float_asinteger(integer); 0358 float_copy(integer, &c1, EXACT); 0359 return _pochhammer_su(integer, ofs-1, digits); 0360 } 0361 0362 char 0363 _gamma0_5( 0364 floatnum x, 0365 int digits) 0366 { 0367 floatstruct tmp; 0368 int ofs; 0369 0370 if (float_getexponent(x) >= 2) 0371 return _gamma(x, digits); 0372 float_create(&tmp); 0373 float_sub(&tmp, x, &c1Div2, EXACT); 0374 ofs = float_asinteger(&tmp); 0375 float_free(&tmp); 0376 if (ofs >= 0) 0377 { 0378 float_copy(x, &c1Div2, EXACT); 0379 if(!_pochhammer_su(x, ofs, digits)) 0380 return 0; 0381 return float_mul(x, x, &cSqrtPi, digits); 0382 } 0383 if(!_pochhammer_su(x, -ofs, digits)) 0384 return 0; 0385 return float_div(x, &cSqrtPi, x, digits); 0386 } 0387 0388 static char 0389 _pochhammer_si( 0390 floatnum x, 0391 int n, 0392 int digits) 0393 { 0394 /* this extends the rising Pochhammer symbol to negative integer offsets 0395 following the formula pochhammer(x,n-1) = pochhammer(x,n)/(x-n+1) */ 0396 0397 if (n >= 0) 0398 return _pochhammer_su(x, n, digits); 0399 return float_addi(x, x, n, digits) 0400 && _pochhammer_su(x, -n, digits) 0401 && float_reciprocal(x, digits); 0402 } 0403 0404 static char 0405 _pochhammer_g( 0406 floatnum x, 0407 cfloatnum n, 0408 int digits) 0409 { 0410 /* this generalizes the rising Pochhammer symbol using the 0411 formula pochhammer(x,n) = Gamma(x+1)/Gamma(x-n+1) */ 0412 floatstruct tmp, factor1, factor2; 0413 int inf1, inf2; 0414 char result; 0415 0416 float_create(&tmp); 0417 float_create(&factor1); 0418 float_create(&factor2); 0419 inf2 = 0; 0420 float_add(&tmp, x, n, digits+1); 0421 result = _lngamma_prim(x, &factor1, &inf1, digits) 0422 && _lngamma_prim(&tmp, &factor2, &inf2, digits) 0423 && (inf2 -= inf1) <= 0; 0424 if (inf2 > 0) 0425 float_seterror(ZeroDivide); 0426 if (result && inf2 < 0) 0427 float_setzero(x); 0428 if (result && inf2 == 0) 0429 result = float_div(&factor1, &factor1, &factor2, digits+1) 0430 && float_sub(x, &tmp, x, digits+1) 0431 && _exp(x, digits) 0432 && float_mul(x, x, &factor1, digits+1); 0433 float_free(&tmp); 0434 float_free(&factor2); 0435 float_free(&factor1); 0436 if (!result) 0437 float_setnan(x); 0438 return result; 0439 } 0440 0441 static char 0442 _pochhammer_i( 0443 floatnum x, 0444 cfloatnum n, 0445 int digits) 0446 { 0447 /* do not use the expensive Gamma function when a few 0448 multiplications do the same */ 0449 /* pre: n is an integer */ 0450 int ni; 0451 signed char result; 0452 0453 if (float_iszero(n)) 0454 return float_copy(x, &c1, EXACT); 0455 if (float_isinteger(x)) 0456 { 0457 result = -1; 0458 float_neg((floatnum)n); 0459 if (float_getsign(x) <= 0 && float_cmp(x, n) > 0) 0460 /* x and x+n have opposite signs, meaning 0 is 0461 among the factors */ 0462 result = _setzero(x); 0463 else if (float_getsign(x) > 0 && float_cmp(x, n) <= 0) 0464 /* x and x+n have opposite signs, meaning at one point 0465 you have to divide by 0 */ 0466 result = _seterror(x, ZeroDivide); 0467 float_neg((floatnum)n); 0468 if (result >= 0) 0469 return result; 0470 } 0471 if (float_getexponent(x) < EXPMAX/100) 0472 { 0473 ni = float_asinteger(n); 0474 if (ni != 0 && ni < 50 && ni > -50) 0475 return _pochhammer_si(x, ni, digits+2); 0476 } 0477 return _pochhammer_g(x, n, digits); 0478 } 0479 0480 char 0481 _pochhammer( 0482 floatnum x, 0483 cfloatnum n, 0484 int digits) 0485 { 0486 if (float_isinteger(n)) 0487 return _pochhammer_i(x, n, digits); 0488 return _pochhammer_g(x, n, digits); 0489 }