Listing 1 Deriving from the GThread Class

[Serializable]
class CustomGridThread : GThread {
    public override void Start() {  }
}


Listing 2 Plouffe-Bellard Calculation Class in C#

public class Plouffe_Bellard
{
    public Plouffe_Bellard() {}
    private static int mul_mod(int a, int b, int m) {
        return (int) (((long) a * (long) b) % m);
    }
    private static int inv_mod(int x, int y) {
        int q,u,v,a,c,t;
        u=x; v=y; c=1; a=0;
        do {
            q=v/u; t=c; c=a-q*c; 
            a=t; t=u; u=v-q*u; v=t;
        } while (u!=0);
        a=a%y;
        if (a<0) {
            a=y+a;
        }
        return a;
    }
    private static int pow_mod(int a, int b, int m) {
        int r, aa;
        r=1; aa=a;
        while (true) {
            if ((b & 1) != 0) 
                r = mul_mod(r, aa, m);
            b = b >> 1;
            if (b == 0) break;    
            aa = mul_mod(aa, aa, m);
        }
        return r;
    }
    private static bool is_prime(int n) {
        if ((n % 2) == 0)
            return false;
        int r = (int) Math.Sqrt(n);
        for (int i = 3; i <= r; i += 2) {
            if ((n % i) == 0)
                return false;
        }
        return true;
    }
    private static int next_prime(int n) {
        do {
            n++;
        } while (!is_prime(n));
        return n;
    }
    public String CalculatePiDigits(int n) {
        int av, vmax, num, den, s, t;
        int N = (int) ((n + 20) * Math.Log(10) / Math.Log(2));
        double sum = 0;
        for (int a = 3; a <= (2 * N); a = next_prime(a)) {
            vmax = (int) (Math.Log(2 * N) / Math.Log(a));
            av = 1;
            for (int i = 0; i < vmax; i++) {
                av = av * a;
            }
            s = 0; num = 1; den = 1;
            int v = 0;
            int kq = 1;
            int kq2 = 1;
            for (int k = 1; k <= N; k++) {
                t = k;
                if (kq >= a) {
                    do {
                        t = t / a;
                        v--;
                    } while ((t % a) == 0);
                    kq = 0;
                }
                kq++;
                num = mul_mod(num, t, av);
                t = 2 * k - 1;
                if (kq2 >= a) {
                    if (kq2 == a) {
                        do {
                            t = t / a;
                            v++;
                        } while ((t % a) == 0);
                    }
                    kq2 -= a;
                }
                den = mul_mod(den, t, av);
                kq2 += 2;
                if (v > 0) {
                    t = inv_mod(den, av);
                    t = mul_mod(t, num, av);
                    t = mul_mod(t, k, av);
                    for (int i = v; i < vmax; i++){
                        t = mul_mod(t, a, av);
                    }
                    s += t;
                    if (s >= av) s -= av;
                }
            }
            t = pow_mod(10, n - 1, av);
            s = mul_mod(s, t, av);
            sum = (sum + (double) s / (double) av) % 1.0;
        }
        int Result = (int) (sum * 1e9);
        String StringResult = String.Format("{0:D9}", Result);
        return StringResult;
    }
}


Listing 3 GThread Implementation Using the C# Calculation Class

public class PiCalcGridThread : GThread
{
    private int _StartDigitNum;
    private int _NumDigits;
    private string _Result;
    public int StartDigitNum
    { get { return _StartDigitNum ; }   }
    public int NumDigits
    { get { return _NumDigits; }  }
    public string Result
    { get { return _Result; }  }
    public PiCalcGridThread(int startDigitNum, int numDigits) {
        _StartDigitNum = startDigitNum; _NumDigits = numDigits;
    }
    public override void Start()  {
        StringBuilder temp = new StringBuilder();
        Plouffe_Bellard pb = new Plouffe_Bellard();
        for (int i = 0; 
             i <= Math.Ceiling((double)_NumDigits / 9); i++) {
            temp.Append(pb.CalculatePiDigits(_StartDigitNum+(i * 9)));
        }
        _Result = temp.ToString().Substring(0, _NumDigits);
    }
}


Listing 4 PiCalcGridThread Instantiation

for (int i = 0; i < NumThreads; i++){
  int StartDigitNum = 1 + (i*DigitsPerThread);
  int DigitsForThisThread = Math.Min(DigitsPerThread,
      NumberOfDigits - i * DigitsPerThread);
    PiCalcGridThread thread = new PiCalcGridThread(
      StartDigitNum,
      DigitsForThisThread
      );
    App.Threads.Add(thread);
}


Listing 5 pb.fsi

module pb
val CalculatePiDigits: int -> string


Listing 6 pb.fs Test Code

module pb
open System
let CalculatePiDigits (n:int) = 
      string.Format("{0}11111111", n.ToString())


Listing 7 Pi Calculation Thread Using F# Module

