object Pi { def main() : Unit = { if(new Computer().computePi()) { println("Ok"); } else { println("error"); } } } class Computer { def computePi() : Bool = { var j : Int; var value : Frac; var inter : Real; println("First method"); println("************"); value = new Frac().init(0,1); j = 0; while(j < 3) { println(value.toString() + " ~= " + new Real().init(0,10).evalFrac(value).toString()); value = value.plus(this.getTerm(j)); j = j + 1; } println(value.toString() + " ~= " + new Real().init(0,10).evalFrac(value).toString()); println(""); println("Second method"); println("*************"); value = new Frac().init(0,1); inter = new Real().init(0,10).evalFrac(value); j = 0; while(j < 7) { println(inter.toString()); value = this.getTerm(j); inter = inter.plus(new Real().init(0,10).evalFrac(value)); j = j + 1; } println(inter.toString()); return true; } def getTerm(i : Int) : Frac = { var par : Frac; var first : Frac; var second : Frac; var third : Frac; var fourth : Frac; first = new Frac().init(4, 8 * i + 1); second = new Frac().init(2, 8 * i + 4); third = new Frac().init(1, 8 * i + 5); fourth = new Frac().init(1, 8 * i + 6); par = first.minus(second).minus(third).minus(fourth); return par.times(new Frac().init(1, this.sixteenPow(i))); } def sixteenPow(n : Int) : Int = { var res : Int; var i : Int; res = 1; i = 0; while(i < n) { i = i + 1; res = res * 16; } return res; } } class Frac { var numerator : Int; var denominator : Int; var sign : Bool; // true means positive. var util : Util; def init(n : Int, d : Int) : Frac = { util = new Util(); numerator = util.abs(n); denominator = util.abs(d); sign = (n < 0 && d < 0 || (0 < n || n == 0) && (0 < d || d == 0)); return this.simplify(); } def getNumerator() : Int = { return numerator; } def getDenominator() : Int = { return denominator; } def setPos(positive : Bool) : Frac = { sign = positive; return this; } def isPos() : Bool = { return sign; } def simplify() : Frac = { var gcd_ : Int; if(!(numerator == 0) && !(denominator == 0)) { gcd_ = util.gcd(numerator, denominator); if(!(gcd_ == 1)) { numerator = numerator / gcd_; denominator = denominator / gcd_; } } return this; } def plus(other : Frac) : Frac = { var lcm : Int; var lfac : Int; var rfac : Int; lcm = util.lcm(denominator, other.getDenominator()); lfac = lcm / denominator; if(!sign) { lfac = 0 - lfac; } rfac = lcm / other.getDenominator(); if(!other.isPos()) { rfac = 0 - rfac; } return (new Frac()).init((lfac * numerator) + (rfac * other.getNumerator()), lcm); } def minus(other : Frac) : Frac = { return this.plus(other.negative()); } def times(other : Frac) : Frac = { return (new Frac()).init(numerator * other.getNumerator(), denominator * other.getDenominator()).simplify().setPos(this.isPos() && other.isPos() || !this.isPos() && !other.isPos()); } def divided(other : Frac) : Frac = { return this.times(other.inverse()); } def inverse() : Frac = { return (new Frac()).init(denominator, numerator); } def negative() : Frac = { return (new Frac()).init(numerator, denominator).setPos(false); } def toString() : String = { var result : String; if(sign) { result = ""; } else { result = "-"; } return result + numerator + "/" + denominator; } } // represents real numbers as a number plus an array containing the digits class Real { var integerPart : Int; var digits : Int[]; var util : Util; def init(intPart : Int, digitsCount: Int): Real = { var i : Int; util = new Util(); integerPart = intPart; digits = new Int[digitsCount]; i = 0; while(i < digitsCount) { digits[i] = 0; i = i + 1; } return this; } def getDigits() : Int[] = { return digits; } def getIntegerPart() : Int = { return integerPart; } def setIntegerPart(p : Int) : Real = { integerPart = p; return this; } def evalFrac(frac : Frac) : Real = { var leftover : Int; var i : Int; var den : Int; den = frac.getDenominator(); integerPart = frac.getNumerator() / den; if(!frac.isPos()) { integerPart = 0 - integerPart; } leftover = util.mod(frac.getNumerator(), den); i = 0; while(i < digits.length) { leftover = 10 * leftover; digits[i] = leftover / den; leftover = util.mod(leftover, den); i = i + 1; } return this; } // note that this only works for positive reals def plus(other : Real) : Real = { var len : Int; var od : Int[]; var resDig : Int[]; var carry : Int; var i : Int; var sum : Int; var result : Real; od = other.getDigits(); // taking the max length ensures that it will crash if they don't match :P if(digits.length < od.length) { len = od.length; } else { len = digits.length; } result = new Real().init(0, len); resDig = result.getDigits(); carry = 0; i = len - 1; while(!(i < 0)) { sum = digits[i] + od[i] + carry; carry = sum / 10; //println(digits[i] + " + " + od[i] + " = " + sum + "(" + carry + ")"); resDig[i] = util.mod(sum, 10); i = i - 1; } return result.setIntegerPart(integerPart + other.getIntegerPart() + carry); } def toString() : String = { var ret : String; var i : Int; ret = "" + integerPart + "."; i = 0; while(i < digits.length) { ret = ret + digits[i]; i = i + 1; } return ret; } } // Some useful stuff class Util { def abs(v : Int) : Int = { var res : Int; if(!(v < 0)) { res = v; } else { res = 0 - v; } return res; } def gcd(m_ : Int, n_ : Int) : Int = { var t : Int; var r : Int; var result : Int; var m : Int; var n : Int; m = this.abs(m_); n = this.abs(n_); if (m < n) { t = m; m = n; n = t; } r = this.mod(m,n); // m % n; if (r == 0) { result = n; } else { result = this.gcd(n, r); } return result; } def lcm(m : Int, n : Int) : Int = { return (n*m) / this.gcd(n,m); } def mod(m : Int, n : Int) : Int = { return m - (n * (m / n)); } }