Task: Primality by Wilson's theorem



C#: using System;
using System.Linq;
using System.Collections;
using static System.Console;
using System.Collections.Generic;
using BI = System.Numerics.BigInteger;

class Program {

  
    const int fst = 120, skp = 1000, max = 1015; static double et1, et2; static DateTime st;
    static string ms1 = "Wilson's theorem method", ms2 = "Sieve of Eratosthenes method", 
       fmt = "--- {0} ---\n\nThe first {1} primes are:", fm2 = "{0} prime thru the {1} prime:";
    static List<int> lst = new List<int>();

  
    static void Dump(int s, int t, string f) {
        foreach (var item in lst.Skip(s).Take(t)) Write(f, item); WriteLine("\n"); }

  
    static string Ord(int x, string fmt = "{0:n0}") {
      var y = x % 10; if ((x % 100) / 10 == 10 || y > 3) y = 0;
      return string.Format(fmt, x) + "thstndrd".Substring(y << 1, 2); }

  
    static void ShowOne(string title, ref double et) {
        WriteLine(fmt, title, fst); Dump(0, fst, "{0,-3} ");
        WriteLine(fm2, Ord(skp), Ord(max)); Dump(skp - 1, max - skp + 1, "{0,4} ");
        WriteLine("Time taken: {0}ms\n", et = (DateTime.Now - st).TotalMilliseconds); }

  
    static BI factorial(int n) { BI res = 1; if (n < 2) return res;
        while (n > 0) res *= n--; return res; }

    static bool WTisPrimeSA(int n) { return ((factorial(n - 1) + 1) % n) == 0; }

    static BI[] facts;

    static void initFacts(int n) {
        facts = new BI[n]; facts[0] = facts[1] = 1;
        for (int i = 1, j = 2; j < n; i = j++)
            facts[j] = facts[i] * j; }

    static bool WTisPrime(int n) { return ((facts[n - 1] + 1) % n) == 0; }
  

    static void Main(string[] args) { st = DateTime.Now;
        BI f = 1; for (int n = 2; lst.Count < max; f *= n++) if ((f + 1) % n == 0) lst.Add(n);
        ShowOne(ms1, ref et1);
        st = DateTime.Now; int lmt = lst.Last(); lst.Clear(); BitArray flags = new BitArray(lmt + 1);
        for (int n = 2; n <= lmt; n+=n==2?1:2) if (!flags[n]) {
                lst.Add(n); for (int k = n * n, n2=n<<1; k <= lmt; k += n2) flags[k] = true; }
        ShowOne(ms2, ref et2);
        WriteLine("{0} was {1:0.0} times slower than the {2}.", ms1, et1 / et2, ms2);

      
        WriteLine("\n" + ms1 + " stand-alone computation:");
        WriteLine("factorial computed for each item");
        st = DateTime.Now;
        for (int x = lst[skp - 1]; x <= lst[max - 1]; x++) if (WTisPrimeSA(x)) Write("{0,4} ", x);
        WriteLine(); WriteLine("\nTime taken: {0}ms\n", (DateTime.Now - st).TotalMilliseconds);

        WriteLine("factorials precomputed up to highest item");
        st = DateTime.Now; initFacts(lst[max - 1]);
        for (int x = lst[skp - 1]; x <= lst[max - 1]; x++) if (WTisPrime(x)) Write("{0,4} ", x);
        WriteLine(); WriteLine("\nTime taken: {0}ms\n", (DateTime.Now - st).TotalMilliseconds);
    }
}


Go: package main

import (
    "fmt"
    "math/big"
)

var (
    zero = big.NewInt(0)
    one  = big.NewInt(1)
    prev = big.NewInt(factorial(20))
)


func factorial(n int64) int64 {
    res := int64(1)
    for k := n; k > 1; k-- {
        res *= k
    }
    return res
}



func wilson(n int64, memo bool) bool {
    if n <= 1 || (n%2 == 0 && n != 2) {
        return false
    }
    if n <= 21 {
        return (factorial(n-1)+1)%n == 0
    }
    b := big.NewInt(n)
    r := big.NewInt(0)
    z := big.NewInt(0)
    if !memo {
        z.MulRange(2, n-1) 
    } else {
        prev.Mul(prev, r.MulRange(n-2, n-1)) 
        z.Set(prev)
    }
    z.Add(z, one)
    return r.Rem(z, b).Cmp(zero) == 0    
}

func main() {
    numbers := []int64{2, 3, 9, 15, 29, 37, 47, 57, 67, 77, 87, 97, 237, 409, 659}
    fmt.Println("  n  prime")
    fmt.Println("---  -----")
    for _, n := range numbers {
        fmt.Printf("%3d  %t\n", n, wilson(n, false))
    }

    
    fmt.Println("\nThe first 120 prime numbers are:")
    for i, count := int64(2), 0; count < 1015; i += 2 {
        if wilson(i, true) {
            count++
            if count <= 120 {
                fmt.Printf("%3d ", i)
                if count%20 == 0 {
                    fmt.Println()
                }
            } else if count >= 1000 {
                if count == 1000 {
                    fmt.Println("\nThe 1,000th to 1,015th prime numbers are:") 
                }
                fmt.Printf("%4d ", i)
            }            
        }
        if i == 2 {
            i--
        }
    }
    fmt.Println()    
}