subroutine aptpfft (ifact, npmax, iprime, ipow, np, nerr)

ccbeg.
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c                             SUBROUTINE APTPFFT
c
c     call aptpfft (ifact, npmax, iprime, ipow, np, nerr)
c
c     Version:  aptpfft  Updated    2003 September 26 14:00.
c               aptpfft  Originated 2003 September 26 14:00.
c
c     Authors:  Arthur L. Edwards, LLNL, L-298, Telephone (925) 422-4123.
c
c
c     Purpose:  For the factorial function ifact!, find all of the prime factors
c               iprime(n), and their powers ipow(n), n = 1, np <= npmax, such
c               that if np is not limited by npmax,
c               ifact! = product {iprime(n)^ipow(n)}, n = 1, np,
c               with iprime(np) <= ifact.
c
c               Flag nerr indicates any input error or limited results.
c
c     Input:    ifact, npmax
c
c     Output:   iprime, np, nerr
c
c     Calls: (none) 
c
c     Glossary:
c
c     ifact     Input    The argument of the factorial function ifact!, for
c                          which all prime factors and their powers are to be
c                          found, up to a limit of npmax prime factors.
c                          Unless limited by npmax, the largest prime factor
c                          will be the largest one less than or equat to ifact.
c                          If np is not limited by npmax,
c                          ifact! = product {iprime(n)^ipow(n)}, n = 1, np,
c                          with iprime(np) <= ifact.
c
c     ipow(n)   Output   The power of prime factor iprime(n).
c                          Size at least npmax.
c
c     iprime(n) Output   The n'th prime number.  Size at least npmax.
c                          None will be returned if ifact < 1 (nerr = 1) or
c                          npmax < 1 (nerr = 2).
c
c                          The density of prime numbers from 1 to iprime(n) is
c                          d = n/iprime(n).  For large iprime(n),
c                          d ~ dlim = 1/ln(iprime(n)), and
c                          n ~ nlim = iprime(n)/ln (iprime(n)), and
c                          d/dlim = n/nlim = n*ln(iprime(n))/iprime(n).
c
c                                           d =       dlim =        d/dlim =
c                               n  iprime   n/iprime  1/ln(iprime)  n/nlim
c                           -----  ------   --------  ------------  --------
c                               1       1   1.000     infinite      0.000
c                               2       2   1.000     1.443         0.683
c                               3       3   1.000     0.910         1.099
c                               4       5   0.800     0.621         1.288
c                               5       7   0.714     0.514         1.390
c                              10      23   0.435     0.319         1.363
c                              30     109   0.275     0.213         1.291
c                             100     523   0.191     0.160         1.197
c                             300    1979   0.152     0.132         1.150
c                            1000    7907   0.126     0.111         1.135
c                            3000   27437   0.109     0.098         1.117
c                           10000  104723   0.095     0.087         1.104
c                           30000  350351   0.086     0.078         1.093
c
c     nerr      Output   Indicates an input error, if not zero:
c                         -1 if npmax prime numbers and their powers are found
c                            without reaching the highest prime number not
c                            exceeding ifact.
c                          1 if ifact is less than 1.
c                          2 if npmax is less than 1.
c
c     npmax     Input    The maximum number of sequential prime numbers to find,
c                          from 1 up to but not exceeding ifact.
c                          For large ifact, the necessary npmax is at least
c                          nlim = iprime/ln (iprime).  See the table under
c                          "iprime(n)" above for factors n/nlim to estimate a
c                          sufficient value of npmax.
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
ccend.

c.... Declarations for arguments.

      integer ifact                   ! Argument of factorial function.
      integer ipow(1)                 ! An array of up to npmax powers.
      integer iprime(1)               ! An array of up to npmax prime numbers.
      integer np                      ! The actual number of prime numbers.
      integer npmax                   ! Maximum number of prime numbers allowed.
      integer nerr                    ! Indicates error, if not zero.

c.... Declarations for local variables.

      integer int                     ! A number to be tested.
      integer i                       ! Index of preceding prime number.
      integer iadd                    ! Integer added to ipow.
      integer n                       ! Index of current prime number.
      integer nterm                   ! Term in addition to ipow.

cbugc***DEBUG begins.
cbug 9901 format (/ 'aptpfft finding prime factors and powers of'
cbug     &  ' factorial',i13 /
cbug     $  'but no more than',i13,' prime factors.' )
cbug      write ( 3, 9901) ifact, npmax
cbugc***DEBUG ends.

c.... Initialize.

      nerr = 0
      np   = 0

      if (npmax .gt. 0) then
        do 100 n = 1, npmax
          iprime(n) = -999999999
          ipow(n)   = -999999999
  100   continue
      endif

c.... Test for input errors.

      if (ifact .lt. 1) then
        nerr = 1
        go to 210
      endif

      if (npmax .lt. 1) then
        nerr = 2
        go to 210
      endif

c.... Set the first prime factor and its power to 1.

      np        = 1
      iprime(1) = 1
      ipow(1)   = 1
      if (ifact .eq. 1) go to 210
      if (npmax .eq. 1) go to 210

c.... Set the second prime factor to 2, and find its power.

      np        = 2
      iprime(2) = 2
      ipow(2)   = 0
      nterm     = 0
  105 nterm     = nterm + 1
      iadd      = ifact / iprime(2)**nterm
      ipow(2)   = ipow(2) + iadd
      if (iadd .gt. 0) go to 105

      if (ifact .eq. 2) go to 210
      if (npmax .eq. 2) go to 210

c.... Loop over higher integers to find prime numbers and powers.

      int = 2
  110 int = int + 1

c.... See if maximum prime number has been reached.

      if (int .gt. ifact) go to 210

c.... See if the current test integer has any prime factors among the prime
c....   numbers less than the square root of the integer.

      do 120 i = 2, np
        if (iprime(i)**2 .gt. int) go to 130        ! Integer int is prime.
        if (mod (int, iprime(i)) .eq. 0) go to 110  ! Integer int is not prime.
  120 continue

c.... The current test integer is prime.

  130 np         = np + 1
      iprime(np) = int

c.... Find the power for this prime.

      ipow(np)   = 0
      nterm      = 0
  140 nterm      = nterm + 1
      iadd       = ifact / iprime(np)**nterm
      ipow(np)   = ipow(np) + iadd
      if (iadd .gt. 0) go to 140

c.... See if npmax primes have been found.

      if (np .lt. npmax) go to 110

c.... Reached npmax without reaching largest prime not exceeding ifact.

      nerr = -1

  210 continue
cbugc***DEBUG begins.
cbug 9902 format (/ 'aptpfft found',i12,' primes and powers.  nerr =',
cbug     &  i3,'.' //
cbug     &          '           np       iprime         ipow' / )
cbug 9903 format (3i13)
cbug      write ( 3, 9902) np, nerr
cbug      if (nerr .le. 0) then
cbug        write ( 3, 9903) (i, iprime(i), ipow(i), i = 1, np)
cbug      endif
cbugc***DEBUG ends.
      return

c.... End of subroutine aptpfft.      (+1 line.)
      end

UCRL-WEB-209832