Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

random.cc

Go to the documentation of this file.
00001 // -*- C++ -*- 00002 00003 // PLearn (A C++ Machine Learning Library) 00004 // Copyright (C) 1998 Pascal Vincent 00005 // Copyright (C) 1999-2002 Pascal Vincent, Yoshua Bengio and University of Montreal 00006 // 00007 00008 // Redistribution and use in source and binary forms, with or without 00009 // modification, are permitted provided that the following conditions are met: 00010 // 00011 // 1. Redistributions of source code must retain the above copyright 00012 // notice, this list of conditions and the following disclaimer. 00013 // 00014 // 2. Redistributions in binary form must reproduce the above copyright 00015 // notice, this list of conditions and the following disclaimer in the 00016 // documentation and/or other materials provided with the distribution. 00017 // 00018 // 3. The name of the authors may not be used to endorse or promote 00019 // products derived from this software without specific prior written 00020 // permission. 00021 // 00022 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00023 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00024 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00025 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00026 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00027 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00028 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00029 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00030 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00031 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00032 // 00033 // This file is part of the PLearn library. For more information on the PLearn 00034 // library, go to the PLearn Web site at www.plearn.org 00035 00036 /* ******************************************************* 00037 * $Id: random.cc,v 1.8 2004/07/21 16:30:53 chrish42 Exp $ 00038 ******************************************************* */ 00039 00040 extern "C" { 00041 #include <ctime> 00042 } 00043 00044 #include <plearn/base/general.h> 00045 #include "random.h" 00046 00047 namespace PLearn { 00048 using namespace std; 00049 00050 00051 /* 00052 The static data to store the seed used by the random number generators. 00053 */ 00054 00055 static long the_seed=0; 00056 static int iset=0; 00057 static real gset; 00058 00059 /* 00060 Special functions. 00061 ================= 00062 */ 00063 00064 /* 00065 log_gamma(): 00066 returns the natural logarithm of the gamma function 00067 */ 00068 00069 real log_gamma(real xx) 00070 { 00071 double x,y,tmp,ser; 00072 static double gamma_coeffs[6]={ 76.18009172947146 , 00073 -86.50532032941677 , 00074 24.01409824083091 , 00075 -1.231739572450155 , 00076 0.1208650973866179e-2, 00077 -0.5395239384953e-5 }; 00078 int j; 00079 00080 y=x=xx; 00081 tmp=x+5.5; 00082 tmp -= (x+0.5)*log(tmp); 00083 ser=1.000000000190015; 00084 for (j=0;j<=5;j++) ser += gamma_coeffs[j]/++y; 00085 return -tmp+log(2.5066282746310005*ser/x); 00086 } 00087 00089 real log_beta(real x, real y) 00090 { 00091 return log_gamma(x) + log_gamma(y) - log_gamma(x+y); 00092 } 00093 00094 real incomplete_beta_continued_fraction(real z, real x, real y) 00095 { 00096 real x_minus_1 = x-1; 00097 real x_plus_1 = x+1; 00098 real x_plus_y = x+y; 00099 real denom = -z*x_plus_y/x_plus_1+1; 00100 if (fabs(denom)<1e-35) { 00101 denom=1e-35; 00102 } 00103 real rat1=1/denom; 00104 real rat2=1.0; 00105 real frac=rat1; 00106 for (int k=1;k<100;k++) 00107 { 00108 real f=z*k*(y-k)/((x+2*k)*(x_minus_1+2*k)); 00109 rat2 = f/rat2 + 1; 00110 rat1 = rat1*f+1; 00111 if (fabs(rat1)<1e-35) { 00112 rat1=1e-35; 00113 } 00114 if (fabs(rat2)<1e-35) { 00115 rat2=1e-35; 00116 } 00117 rat1=1/rat1; 00118 frac *= rat1*rat2; 00119 00120 f=-z*(x+k)*(x_plus_y+k)/((x_plus_1+2*k)*(x+2*k)); 00121 rat2 = f/rat2+ 1; 00122 rat1 = rat1*f+1; 00123 if (fabs(rat1)<1e-35) { 00124 rat1=1e-35; 00125 } 00126 if (fabs(rat2)<1e-35) { 00127 rat2=1e-35; 00128 } 00129 rat1=1/rat1; 00130 00131 real delta = rat1*rat2; 00132 frac *= delta; 00133 // stopping criterion 00134 if (fabs(1-delta) < 2e-7) { 00135 return frac; 00136 } 00137 } 00138 // If that happens, increase the number of k iterations or increase 00139 // the stopping criterion tolerance. 00140 PLWARNING("incomplete_beta_continued_fraction: insufficient precision!"); 00141 return frac; 00142 } 00143 00146 real incomplete_beta(real z, real x, real y) 00147 { 00148 if (z>1 || z<0) PLERROR("incomplete_beta(z,x,y): z =%f must be in [0,1]",z); 00149 real coeff = 0; 00150 if (z>0 && z<1) coeff = exp(x*log(z)+y*log(1.-z)-log_beta(x,y)); 00151 if (z*(x+y+2)<x+1) { 00152 return coeff*incomplete_beta_continued_fraction(z,x,y)/x; 00153 } 00154 return 1-coeff*incomplete_beta_continued_fraction(1-z,y,x)/y; 00155 } 00156 00158 real student_t_cdf(real t, int nb_degrees_of_freedom) 00159 { 00160 real p_t = 0.5*incomplete_beta(nb_degrees_of_freedom/(nb_degrees_of_freedom+t*t),0.5*nb_degrees_of_freedom,0.5); 00161 //real p_t = 0.5*incbet(0.5*nb_degrees_of_freedom,0.5,nb_degrees_of_freedom/(nb_degrees_of_freedom+t*t)); 00162 #ifdef BOUNDCHECK 00163 if (p_t < 0) { 00164 PLERROR("Bug in incomplete_beta : returned a negative p_t !\n- p_t = %f\n- degrees of freedom = %d\n- t = %f", 00165 p_t, nb_degrees_of_freedom, t); 00166 } 00167 #endif 00168 if (t>0) 00169 return 1.0 - p_t; 00170 else 00171 return p_t; 00172 } 00173 00174 /* 00175 Utilities for random numbers generation. 00176 ======================================= 00177 */ 00178 00179 /* 00180 manual_seed(): gives a seed for random number generators. 00181 00182 Rem: - The stored value is negative. 00183 */ 00184 00185 void manual_seed(long x) 00186 { 00187 the_seed = - labs(x); 00188 iset = 0; 00189 } 00190 00191 /* 00192 seed(): generates a seed for random number generators, using the cpu time. 00193 */ 00194 00195 void seed() 00196 { 00197 time_t ltime; 00198 struct tm *today; 00199 time(&ltime); 00200 today = localtime(&ltime); 00201 manual_seed((long)today->tm_sec+ 00202 60*today->tm_min+ 00203 60*60*today->tm_hour+ 00204 60*60*24*today->tm_mday); 00205 } 00206 00207 /* 00208 get_seed(): returns the current value of the 'seed'. 00209 */ 00210 00211 long get_seed() 00212 { 00213 long seed = the_seed; 00214 return seed; 00215 } 00216 00217 /* 00218 Constants used by the 'numerical recipes' random number generators. 00219 */ 00220 00221 #define NTAB 32 /* needs for ran1 & ran2 */ 00222 #define EPS 1.2e-7 /* needs for ran1 & ran2 */ 00223 #define RNMX (1.0-EPS) /* needs for ran1 & ran2 */ 00224 #define IM1 2147483563 /* needs for ran2 */ 00225 #define IM2 2147483399 /* needs for ran2 */ 00226 #define AM1 (1.0/IM1) /* needs for ran2 */ 00227 #define IMM1 (IM1-1) /* needs for ran2 */ 00228 #define IA1 40014 /* needs for ran2 */ 00229 #define IA2 40692 /* needs for ran2 */ 00230 #define IQ1 53668 /* needs for ran2 */ 00231 #define IQ2 52774 /* needs for ran2 */ 00232 #define IR1 12211 /* needs for ran2 */ 00233 #define IR2 3791 /* needs for ran2 */ 00234 #define NDIV1 (1+IMM1/NTAB) /* needs for ran2 */ 00235 00236 /* 00237 ran2(): long period ramdom number generator from the 'numerical recipes'. 00238 00239 Rem: - It is a long period (> 2 x 10^18) random number generator of L'Ecuyer 00240 with Bays-Durham shuffle and added safeguards. 00241 00242 - Returns a uniform random deviate between 0.0 and 1.0 00243 (exclusive of the endpoint values). 00244 00245 - Initilized with a negative seed. 00246 */ 00247 00248 real uniform_sample() 00249 { 00250 int j; 00251 long k; 00252 static long idum2=123456789; 00253 static long iy=0; 00254 static long iv[NTAB]; 00255 real temp; 00256 00257 if (the_seed <= 0) { 00258 if (-the_seed < 1) the_seed=1; 00259 else the_seed = -the_seed; 00260 idum2=the_seed; 00261 for (j=NTAB+7;j>=0;j--) { 00262 k=the_seed/IQ1; 00263 the_seed=IA1*(the_seed-k*IQ1)-k*IR1; 00264 if (the_seed < 0) the_seed += IM1; 00265 if (j < NTAB) iv[j] = the_seed; 00266 } 00267 iy=iv[0]; 00268 } 00269 k=the_seed/IQ1; 00270 the_seed=IA1*(the_seed-k*IQ1)-k*IR1; 00271 if (the_seed < 0) the_seed += IM1; 00272 k=idum2/IQ2; 00273 idum2=IA2*(idum2-k*IQ2)-k*IR2; 00274 if (idum2 < 0) idum2 += IM2; 00275 j=iy/NDIV1; 00276 iy=iv[j]-idum2; 00277 iv[j] = the_seed; 00278 if (iy < 1) iy += IMM1; 00279 if ((temp=AM1*iy) > RNMX) return RNMX; 00280 else return temp; 00281 } 00282 00283 /* 00284 bounded_uniform(): return an uniform random generator in [a,b]. 00285 */ 00286 00287 real bounded_uniform(real a,real b) 00288 { 00289 real res = uniform_sample()*(b-a) + a; 00290 if (res >= b) return b*RNMX; 00291 else return res; 00292 } 00293 00294 #undef NDIV 00295 #undef EPS 00296 #undef RNMX 00297 #undef IM1 00298 #undef IM2 00299 #undef AM1 00300 #undef IMM1 00301 #undef IA1 00302 #undef IA2 00303 #undef IQ1 00304 #undef IQ2 00305 #undef IR1 00306 #undef IR2 00307 #undef NDIV1 00308 00309 /* 00310 TRANSFORMATION METHOD: 00311 --------------------- 00312 */ 00313 00314 /* 00315 expdev(): exponential deviate random number from the 'numerical recipes'. 00316 */ 00317 00318 real expdev() 00319 { 00320 real dum; 00321 00322 do 00323 dum=uniform_sample(); 00324 while (dum == 0.0); 00325 return -log(dum); 00326 } 00327 00328 real gaussian_01() 00329 { 00330 real fac,rsq,v1,v2; 00331 00332 if(the_seed < 0) iset=0; 00333 if (iset == 0) { 00334 do { 00335 v1=2.0*uniform_sample()-1.0; 00336 v2=2.0*uniform_sample()-1.0; 00337 rsq=v1*v1+v2*v2; 00338 } while (rsq >= 1.0 || rsq == 0.0); 00339 fac=sqrt(-2.0*log(rsq)/rsq); 00340 gset=v1*fac; 00341 iset=1; 00342 return v2*fac; 00343 } else { 00344 iset=0; 00345 return gset; 00346 } 00347 } 00348 00349 /* 00350 gaussian_mu_sigma(): returns a gaussian distributed random number 00351 with mean 'mu' and standard deviation 'sigma'. 00352 00353 Rem: - i.e. N(mu,sigma). 00354 */ 00355 00356 real gaussian_mu_sigma(real mu, real sigma) 00357 { 00358 return gaussian_01() * sigma + mu; 00359 } 00360 00361 00362 /* 00363 gaussian_misture_mu_sigma(): returns a random number with mixture of gaussians, 00364 'w' is the mixture (must be positive summing to 1). 00365 00366 Rem: - i.e. SUM w[i] * N(mu[i],sigma[i]) 00367 */ 00368 00369 real gaussian_mixture_mu_sigma(Vec& w, const Vec& mu, const Vec& sigma) 00370 { 00371 int i; 00372 int n = w.length(); 00373 real *p_mu = mu.data(); 00374 real *p_sigma = sigma.data(); 00375 real *p_w = w.data(); 00376 real res = 0.0; 00377 00378 for (i=0; i<n; i++, p_mu++, p_sigma++, p_w++) 00379 res += *p_w * gaussian_mu_sigma(*p_mu,*p_sigma); 00380 00381 return res; 00382 } 00383 00384 /* 00385 REJECTION METHOD: 00386 ---------------- 00387 */ 00388 00389 /* 00390 gamdev(): returns a deviate distributed as a gamma distribution from the 'numerical recipes'. 00391 */ 00392 00393 real gamdev(int ia) 00394 { 00395 int j; 00396 real am,e,s,v1,v2,x,y; 00397 00398 if (ia < 1) PLERROR("Error in routine gamdev"); 00399 if (ia < 6) { 00400 x=1.0; 00401 for (j=1;j<=ia;j++) x *= uniform_sample(); 00402 x = -log(x); 00403 } else { 00404 do { 00405 do { 00406 do { 00407 v1=uniform_sample(); 00408 v2=2.0*uniform_sample()-1.0; 00409 } while (v1*v1+v2*v2 > 1.0); 00410 y=v2/v1; 00411 am=ia-1; 00412 s=sqrt(2.0*am+1.0); 00413 x=s*y+am; 00414 } while (x <= 0.0); 00415 e=(1.0+y*y)*exp(am*log(x/am)-s*y); 00416 } while (uniform_sample() > e); 00417 } 00418 return x; 00419 } 00420 00421 /* 00422 poidev(): returns a deviate distributed as a poisson distribution of mean (lambda) 'xm' 00423 from the 'numerical recipes'. 00424 */ 00425 00426 real poidev(real xm) 00427 { 00428 static real sq,alxm,g,oldm=(-1.0); 00429 real em,t,y; 00430 00431 if (xm < 12.0) { 00432 if (xm != oldm) { 00433 oldm=xm; 00434 g=exp(-xm); 00435 } 00436 em = -1; 00437 t=1.0; 00438 do { 00439 ++em; 00440 t *= uniform_sample(); 00441 } while (t > g); 00442 } else { 00443 if (xm != oldm) { 00444 oldm=xm; 00445 sq=sqrt(2.0*xm); 00446 alxm=log(xm); 00447 g=xm*alxm-log_gamma(xm+1.0); 00448 } 00449 do { 00450 do { 00451 y=tan(Pi*uniform_sample()); 00452 em=sq*y+xm; 00453 } while (em < 0.0); 00454 em=floor(em); 00455 t=0.9*(1.0+y*y)*exp(em*alxm-log_gamma(em+1.0)-g); 00456 } while (uniform_sample() > t); 00457 } 00458 return em; 00459 } 00460 00461 /* 00462 bnldev(): return a random deviate drawn from a binomial distribution of 'n' trials 00463 each of probability 'pp', from 'numerical recipes'. 00464 00465 Rem: - The returned type is an real although a binomial random variable is an integer. 00466 */ 00467 00468 real bnldev(real pp, int n) 00469 { 00470 int j; 00471 static int nold=(-1); 00472 real am,em,g,angle,p,bnl,sq,t,y; 00473 static real pold=(-1.0),pc,plog,pclog,en,oldg; 00474 00475 p=(pp <= 0.5 ? pp : 1.0-pp); 00476 am=n*p; 00477 if (n < 25) { 00478 bnl=0.0; 00479 for (j=1;j<=n;j++) 00480 if (uniform_sample() < p) ++bnl; 00481 } else if (am < 1.0) { 00482 g=exp(-am); 00483 t=1.0; 00484 for (j=0;j<=n;j++) { 00485 t *= uniform_sample(); 00486 if (t < g) break; 00487 } 00488 bnl=(j <= n ? j : n); 00489 } else { 00490 if (n != nold) { 00491 en=n; 00492 oldg=log_gamma(en+1.0); 00493 nold=n; 00494 } if (p != pold) { 00495 pc=1.0-p; 00496 plog=log(p); 00497 pclog=log(pc); 00498 pold=p; 00499 } 00500 sq=sqrt(2.0*am*pc); 00501 do { 00502 do { 00503 angle=Pi*uniform_sample(); 00504 y=tan(angle); 00505 em=sq*y+am; 00506 } while (em < 0.0 || em >= (en+1.0)); 00507 em=floor(em); 00508 t=1.2*sq*(1.0+y*y)*exp(oldg-log_gamma(em+1.0) 00509 -log_gamma(en-em+1.0)+em*plog+(en-em)*pclog); 00510 } while (uniform_sample() > t); 00511 bnl=em; 00512 } 00513 if (p != pp) bnl=n-bnl; 00514 return bnl; 00515 } 00516 00517 /* 00518 SOME KIND OF DISCRETE DISTRIBUTIONS: 00519 ----------------------------------- 00520 */ 00521 00522 /* 00523 multinomial_sample(): returns a random deviate from a discrete distribution 00524 given explicitely by 'distribution'. 00525 00526 Rem: - So, the vector elements of 'distribution' are probabilities summing to 1. 00527 00528 - The returned value is a index value of 'distribution' (i.e. in range 00529 [0 .. (distribution->lenght)-1] ). 00530 00531 - The graphical representation of vectors 'distribution' is histogram. 00532 00533 - This random deviate is computed by the transformation method. 00534 */ 00535 00536 int multinomial_sample(const Vec& distribution) 00537 { 00538 real u = uniform_sample(); 00539 real* pi = distribution.data(); 00540 real s = *pi; 00541 int n = distribution.length(); 00542 int i = 0; 00543 while ((i<n) && (s<u)) { 00544 i++; 00545 pi++; 00546 s += *pi; 00547 } 00548 if (i==n) 00549 i = n - 1; /* improbable but... */ 00550 return i; 00551 } 00552 00553 int uniform_multinomial_sample(int N) 00554 { 00555 // N.B. uniform_sample() cannot return 1.0 00556 return int(N*uniform_sample()); 00557 } 00558 00560 void fill_random_uniform(const Vec& dest, real minval, real maxval) 00561 { 00562 Vec::iterator it = dest.begin(); 00563 Vec::iterator itend = dest.end(); 00564 double scale = maxval-minval; 00565 for(; it!=itend; ++it) 00566 *it = real(uniform_sample()*scale+minval); 00567 } 00568 00570 void fill_random_discrete(const Vec& dest, const Vec& set) 00571 { 00572 Vec::iterator it = dest.begin(); 00573 Vec::iterator itend = dest.end(); 00574 int n=set.length(); 00575 for(; it!=itend; ++it) 00576 *it = set[uniform_multinomial_sample(n)]; 00577 } 00578 00580 void fill_random_normal(const Vec& dest, real mean, real stdev) 00581 { 00582 Vec::iterator it = dest.begin(); 00583 Vec::iterator itend = dest.end(); 00584 for(; it!=itend; ++it) 00585 *it = real(gaussian_mu_sigma(mean,stdev)); 00586 } 00587 00589 void fill_random_normal(const Vec& dest, const Vec& mean, const Vec& stdev) 00590 { 00591 #ifdef BOUNDCHECK 00592 if(mean.length()!=dest.length() || stdev.length()!=dest.length()) 00593 PLERROR("In fill_random_normal: dest, mean and stdev must have the same length"); 00594 #endif 00595 Vec::iterator it_mean = mean.begin(); 00596 Vec::iterator it_stdev = stdev.begin(); 00597 Vec::iterator it = dest.begin(); 00598 Vec::iterator itend = dest.end(); 00599 for(; it!=itend; ++it, ++it_mean, ++it_stdev) 00600 *it = real(gaussian_mu_sigma(*it_mean,*it_stdev)); 00601 } 00602 00603 00604 void fill_random_uniform(const Mat& dest, real minval, real maxval) 00605 { 00606 double scale = maxval-minval; 00607 Mat::iterator it = dest.begin(); 00608 Mat::iterator itend = dest.end(); 00609 for(; it!=itend; ++it) 00610 *it = real(uniform_sample()*scale+minval); 00611 } 00612 00613 void fill_random_normal(const Mat& dest, real mean, real sdev) 00614 { 00615 Mat::iterator it = dest.begin(); 00616 Mat::iterator itend = dest.end(); 00617 for(; it!=itend; ++it) 00618 *it = real(gaussian_mu_sigma(mean,sdev)); 00619 } 00620 00621 /* incbet.c 00622 * 00623 * Incomplete beta integral 00624 * 00625 * 00626 * SYNOPSIS: 00627 * 00628 * double a, b, x, y, incbet(); 00629 * 00630 * y = incbet( a, b, x ); 00631 * 00632 * 00633 * DESCRIPTION: 00634 * 00635 * Returns incomplete beta integral of the arguments, evaluated 00636 * from zero to x. The function is defined as 00637 * 00638 * x 00639 * - - 00640 * | (a+b) | | a-1 b-1 00641 * ----------- | t (1-t) dt. 00642 * - - | | 00643 * | (a) | (b) - 00644 * 0 00645 * 00646 * The domain of definition is 0 <= x <= 1. In this 00647 * implementation a and b are restricted to positive values. 00648 * The integral from x to 1 may be obtained by the symmetry 00649 * relation 00650 * 00651 * 1 - incbet( a, b, x ) = incbet( b, a, 1-x ). 00652 * 00653 * The integral is evaluated by a continued fraction expansion 00654 * or, when b*x is small, by a power series. 00655 * 00656 * ACCURACY: 00657 * 00658 * Tested at uniformly distributed random points (a,b,x) with a and b 00659 * in "domain" and x between 0 and 1. 00660 * Relative error 00661 * arithmetic domain # trials peak rms 00662 * IEEE 0,5 10000 6.9e-15 4.5e-16 00663 * IEEE 0,85 250000 2.2e-13 1.7e-14 00664 * IEEE 0,1000 30000 5.3e-12 6.3e-13 00665 * IEEE 0,10000 250000 9.3e-11 7.1e-12 00666 * IEEE 0,100000 10000 8.7e-10 4.8e-11 00667 * Outputs smaller than the IEEE gradual underflow threshold 00668 * were excluded from these statistics. 00669 * 00670 * ERROR MESSAGES: 00671 * message condition value returned 00672 * incbet domain x<0, x>1 0.0 00673 * incbet underflow 0.0 00674 */ 00675 00676 00677 /* 00678 Cephes Math Library, Release 2.8: June, 2000 00679 Copyright 1984, 1995, 2000 by Stephen L. Moshier 00680 */ 00681 00682 //#include "mconf.h" 00683 00684 #define MAXGAM 171.624376956302725 00685 00686 /* 00687 extern double MACHEP, MINLOG, MAXLOG; 00688 #ifdef ANSIPROT 00689 extern double gamma ( double ); 00690 extern double lgam ( double ); 00691 extern double exp ( double ); 00692 extern double log ( double ); 00693 extern double pow ( double, double ); 00694 extern double fabs ( double ); 00695 static double incbcf(double, double, double); 00696 static double incbd(double, double, double); 00697 static double pseries(double, double, double); 00698 #else 00699 double gamma(), lgam(), exp(), log(), pow(), fabs(); 00700 static double incbcf(), incbd(), pseries(); 00701 #endif 00702 00703 */ 00704 double MAXLOG = 7.09782712893383996732E2; /* log(MAXNUM) */ 00705 double MINLOG = -7.451332191019412076235E2; /* log(2**-1075) */ 00706 double MACHEP = 1.11022302462515654042E-16; /* 2**-53 */ 00707 //double pseries( double a, double b, double x ); 00708 double incbcf( double a, double b, double x ); 00709 double incbd( double a, double b, double x ); 00710 double big = 4.503599627370496e15; 00711 double biginv = 2.22044604925031308085e-16; 00712 00713 00714 /* 00715 double incbet(double aa, double bb, double xx ) 00716 { 00717 double a, b, t, x, xc, w, y; 00718 int flag; 00719 00720 if( aa <= 0.0 || bb <= 0.0 ) 00721 goto domerr; 00722 00723 if( (xx <= 0.0) || ( xx >= 1.0) ) 00724 { 00725 if( xx == 0.0 ) 00726 return(0.0); 00727 if( xx == 1.0 ) 00728 return( 1.0 ); 00729 domerr: 00730 PLERROR("incbet: arguments out of expected domain"); 00731 return( 0.0 ); 00732 } 00733 00734 flag = 0; 00735 if( (bb * xx) <= 1.0 && xx <= 0.95) 00736 { 00737 t = pseries(aa, bb, xx); 00738 goto done; 00739 } 00740 00741 w = 1.0 - xx; 00742 00743 // Reverse a and b if x is greater than the mean. 00744 if( xx > (aa/(aa+bb)) ) 00745 { 00746 flag = 1; 00747 a = bb; 00748 b = aa; 00749 xc = xx; 00750 x = w; 00751 } 00752 else 00753 { 00754 a = aa; 00755 b = bb; 00756 xc = w; 00757 x = xx; 00758 } 00759 00760 if( flag == 1 && (b * x) <= 1.0 && x <= 0.95) 00761 { 00762 t = pseries(a, b, x); 00763 goto done; 00764 } 00765 00766 // Choose expansion for better convergence. 00767 y = x * (a+b-2.0) - (a-1.0); 00768 if( y < 0.0 ) 00769 w = incbcf( a, b, x ); 00770 else 00771 w = incbd( a, b, x ) / xc; 00772 00773 // Multiply w by the factor 00774 // a b _ _ _ 00775 // x (1-x) | (a+b) / ( a | (a) | (b) ) . 00776 00777 y = a * log(x); 00778 t = b * log(xc); 00779 if( (a+b) < MAXGAM && fabs(y) < MAXLOG && fabs(t) < MAXLOG ) 00780 { 00781 t = pow(xc,b); 00782 t *= pow(x,a); 00783 t /= a; 00784 t *= w; 00785 t *= gamma(a+b) / (gamma(a) * gamma(b)); 00786 goto done; 00787 } 00788 // Resort to logarithms. 00789 y += t + log_gamma(a+b) - log_gamma(a) - log_gamma(b); 00790 y += log(w/a); 00791 if( y < MINLOG ) 00792 t = 0.0; 00793 else 00794 t = exp(y); 00795 00796 done: 00797 00798 if( flag == 1 ) 00799 { 00800 if( t <= MACHEP ) 00801 t = 1.0 - MACHEP; 00802 else 00803 t = 1.0 - t; 00804 } 00805 return( t ); 00806 } 00807 */ 00808 00809 /* Continued fraction expansion #1 00810 * for incomplete beta integral 00811 */ 00812 00813 double incbcf( double a, double b, double x ) 00814 { 00815 double xk, pk, pkm1, pkm2, qk, qkm1, qkm2; 00816 double k1, k2, k3, k4, k5, k6, k7, k8; 00817 double r, t, ans, thresh; 00818 int n; 00819 00820 k1 = a; 00821 k2 = a + b; 00822 k3 = a; 00823 k4 = a + 1.0; 00824 k5 = 1.0; 00825 k6 = b - 1.0; 00826 k7 = k4; 00827 k8 = a + 2.0; 00828 00829 pkm2 = 0.0; 00830 qkm2 = 1.0; 00831 pkm1 = 1.0; 00832 qkm1 = 1.0; 00833 ans = 1.0; 00834 r = 1.0; 00835 n = 0; 00836 thresh = 3.0 * MACHEP; 00837 do 00838 { 00839 00840 xk = -( x * k1 * k2 )/( k3 * k4 ); 00841 pk = pkm1 + pkm2 * xk; 00842 qk = qkm1 + qkm2 * xk; 00843 pkm2 = pkm1; 00844 pkm1 = pk; 00845 qkm2 = qkm1; 00846 qkm1 = qk; 00847 00848 xk = ( x * k5 * k6 )/( k7 * k8 ); 00849 pk = pkm1 + pkm2 * xk; 00850 qk = qkm1 + qkm2 * xk; 00851 pkm2 = pkm1; 00852 pkm1 = pk; 00853 qkm2 = qkm1; 00854 qkm1 = qk; 00855 00856 if( qk != 0 ) 00857 r = pk/qk; 00858 if( r != 0 ) 00859 { 00860 t = fabs( (ans - r)/r ); 00861 ans = r; 00862 } 00863 else 00864 t = 1.0; 00865 00866 if( t < thresh ) 00867 goto cdone; 00868 00869 k1 += 1.0; 00870 k2 += 1.0; 00871 k3 += 2.0; 00872 k4 += 2.0; 00873 k5 += 1.0; 00874 k6 -= 1.0; 00875 k7 += 2.0; 00876 k8 += 2.0; 00877 00878 if( (fabs(qk) + fabs(pk)) > big ) 00879 { 00880 pkm2 *= biginv; 00881 pkm1 *= biginv; 00882 qkm2 *= biginv; 00883 qkm1 *= biginv; 00884 } 00885 if( (fabs(qk) < biginv) || (fabs(pk) < biginv) ) 00886 { 00887 pkm2 *= big; 00888 pkm1 *= big; 00889 qkm2 *= big; 00890 qkm1 *= big; 00891 } 00892 } 00893 while( ++n < 300 ); 00894 00895 cdone: 00896 return(ans); 00897 } 00898 00899 /* Continued fraction expansion #2 00900 * for incomplete beta integral 00901 */ 00902 00903 double incbd( double a, double b, double x ) 00904 { 00905 double xk, pk, pkm1, pkm2, qk, qkm1, qkm2; 00906 double k1, k2, k3, k4, k5, k6, k7, k8; 00907 double r, t, ans, z, thresh; 00908 int n; 00909 00910 k1 = a; 00911 k2 = b - 1.0; 00912 k3 = a; 00913 k4 = a + 1.0; 00914 k5 = 1.0; 00915 k6 = a + b; 00916 k7 = a + 1.0;; 00917 k8 = a + 2.0; 00918 00919 pkm2 = 0.0; 00920 qkm2 = 1.0; 00921 pkm1 = 1.0; 00922 qkm1 = 1.0; 00923 z = x / (1.0-x); 00924 ans = 1.0; 00925 r = 1.0; 00926 n = 0; 00927 thresh = 3.0 * MACHEP; 00928 do 00929 { 00930 00931 xk = -( z * k1 * k2 )/( k3 * k4 ); 00932 pk = pkm1 + pkm2 * xk; 00933 qk = qkm1 + qkm2 * xk; 00934 pkm2 = pkm1; 00935 pkm1 = pk; 00936 qkm2 = qkm1; 00937 qkm1 = qk; 00938 00939 xk = ( z * k5 * k6 )/( k7 * k8 ); 00940 pk = pkm1 + pkm2 * xk; 00941 qk = qkm1 + qkm2 * xk; 00942 pkm2 = pkm1; 00943 pkm1 = pk; 00944 qkm2 = qkm1; 00945 qkm1 = qk; 00946 00947 if( qk != 0 ) 00948 r = pk/qk; 00949 if( r != 0 ) 00950 { 00951 t = fabs( (ans - r)/r ); 00952 ans = r; 00953 } 00954 else 00955 t = 1.0; 00956 00957 if( t < thresh ) 00958 goto cdone; 00959 00960 k1 += 1.0; 00961 k2 -= 1.0; 00962 k3 += 2.0; 00963 k4 += 2.0; 00964 k5 += 1.0; 00965 k6 += 1.0; 00966 k7 += 2.0; 00967 k8 += 2.0; 00968 00969 if( (fabs(qk) + fabs(pk)) > big ) 00970 { 00971 pkm2 *= biginv; 00972 pkm1 *= biginv; 00973 qkm2 *= biginv; 00974 qkm1 *= biginv; 00975 } 00976 if( (fabs(qk) < biginv) || (fabs(pk) < biginv) ) 00977 { 00978 pkm2 *= big; 00979 pkm1 *= big; 00980 qkm2 *= big; 00981 qkm1 *= big; 00982 } 00983 } 00984 while( ++n < 300 ); 00985 cdone: 00986 return(ans); 00987 } 00988 00989 /* Power series for incomplete beta integral. 00990 Use when b*x is small and x not too close to 1. */ 00991 00992 /* 00993 double pseries( double a, double b, double x ) 00994 { 00995 double s, t, u, v, n, t1, z, ai; 00996 00997 ai = 1.0 / a; 00998 u = (1.0 - b) * x; 00999 v = u / (a + 1.0); 01000 t1 = v; 01001 t = u; 01002 n = 2.0; 01003 s = 0.0; 01004 z = MACHEP * ai; 01005 while( fabs(v) > z ) 01006 { 01007 u = (n - b) * x / n; 01008 t *= u; 01009 v = t / (a + n); 01010 s += v; 01011 n += 1.0; 01012 } 01013 s += t1; 01014 s += ai; 01015 01016 u = a * log(x); 01017 if( (a+b) < MAXGAM && fabs(u) < MAXLOG ) 01018 { 01019 t = gamma(a+b)/(gamma(a)*gamma(b)); 01020 s = s * t * pow(x,a); 01021 } 01022 else 01023 { 01024 t = log_gamma(a+b) - log_gamma(a) - log_gamma(b) + u + log(s); 01025 if( t < MINLOG ) 01026 s = 0.0; 01027 else 01028 s = exp(t); 01029 } 01030 return(s); 01031 } 01032 */ 01033 01034 } // end of namespace PLearn 01035

Generated on Tue Aug 17 16:03:21 2004 for PLearn by doxygen 1.3.7