Task: Emirp primes




Go: package main

import (
	"flag"
	"fmt"
	"github.com/jbarham/primegen.go" 
	"math"
)



type primeCache struct {
	gen    *primegen.Primegen
	primes []uint64
}

func NewPrimeCache() primeCache {
	g := primegen.New()
	return primeCache{gen: g, primes: []uint64{g.Next()}}
}



func (pc *primeCache) upto(n uint64) []uint64 {
	if p := pc.primes[len(pc.primes)-1]; p <= n {
		for p <= n {
			p = pc.gen.Next()
			pc.primes = append(pc.primes, p)
		}
		return pc.primes[:len(pc.primes)-1]
	}
	for i, p := range pc.primes {
		if p > n {
			return pc.primes[:i]
		}
	}
	panic("not reached")
}

var cache = NewPrimeCache()

func sqrt(x uint64) uint64 { return uint64(math.Sqrt(float64(x))) }



func isprime(n uint64) bool {
	for _, p := range cache.upto(sqrt(n)) {
		if n%p == 0 {
			return false
		}
	}
	return true
}

func reverse(n uint64) (r uint64) {
	for n > 0 {
		r = 10*r + n%10
		n /= 10
	}
	return
}


func isEmirp(n uint64) bool {
	r := reverse(n)
	return r != n && isprime(r)
}


type EmirpGen struct {
	pgen     *primegen.Primegen
	nextn    uint64
	r1l, r1h uint64
	r2l, r2h uint64
	r3l, r3h uint64
}

func NewEmirpGen() *EmirpGen {
	e := &EmirpGen{pgen: primegen.New()}
	e.Reset()
	return e
}

func (e *EmirpGen) Reset() {
	e.pgen.Reset()
	e.nextn = 0
	
	e.r1l, e.r1h = 20, 30
	e.r2l, e.r2h = 40, 70
	e.r3l, e.r3h = 80, 90
}

func (e *EmirpGen) next() (n uint64) {
	for n = e.pgen.Next(); !isEmirp(n); n = e.pgen.Next() {
		
		
		switch {
		case e.r1l <= n && n < e.r1h:
			e.pgen.SkipTo(e.r1h)
		case e.r2l <= n && n < e.r2h:
			e.pgen.SkipTo(e.r2h)
		case e.r3l <= n && n < e.r3h:
			e.pgen.SkipTo(e.r3h)
		case n > e.r3h:
			e.r1l *= 10
			e.r1h *= 10
			e.r2l *= 10
			e.r2h *= 10
			e.r3l *= 10
			e.r3h *= 10
		}
	}
	return
}

func (e *EmirpGen) Next() (n uint64) {
	if n = e.nextn; n != 0 {
		e.nextn = 0
		return
	}
	return e.next()
}

func (e *EmirpGen) Peek() uint64 {
	if e.nextn == 0 {
		e.nextn = e.next()
	}
	return e.nextn
}

func (e *EmirpGen) SkipTo(nn uint64) {
	e.pgen.SkipTo(nn)
	e.nextn = 0
	return
}



type SequenceGen interface {
	Next() uint64
	Peek() uint64
	Reset()
	SkipTo(uint64)
	
}

func main() {
	var start, end uint64
	var n, skip uint
	var oneline, primes bool
	flag.UintVar(&n, "n", math.MaxUint64, "number of emirps to print")
	flag.UintVar(&skip, "skip", 0, "number of emirps to skip")
	flag.Uint64Var(&start, "start", 0, "start at x>=start")
	flag.Uint64Var(&end, "end", math.MaxUint64, "stop at x<=end")
	flag.BoolVar(&oneline, "oneline", false, "output on a single line")
	flag.BoolVar(&primes, "primes", false, "generate primes rather than emirps")
	flag.Parse()

	sep := "\n"
	if oneline {
		sep = " "
	}

	
	var seq SequenceGen
	if primes {
		seq = primegen.New()
	} else {
		seq = NewEmirpGen()
	}

	for seq.Peek() < start {
		seq.Next()
	}
	for ; skip > 0; skip-- {
		seq.Next()
	}
	for ; n > 0 && seq.Peek() <= end; n-- {
		fmt.Print(seq.Next(), sep)
	}
	if oneline {
		fmt.Println()
	}
}







Fortran:       MODULE BAG	
       INTEGER MSG	
       INTEGER PF16LIMIT,PF32LIMIT,NP			
       PARAMETER (PF16LIMIT = 3512, PF32LIMIT = 4793)	
       INTEGER*2 PRIME16(PF16LIMIT)			
       INTEGER*4 PRIME32(PF16LIMIT + 1:PF32LIMIT)	
       DATA NP,PRIME16(1),PRIME16(2)/2,2,3/	
       INTEGER NGP,NNP,NIP	
       DATA NGP,NNP,NIP/3*0/	
       CONTAINS		
        RECURSIVE INTEGER FUNCTION GETPRIME(I)	
