RosettaCodeData/Task/Arithmetic-Rational/Ballerina/arithmetic-rational.ballerina

157 lines
3.6 KiB
Plaintext

import ballerina/io;
function gcd(int num, int den) returns int {
int n = num; // make mutable
int d = den; // ditto
while d != 0 {
int t = d;
d = n % d;
n = t;
}
return n;
}
class Frac {
int num;
int den;
function init(int num, int den) {
int n = num; // make mutable
int d = den; // ditto
if n == 0 {
d = 1;
} else if d < 0 {
n = -n;
d = -d;
}
int g = gcd(n, d).abs();
if g > 1 {
n /= g;
d /= g;
}
self.num = n;
self.den = d;
}
function fromInt(int i) returns Frac {
return new Frac(i, 1);
}
function neg() returns Frac {
return new Frac(-self.num, self.den);
}
function inv() returns Frac {
return new Frac(self.den, self.num);
}
function copy() returns Frac {
return new Frac(self.num, self.den);
}
function abs() returns Frac {
if self.num >= 0 { return self.copy(); }
return self.neg();
}
function add(Frac other) returns Frac {
return new Frac(self.num * other.den + self.den * other.num, self.den * other.den);
}
function sub(Frac other) returns Frac {
return self.add(other.neg());
}
function mul(Frac other) returns Frac {
return new Frac(self.num * other.num, self.den * other.den);
}
function div(Frac other) returns Frac {
return new Frac(self.num * other.den, self.den * other.num);
}
function toFloat() returns float {
return <float>self.num / <float>self.den;
}
function toInt() returns int {
float f = self.toFloat();
f = f >= 0.0 ? f.floor() : f.ceiling();
return <int>f;
}
function idiv(Frac other) returns Frac {
return new Frac(self.toInt(), 1);
}
function mod(Frac other) returns Frac {
return self.sub(self.idiv(other).mul(other));
}
function lt(Frac other) returns boolean {
return self.toFloat() < other.toFloat();
}
function le(Frac other) returns boolean {
return self.toFloat() <= other.toFloat();
}
function gt(Frac other) returns boolean {
return self.toFloat() > other.toFloat();
}
function ge(Frac other) returns boolean {
return self.toFloat() >= other.toFloat();
}
function eq(Frac other) returns boolean {
return self.toFloat() == other.toFloat();
}
function ne(Frac other) returns boolean {
return self.toFloat() != other.toFloat();
}
function toString() returns string {
return string `${self.num} / ${self.den}`;
}
}
function divisors(int n) returns int[] {
if n < 1 { return []; }
int[] divisors = [];
int[] divisors2 = [];
int i = 1;
int k = n % 2 == 0 ? 1 : 2;
while i * i <= n {
if n % i == 0 {
divisors.push(i);
int j = n / i;
if j != i { divisors2.push(j); }
}
i += k;
}
if divisors2.length() > 0 {
divisors.push(...divisors2.reverse());
}
return divisors;
}
function properDivisors(int n) returns int[] {
int[] d = divisors(n);
int c = d.length();
return c <= 1 ? [] : d.slice(0, c - 1);
}
public function main() {
final Frac one = new Frac(1, 1);
io:println("The following numbers (less than 2^19) are perfect:");
foreach int i in 2..<(<int>1<<19) {
var sum = new Frac(1, i);
foreach int j in properDivisors(i).slice(1) {
sum = sum.add(new Frac(1, j));
}
if sum.eq(one) { io:println(" ", i); }
}
}