Task

Create a reasonably complete implementation of rational arithmetic in the particular language using the idioms of the language.



Example

Define a new type called frac with binary operator "//" of two integers that returns a structure made up of the numerator and the denominator (as per a rational number).

Further define the appropriate rational unary operators abs and '-', with the binary operators for addition '+', subtraction '-', multiplication '×', division '/', integer division '÷', modulo division, the comparison operators (e.g. '<', '≤', '>', & '≥') and equality operators (e.g. '=' & '≠').

Define standard coercion operators for casting int to frac etc.

If space allows, define standard increment and decrement operators (e.g. '+:=' & '-:=' etc.).

Finally test the operators:
Use the new type frac to find all perfect numbers less than 219 by summing the reciprocal of the factors.



Related task

   Perfect Numbers


import math
 
proc `^`[T](base, exp: T): T =
  var (base, exp) = (base, exp)
  result = 1
 
  while exp != 0:
    if (exp and 1) != 0:
      result *= base
    exp = exp shr 1
    base *= base
 
proc gcd[T](u, v: T): T =
  if v != 0:
    gcd(v, u mod v)
  else:
    u.abs
 
proc lcm[T](a, b: T): T =
  a div gcd(a, b) * b
 
type Rational* = tuple[num, den: int64]
 
proc fromInt*(x: SomeInteger): Rational =
  result.num = x
  result.den = 1
 
proc frac*(x: var Rational) =
  let common = gcd(x.num, x.den)
  x.num = x.num div common
  x.den = x.den div common
 
proc `+` *(x, y: Rational): Rational =
  let common = lcm(x.den, y.den)
  result.num = common div x.den * x.num + common div y.den * y.num
  result.den = common
  result.frac
 
proc `+=` *(x: var Rational, y: Rational) =
  let common = lcm(x.den, y.den)
  x.num = common div x.den * x.num + common div y.den * y.num
  x.den = common
  x.frac
 
proc `-` *(x: Rational): Rational =
  result.num = -x.num
  result.den = x.den
 
proc `-` *(x, y: Rational): Rational =
  x + -y
 
proc `-=` *(x: var Rational, y: Rational) =
  x += -y
 
proc `*` *(x, y: Rational): Rational =
  result.num = x.num * y.num
  result.den = x.den * y.den
  result.frac
 
proc `*=` *(x: var Rational, y: Rational) =
  x.num *= y.num
  x.den *= y.den
  x.frac
 
proc reciprocal*(x: Rational): Rational =
  result.num = x.den
  result.den = x.num
 
proc `div`*(x, y: Rational): Rational =
  x * y.reciprocal
 
proc toFloat*(x: Rational): float =
  x.num.float / x.den.float
 
proc toInt*(x: Rational): int64 =
  x.num div x.den
 
proc cmp*(x, y: Rational): int =
  cmp x.toFloat, y.toFloat
 
proc `<` *(x, y: Rational): bool =
  x.toFloat < y.toFloat
 
proc `<=` *(x, y: Rational): bool =
  x.toFloat <= y.toFloat
 
proc abs*(x: Rational): Rational =
  result.num = abs x.num
  result.den = abs x.den
 
for candidate in 2'i64 .. <((2'i64)^19):
  var sum: Rational = (1'i64, candidate)
  for factor in 2'i64 .. pow(candidate.float, 0.5).int64:
    if candidate mod factor == 0:
      sum += (1'i64, factor) + (1'i64, candidate div factor)
  if sum.den == 1:
    echo "Sum of recipr. factors of ",candidate," = ",sum.num," exactly ",
      if sum.num == 1: "perfect!" else: ""