Chooses from amongst two arrays, of sizes known from previous work.
         INTEGER I		
         INTEGER P		
         INTEGER MP		
          NGP = NGP + 1		
          IF (I.LE.0) THEN	
            GETPRIME = -666		
          ELSE IF (I.LE.NP) THEN	
            IF (I.LE.PF16LIMIT) THEN		
              GETPRIME = PRIME16(I)		
             ELSE				
              GETPRIME = PRIME32(I)		
            END IF			
          ELSE IF (I.LE.PF32LIMIT) THEN	
            MP = NP			
            P = GETPRIME(NP)		
   10       P = NEXTPRIME(P)		
            MP = MP + 1			
            IF (MP.LT.I) GO TO 10	
            GETPRIME = P		
           ELSE			
            WRITE (MSG,*) "Hic
            STOP "Too far..."		
          END IF		
        END FUNCTION GETPRIME	

        SUBROUTINE STASHPRIME(P)	
         INTEGER P	
          NP = NP + 1		
          IF (NP.LE.PF16LIMIT) THEN	
            PRIME16(NP) = P			
          ELSE IF (NP.LE.PF32LIMIT) THEN
            PRIME32(NP) = P			
          ELSE				
            STOP "Stash overflow
          END IF			
        END SUBROUTINE STASHPRIME	

        INTEGER FUNCTION FINDPRIME(IT)	
         INTEGER IT	
         INTEGER L,R,P	
          L = 0		
          R = NP + 1	
    1     P = (R - L)/2		
          IF (P.LE.0) THEN	
            FINDPRIME = -L		
            RETURN			
          END IF		
          P = P + L		
          IF (IT - GETPRIME(P)) 2,4,3	
    2     R = P; GO TO 1	
    3     L = P; GO TO 1	
    4     FINDPRIME = P		
        END FUNCTION FINDPRIME	

        RECURSIVE INTEGER FUNCTION NEXTPRIME(P)	
Checks the stash in PRIME in the hope of finding the next prime directly, otherwise advances from P.
Collates a stash of primes in PRIME16 and PRIME32, advancing NP from 2 to PF32LIMIT as it goes.
         INTEGER P	
         INTEGER PI	
         INTEGER IT	
          NNP = NNP + 1	
          IF (P.LE.1) THEN	
            PI = 2		
           ELSE			
            IT = (ABS(FINDPRIME(P)))	
            IF (IT.LT.NP) THEN		
              PI = GETPRIME(IT + 1)	
             ELSE	
              IF (NP.LT.PF32LIMIT) THEN	
                PI = GETPRIME(IT)	
               ELSE			
                PI = P			
                IF (MOD(PI,2).EQ.0) PI = PI - 1	
              END IF			
              DO WHILE (PI.LE.P)	
   11           PI = PI + 2			
                IF (.NOT.ISPRIME(PI)) GO TO 11	
                IF (IT.EQ.NP .AND. IT.LT.PF32LIMIT) THEN	
                  CALL STASHPRIME(PI)		
                  IT = IT + 1			
                END IF			
              END DO		
            END IF		
          END IF		
          NEXTPRIME = PI	
        END FUNCTION NEXTPRIME	

        RECURSIVE LOGICAL FUNCTION ISPRIME(N)	
Crunches up to SQRT(N), and at worst needs to be able to reach Prime(4793) = 46349; greater than SQRT(2147483647) = 46340·95...
         INTEGER N	
         INTEGER I,F,Q	
          NIP = NIP + 1	
          IF (N.LT.2) THEN	
            ISPRIME = .FALSE.	
          ELSE			
            ISPRIME = .FALSE.	
            I = 1		
   10       F = GETPRIME(I)	
            Q = N/F		
            IF (Q .GE. F) THEN	
              IF (Q*F .EQ. N) RETURN	
              I = I + 1		
              GO TO 10		
            END IF		
            ISPRIME = .TRUE.	
          END IF		
        END FUNCTION ISPRIME	

        INTEGER FUNCTION ESREVER(IT,BASE)	
         INTEGER IT	
         INTEGER BASE	
         INTEGER N,R	
          IF (BASE.LE.1) STOP "Base 2 at least
          N = IT	
          R = 0		
          DO WHILE(N.GT.0)	
            R = R*BASE + MOD(N,BASE)	
            N = N/BASE			
          END DO		
          ESREVER = R		
        END FUNCTION ESREVER	

        SUBROUTINE EMIRP(BASE,N1,N2,I1,I2)	
         INTEGER BASE	
         INTEGER N1,N2	
         INTEGER I1,I2	
         INTEGER N	
         INTEGER P,R	
          WRITE (MSG,1) N1,N2,BASE,I1,I2	
    1     FORMAT ("Show the first ",I0," to ",I0,	
     &     " emirP numbers (base ",I0,") between ",I0," and ",I0)	
          N = 0		
          P = I1 - 1	
Chase another emirP.
   10     P = NEXTPRIME(P)		
          IF (P.LT.I1) GO TO 10		
          IF (P.GT.I2) GO TO 900	
          R = ESREVER(P,BASE)		
          IF (P .EQ. R) GO TO 10	
          IF (.NOT.ISPRIME(R)) GO TO 10	
          N = N + 1			
c          if (mod(n,100) .eq. 0) then
c            write (6,66) N,P,R,NP,NGP,NNP,NIP
c   66       format ("N=",I5,",p=",I6,",R=",I6,",NP=",I6,3I12)
c          end if
          IF (N.GE.N1) WRITE (6,*) P,R	
          IF (N.LT.N2) GO TO 10		
Closedown.
  900     WRITE (MSG,901) NP,GETPRIME(NP)	
  901     FORMAT ("Stashed up to Prime(",I0,") = ",I0,/)
        END SUBROUTINE EMIRP	
      END MODULE BAG	

      PROGRAM POKE	
      USE BAG		
      MSG = 6		

      CALL EMIRP(10,    1,   20,   1,   1000)	
      CALL EMIRP(10,    1,   28,7700,   8000)	
      CALL EMIRP(10,10000,10000,   1,1000000)	

      END