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()
	}
}








Ada: with Ada.Text_IO, Miller_Rabin;

procedure Emirp_Gen is
   
   type Num is range 0 .. 2**63-1; 
   
   MR_Iterations: constant Positive := 25; 
     
     
   
   function Is_Emirp(E: Num) return Boolean is
      package MR is new Miller_Rabin(Num); use MR;
      
      function Rev(E: Num) return Num is
	 N: Num := E;
	 R: Num := 0;
      begin
	 while N > 0 loop
	    R := 10*R + N mod 10; 
	    N := N / 10;          
	 end loop;
	 return R;
      end Rev;
      
      R: Num := Rev(E); 
   begin
      return E /= R and then
	     (Is_Prime(E, MR_Iterations) = Probably_Prime) and then
	     (Is_Prime(R, MR_Iterations) = Probably_Prime);
   end Is_Emirp;
	
   function Next(P: Num) return Num is
      N: Num := P+1;
   begin
      while not (Is_Emirp(N)) Loop
	 N := N + 1;
      end loop;
      return N;
   end Next;
   
   Current: Num;
   Count: Num := 0;
   
begin
   
   Ada.Text_IO.Put("First 20 emirps:");
   Current := 1;
   for I in 1 .. 20 loop
      Current := Next(Current);
      Ada.Text_IO.Put(Num'Image(Current));
   end loop;
   Ada.Text_IO.New_Line;
   
   
   Ada.Text_IO.Put("Emirps between 7700 and 8000:");
   Current := 7699;
   loop
      Current := Next(Current);
      exit when Current > 8000;
       Ada.Text_IO.Put(Num'Image(Current));
   end loop;
   
   
   Ada.Text_IO.Put("The 10_000'th emirp:");
   for I in 1 .. 10_000 loop
      Current := Next(Current);
   end loop;
   Ada.Text_IO.Put_Line(Num'Image(Current));
end Emirp_Gen;