public override void Start(){
    StringBuilder temp = new StringBuilder();
        for (int i = 0; 
             i <= Math.Ceiling((double)_NumDigits / 9); i++) {
        temp.Append(pb.CalculatePiDigits(_StartDigitNum + (i * 9)));
    }
    _Result = temp.ToString().Substring(0, _NumDigits);
} 


Listing 8 Adding F# File Dependencies

Module PbMod = typeof(pb).Module;
App.Manifest.Add(new EmbeddedFileDependency(
PbMod.Name, PbMod.FullyQualifiedName));
Module FsMod = typeof(Microsoft.FSharp.Math.Matrix).Module;
App.Manifest.Add(new EmbeddedFileDependency(
FsMod.Name, FsMod.FullyQualifiedName));
Module MlMod = typeof(Microsoft.FSharp.MLLib.Arg).Module;
App.Manifest.Add(new EmbeddedFileDependency(
MlMod.Name, MlMod.FullyQualifiedName));


Listing 9 Adding F# File Dependencies with the standalone option

Module PbMod = typeof(pb).Module;
App.Manifest.Add(new EmbeddedFileDependency(
PbMod.Name, PbMod.FullyQualifiedName));


Listing 10 Plouffe-Bellard Module in F#

module pb
open System
let inline is_prime(n) =
  let mutable ret = true in
  if (n%2) = 0 then ret <- false
  else begin
    let r = Int32.of_float(sqrt(Float.of_int(n))) in
    let mutable i = 3 in
    while i <= r && ret do
      if (n % i) = 0 then ret <- false;
      i <- i + 2
    done;
  end;
  ret
let inline next_prime (a) =
  let mutable n = a in
  n <- n + 1;
  while not(is_prime(n))  do
    n <- n + 1;
  done;
  n
let inline inv_mod( x, y )  =
  let mutable q = 0 in
  let mutable u = 0 in
  let mutable v = 0 in
  let mutable a = 0 in
  let mutable c = 1 in
  let mutable t = 0 in
  u <- x;  v <- y;  q <- v/u;
  t <- c;  c <- a-q*c;  a <- t;
  t <- u;  u <- v-q*u;  v <- t;
  while not(u=0) do
    q <- v/u;  t <- c; c <- a-q*c;
    a <- t; t <- u;  u <- v-q*u;  v <- t;
  done;
  a <- a%y;
  if (a<0) then a<-y+a;
  a
let inline mul_mod( a, b, c ) = (a*b) % c
let inline pow_mod( (a), (inb), (m)) =
  let mutable r = 1 in
  let mutable aa = 0 in
  let mutable run = true in
  let mutable b = 0 in
  b <- inb;
  aa <- a;
  while run do
    if not((b &&& 1) = 0) then r <- mul_mod(r, aa, m);
    b <- b >>> 1;
    if (b = 0) then run <- false
    else aa <- mul_mod(aa, aa, m)
  done;
  r
let CalculatePiDigits (n:int) =
  let mutable av = 0 in
  let mutable vmax = 0 in
  let mutable sum = 0.0 in	
  let N = Int32.of_float(
      Float.of_int(n+20) * (log(10.0) / log(2.0))) in
  let mutable a = 3 in
  let mutable i = 0 in
  let mutable s = 0 in
  let mutable t = 0 in
  let mutable num = 0 in
  let mutable den = 0 in
  while a <= 2*N do
    vmax <- Int32.of_float( log(Float.of_int(2*N)) /
      log(Float.of_int(a)) );
    av <- 1; i <- 0;
    while i < vmax do
      av <- av * a;  i <- i + 1
    done;
    s <- 0;  num <- 1;  den <- 1;
    let mutable v = 0 in
    let mutable k = 1 in
    let mutable kq = 1 in
    let mutable kq2 = 1 in
    while k <= N do
      t <- k;
      if (kq >= a) then begin
        t <- t / a; v <- v - 1;
        while ((t % a) = 0) do
          t <- t / a; v <- v - 1;
        done;
        kq <- 0
      end;
      kq <- kq + 1;
      num <- mul_mod(num, t, av);
      t <- 2 * k - 1;
      if (kq2 >= a) then begin
        if (kq2 = a) then begin
          t <- t / a; v <- v + 1;
          while ((t % a) = 0) do
            t <- t / a; v <- v + 1;
          done;
        end;
        kq2 <- kq2 - a;
      end;
      den <- mul_mod(den, t, av);
      kq2 <- kq2 + 2;
      if (v > 0) then begin
        t <- inv_mod(den, av);
        t <- mul_mod(t, num, av);
        t <- mul_mod(t, k, av);
        i <- v;
        while i < vmax do
          t <- mul_mod(t, a, av);
          i <- i + 1;
        done;
        s <- s + t;
        if (s >= av) then s <- (s - av);
      end;
      k <- k + 1;
    done;
    t <- pow_mod(10, n - 1, av);
    s <- mul_mod(s, t, av);
    sum <- (sum + Float.of_int(s) / Float.of_int(av)) % 1.0;
    a <- next_prime(a)
  done;
  let Result = Int32.of_float(sum * 1e9) in
  string.Format("{0:D9}", Result)


