summary refs log tree commit diff stats
path: root/lib/pure/rationals.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/rationals.nim')
-rw-r--r--lib/pure/rationals.nim36
1 files changed, 36 insertions, 0 deletions
diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim
index 7907b4e6c..3946cf85b 100644
--- a/lib/pure/rationals.nim
+++ b/lib/pure/rationals.nim
@@ -241,6 +241,33 @@ proc abs*[T](x: Rational[T]): Rational[T] =
   result.num = abs x.num
   result.den = abs x.den
 
+proc `div`*[T: SomeInteger](x, y: Rational[T]): T =
+  ## Computes the rational truncated division.
+  (x.num * y.den) div (y.num * x.den)
+
+proc `mod`*[T: SomeInteger](x, y: Rational[T]): Rational[T] =
+  ## Computes the rational modulo by truncated division (remainder).
+  ## This is same as ``x - (x div y) * y``.
+  result = ((x.num * y.den) mod (y.num * x.den)) // (x.den * y.den)
+  reduce(result)
+
+proc floorDiv*[T: SomeInteger](x, y: Rational[T]): T =
+  ## Computes the rational floor division.
+  ##
+  ## Floor division is conceptually defined as ``floor(x / y)``.
+  ## This is different from the ``div`` operator, which is defined
+  ## as ``trunc(x / y)``. That is, ``div`` rounds towards ``0`` and ``floorDiv``
+  ## rounds down.
+  floorDiv(x.num * y.den, y.num * x.den)
+
+proc floorMod*[T: SomeInteger](x, y: Rational[T]): Rational[T] =
+  ## Computes the rational modulo by floor division (modulo).
+  ##
+  ## This is same as ``x - floorDiv(x, y) * y``.
+  ## This proc behaves the same as the ``%`` operator in python.
+  result = floorMod(x.num * y.den, y.num * x.den) // (x.den * y.den)
+  reduce(result)
+
 proc hash*[T](x: Rational[T]): Hash =
   ## Computes hash for rational `x`
   # reduce first so that hash(x) == hash(y) for x == y
@@ -339,3 +366,12 @@ when isMainModule:
   assert toRational(0.33) == 33 // 100
   assert toRational(0.22) == 11 // 50
   assert toRational(10.0) == 10 // 1
+
+  assert (1//1) div (3//10) == 3
+  assert (-1//1) div (3//10) == -3
+  assert (3//10) mod (1//1) == 3//10
+  assert (-3//10) mod (1//1) == -3//10
+  assert floorDiv(1//1, 3//10) == 3
+  assert floorDiv(-1//1, 3//10) == -4
+  assert floorMod(3//10, 1//1) == 3//10
+  assert floorMod(-3//10, 1//1) == 7//10