Blame view

fvn_fnlib/dpoch.f 3.63 KB
38581db0c   daniau   git-svn-id: https...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
        double precision function dpoch (a, x)
  c august 1980 edition.  w. fullerton, c3, los alamos scientific lab.
  c error handling when poch (a, x) is less than half precision is
  c probably incorrect.  grossly wrong arguments are not handled right.
  c
  c evaluate a generalization of pochhammer-s symbol
  c (a)-sub-x = gamma(a+x)/gamma(a).  for x a non-negative integer,
  c poch(a,x) is just pochhammer-s symbol.
  c
        double precision a, x, absa, absax, alnga, alngax, ax, b, pi,
       1  eps, sqeps, cospix, sinpix, cospia, sinpia, errpch, den, err,
       2  sgnga, sgngax, dfac, dlnrel, d9lgmc, dgamma, dgamr, dint,
       3  d1mach, dcos, dexp, dlog, dsin, dsqrt
        external d1mach, d9lgmc, dfac, dgamma, dgamr,
       1  dlnrel
        data pi / 3.1415926535 8979323846 2643383279 503 d0 /
        data eps, sqeps / 2*0.0d0 /
  c
        if (eps.ne.0.0d0) go to 10
        eps = d1mach(4)
        sqeps = dsqrt(eps)
  c
   10   ax = a + x
        if (ax.gt.0.0d0) go to 30
        if (dint(ax).ne.ax) go to 30
  c
        if (a.gt.0.0d0 .or. dint(a).ne.a) call seteru (
       1  48hdpoch   a+x is non-positive integer but a is not, 48, 2, 2)
  c
  c we know here that both a+x and a are non-positive integers.
  c
        dpoch = 1.0d0
        if (x.eq.0.d0) return
  c
        n = x
        if (dmin1(a+x,a).lt.(-20.0d0)) go to 20
  c
        ia = a
        dpoch = (-1.0d0)**n * dfac(-ia)/dfac(-ia-n)
        return
  c
   20   dpoch = (-1.0d0)**n * dexp ((a-0.5d0)*dlnrel(x/(a-1.0d0))
       1  + x*dlog(-a+1.0d0-x) - x + d9lgmc(-a+1.0d0) - d9lgmc(-a-x+1.d0))
        return
  c
  c a+x is not zero or a negative integer.
  c
   30   dpoch = 0.0d0
        if (a.le.0.0d0 .and. dint(a).eq.a) return
  c
        n = dabs(x)
        if (dble(float(n)).ne.x .or. n.gt.20) go to 50
  c
  c x is a small non-positive integer, presummably a common case.
  c
        dpoch = 1.0d0
        if (n.eq.0) return
        do 40 i=1,n
          dpoch = dpoch * (a+dble(float(i-1)))
   40   continue
        return
  c
   50   absax = dabs(a+x)
        absa = dabs(a)
        if (dmax1(absax,absa).gt.20.0d0) go to 60
  c
        if (dabs(x).gt.absax/sqeps) call seteru (67hdpoch   answer lt half
       1 precision, a+x cannot be computed accurately, 67, 1, 1)
        dpoch = dgamma(a+x) * dgamr(a)
  c error handling above is probably bad when a almost = -n and when x is
  c small.  maybe use reflection formula below in modified form?
        return
  c
   60   if (dabs(x).gt.0.5d0*absa) go to 70
  c
  c abs(x) is small and both abs(a+x) and abs(a) are large.  thus,
  c a+x and a must have the same sign.  for negative a, we use
  c gamma(a+x)/gamma(a) = gamma(-a+1)/gamma(-a-x+1) *
  c sin(pi*a)/sin(pi*(a+x))
  c
        b = a
        if (b.lt.0.0d0) b = -a - x + 1.0d0
        dpoch = dexp ((b-0.5d0)*dlnrel(x/b) + x*dlog(b+x) - x
       1  + d9lgmc(b+x) - d9lgmc(b) )
  c
        if (a.ge.0.0d0 .or. dpoch.eq.0.0d0) return
        call entsrc (irold, 1)
        cospix = dcos (pi*x)
        call erroff
        sinpix = dsin (pi*x)
        call erroff
        cospia = dcos (pi*a)
        call erroff
        sinpia = dsin (pi*a)
        call erroff
        call entsrc (irold2, irold)
  c
        errpch = dabs(x)*(1.0d0+dlog(b))
        den = cospix + cospia*sinpix/sinpia
        err = (dabs(x)*(dabs(sinpix) + dabs(cospia*cospix/sinpia))
       1  + dabs(a*sinpix)/sinpia**2)*pi
        err = errpch + err/dabs(den)
        if (err.gt.1.0d0/eps) call seteru (73hdpoch   answer has no precis
       1ion, a or a+x too close to a negative integer, 73, 3, 2)
        if (err.gt.1.0d0/sqeps) call seteru (74hdpoch   answer lt half pre
       2cision, a or a+x too close to a negative integer, 74, 2, 1)
  c
        dpoch = dpoch/den
        return
  c
   70   call dlgams (a+x, alngax, sgngax)
        call dlgams (a, alnga, sgnga)
        dpoch = sgngax * sgnga * dexp(alngax-alnga)
  c
        return
        end