Listing 11 pb.fsi with GThread declaration

module pb
open Alchemi.Core.Owner;;
val CalculatePiDigits: int -> string
type FsPiCalcGThread = 
  class
    inherit GThread
    val _StartDigitNum : int;
    val _NumDigits : int;
    val mutable Result : string;
    new : int * int->FsPiCalcGThread
  end


Listing 12 F# GThread implementation

[<Serializable>]
type FsPiCalcGThread = 
  class
    inherit GThread
    val _StartDigitNum : int;
    val _NumDigits : int;
    val mutable Result : string;
    new(startDigitNum, numDigits) as x = {
         _StartDigitNum=startDigitNum; 
        _NumDigits=numDigits; 
        Result=String.Empty; }
    override x.Start() =
    begin
      let mutable i = 0 in
      let mutable str = String.Empty in
      let temp = new StringBuilder() in
      while i <= Int32.of_float(Math.Ceiling(
          Float.of_int(x._NumDigits) / 9.0)) do				
        str <- CalculatePiDigits(
        x._StartDigitNum + (i * 9));
        temp.Append(str);
        i <- i + 1;
      done;
      str <- temp.ToString();
      x.Result <- str.Substring(0,x._NumDigits);
    end;
  end
 

Listing 13 main.fs

#I @"C:\Products\other\alchemi\Alchemi-1.0.4-sdk\bin";;
#r @"Alchemi.Core.dll";;
open System
open System.Text
open pb
open Alchemi.Core;;
open Alchemi.Core.Owner;;
let mutable NumThreads = 10
let DigitsPerThread = 10
let NumberOfDigits = NumThreads * DigitsPerThread
let mutable StartTime = DateTime.Now
let App = new GApplication(false);;
let ThreadFinished(thread : GThread) =
  Console.WriteLine("grid thread # {0} finished executing", 
        thread.Id)
let AppFinished() = 
  let result = new StringBuilder() in
  let mutable i = 0 in
  while i < App.Threads.Count do
    let pcgt = App.Threads.Item(i) :?> pb.FsPiCalcGThread in
    result.Append(pcgt.Result);
    i <- i + 1
  done;
  Console.WriteLine(
        "===\nThe value of Pi to {0} digits 
        is:\n3.{1}\n===\nTotal time taken = {2}\n===",
        NumberOfDigits, result,
        DateTime.Now.Subtract(StartTime));
  Console.WriteLine("Application Finished")
;;
let _ =
  Console.WriteLine("[Pi Calculator Grid Application]\n
       --------------------------------\n");
  Console.WriteLine("Press <enter> to start ...");
  Console.ReadLine();
  try	
    begin
      // get the number of digits from the user
      let mutable numberOfDigitsEntered = false in
      // get settings from user
      let gc = GConnection.FromConsole(
        "localhost", "9000", "user", "user") in
      // create a new grid application
      StartTime <- DateTime.Now;	
      App.Connection <- gc;
      // Add our exe name due to F# changes to module name	
      let PbMod = (type FsPiCalcGThread).Module in
      App.Manifest.Add(new EmbeddedFileDependency(
        PbMod.Name, PbMod.FullyQualifiedName));
      NumThreads <- Int32.of_float(Math.Floor(
        Float.of_int(NumberOfDigits) / 
        Float.of_int(DigitsPerThread)));
      if (DigitsPerThread * NumThreads < NumberOfDigits)
        then NumThreads <- NumThreads + 1;
      let mutable i = 0 in
      i <- 0;
      while i < NumThreads do
        let StartDigitNum = 1 + (i*DigitsPerThread) in
        let DigitsForThisThread = 
          Int32.of_float(Math.Min(
          Float.of_int(DigitsPerThread), 
          Float.of_int(NumberOfDigits - i *
          DigitsPerThread))) in
        Console.WriteLine(
          "starting a thread to calculate 
          the digits of pi from {0} to {1}",
            StartDigitNum, StartDigitNum + 
            DigitsForThisThread - 1);
        let thread = new pb.FsPiCalcGThread(
          StartDigitNum, DigitsForThisThread) in
        App.Threads.Add(thread);
        i <- i + 1
      done;
      App.add_ThreadFinish( 
        new GThreadFinish(fun t ->ThreadFinished( t )));
      App.add_ApplicationFinish( 
        new GApplicationFinish(fun e ->AppFinished(e)));
      App.Start();
    end;
  finally
    Console.ReadLine();
    App.Stop();	


Listing 14 Revised is_prime and next_prime functions

let is_prime n = 
  (n%2 > 0) && 
  let r = Float.to_int(Math.Sqrt(float(n))) in
  let rec check i = (i > r) or (n % i > 0) && check (i+2) in 
  check 3  
let rec next_prime a =
  let n = a+1 in 
  if is_prime n then n else next_prime(n);;