# LARA

```program Pi {
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));
}
}```