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 self.num / self.den; } function toInt() returns int { float f = self.toFloat(); f = f >= 0.0 ? f.floor() : f.ceiling(); return 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..<(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); } } }