Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
integer, | intent(in) | :: | n | |||
real, | intent(in) | :: | p | |||
logical, | intent(in) | :: | first |
FUNCTION random_binomial1(n, p, first) RESULT(ival) ! FUNCTION GENERATES A RANDOM BINOMIAL VARIATE USING C.D.Kemp's method. ! This algorithm is suitable when many random variates are required ! with the SAME parameter values for n & p. ! P = BERNOULLI SUCCESS PROBABILITY ! (0 <= REAL <= 1) ! N = NUMBER OF BERNOULLI TRIALS ! (1 <= INTEGER) ! FIRST = .TRUE. for the first call using the current parameter values ! = .FALSE. if the values of (n,p) are unchanged from last call ! Reference: Kemp, C.D. (1986). `A modal method for generating binomial ! variables', Commun. Statist. - Theor. Meth. 15(3), 805-813. INTEGER, INTENT(IN) :: n REAL, INTENT(IN) :: p LOGICAL, INTENT(IN) :: first INTEGER :: ival ! Local variables INTEGER :: ru, rd INTEGER, SAVE :: r0 REAL :: u, pd, pu REAL, SAVE :: odds_ratio, p_r REAL, PARAMETER :: zero = 0.0, one = 1.0 IF (first) THEN r0 = (n+1)*p p_r = bin_prob(n, p, r0) odds_ratio = p / (one - p) END IF CALL RANDOM_NUMBER(u) u = u - p_r IF (u < zero) THEN ival = r0 RETURN END IF pu = p_r ru = r0 pd = p_r rd = r0 DO rd = rd - 1 IF (rd >= 0) THEN pd = pd * (rd+1) / (odds_ratio * (n-rd)) u = u - pd IF (u < zero) THEN ival = rd RETURN END IF END IF ru = ru + 1 IF (ru <= n) THEN pu = pu * (n-ru+1) * odds_ratio / ru u = u - pu IF (u < zero) THEN ival = ru RETURN END IF END IF END DO ! This point should not be reached, but just in case: ival = r0 RETURN END FUNCTION random_binomial1