From 1ad1b93f0ac27b250489591bfe1c05ae99ae495f Mon Sep 17 00:00:00 2001 From: def Date: Fri, 2 Jan 2015 21:50:57 +0100 Subject: [PATCH 01/18] Add `^`, gcd and lcm to math --- lib/pure/math.nim | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index b25a1df3ab..6b1d09b901 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -329,6 +329,30 @@ proc standardDeviation*(s: RunningStat): float = {.pop.} {.pop.} +proc `^`*[T](x, y: T): T = + ## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use + ## `pow <#pow,float,float>` for negative exponents. + assert y >= 0 + var (x, y) = (x, y) + result = 1 + + while y != 0: + if (y and 1) != 0: + result *= x + y = y shr 1 + x *= x + +proc gcd*[T](x, y: T): T = + ## Computes the greatest common divisor of ``x`` and ``y``. + if y != 0: + gcd(y, x mod y) + else: + x.abs + +proc lcm*[T](x, y: T): T = + ## Computes the least common multiple of ``x`` and ``y``. + x div gcd(x, y) * y + when isMainModule and not defined(JS): proc gettime(dummy: ptr cint): cint {.importc: "time", header: "".} From 00e82c2fc6129a790fca9d261cc6414f5a204d51 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 2 Jan 2015 21:51:20 +0100 Subject: [PATCH 02/18] Extend complex to convert to/from polar coordinates --- lib/pure/complex.nim | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index 04cffe4e47..9f1546eedc 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -27,6 +27,11 @@ type {.deprecated: [TComplex: Complex].} +proc toComplex*(x: SomeInteger): Complex = + ## Convert some integer ``x`` to a complex number. + result.re = x + result.im = 0 + proc `==` *(x, y: Complex): bool = ## Compare two complex numbers `x` and `y` for equality. result = x.re == y.re and x.im == y.im @@ -291,6 +296,21 @@ proc cosh*(z: Complex): Complex = result = 0.5*(exp(z)+exp(-z)) +proc phase*(z: Complex): float = + ## Returns the phase of `z`. + arctan2(z.im, z.re) + +proc polar*(z: Complex): tuple[r, phi: float] = + ## Returns `z` in polar coordinates. + result.r = abs(z) + result.phi = phase(z) + +proc rect*(r: float, phi: float): Complex = + ## Returns the complex number with poolar coordinates `r` and `phi`. + result.re = r * cos(phi) + result.im = sin(phi) + + proc `$`*(z: Complex): string = ## Returns `z`'s string representation as ``"(re, im)"``. result = "(" & $z.re & ", " & $z.im & ")" @@ -344,6 +364,9 @@ when isMainModule: assert( arcsin(a) =~ (0.427078586392476, 1.528570919480998) ) assert( arccos(a) =~ (1.14371774040242, -1.52857091948100) ) - assert( cosh(a) =~ (-0.642148124715520, 1.068607421382778) ) + assert( cosh(a) =~ (-0.642148124715520, 1.068607421382778) ) assert( sinh(a) =~ (-0.489056259041294, 1.403119250622040) ) - \ No newline at end of file + + assert( phase(a) == 1.1071487177940904 ) + assert( polar(a) =~ (2.23606797749979, 1.1071487177940904) ) + assert( rect(1.0, 2.0) =~ (-0.4161468365471424, 0.9092974268256817) ) From 6fc1f1374f9fbf3a1bc65ee8366b6df85260f49d Mon Sep 17 00:00:00 2001 From: def Date: Fri, 2 Jan 2015 21:51:53 +0100 Subject: [PATCH 03/18] Add rational module --- lib/pure/rational.nim | 228 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 lib/pure/rational.nim diff --git a/lib/pure/rational.nim b/lib/pure/rational.nim new file mode 100644 index 0000000000..f04617dcd0 --- /dev/null +++ b/lib/pure/rational.nim @@ -0,0 +1,228 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + + +## This module implements rational numbers, consisting of a numerator `num` and +## a denominator `den`, both of type int. The denominator can not be 0. + +import math + +type Rational* = tuple[num, den: int] + ## a rational number, consisting of a numerator and denominator + +proc toRational*(x: SomeInteger): Rational = + ## Convert some integer `x` to a rational number. + result.num = x + result.den = 1 + +proc toFloat*(x: Rational): float = + ## Convert a rational number `x` to a float. + float(x.num) / float(x.den) + +proc toInt*(x: Rational): int = + ## Convert a rational number `x` to an int. Conversion rounds if `x` does not + ## contain an integer value. + round(toFloat(x)) + +proc reduce*(x: var Rational) = + ## Reduce rational `x`. + let common = gcd(x.num, x.den) + if x.den > 0: + x.num = x.num div common + x.den = x.den div common + elif x.den < 0: + x.num = -x.num div common + x.den = -x.den div common + else: + raise newException(DivByZeroError, "division by zero") + +proc `+` *(x, y: Rational): Rational = + ## Add two rational numbers. + let common = lcm(x.den, y.den) + result.num = common div x.den * x.num + common div y.den * y.num + result.den = common + reduce(result) + +proc `+` *(x: Rational, y: int): Rational = + ## Add rational `x` to int `y`. + result.num = x.num + y * x.den + result.den = x.den + +proc `+` *(x: int, y: Rational): Rational = + ## Add int `x` to tational `y`. + result.num = x * y.den + y.num + result.den = y.den + +proc `+=` *(x: var Rational, y: Rational) = + ## Add rational `y` to rational `x`. + let common = lcm(x.den, y.den) + x.num = common div x.den * x.num + common div y.den * y.num + x.den = common + reduce(x) + +proc `+=` *(x: var Rational, y: int) = + ## Add int `y` to rational `x`. + x.num += y + +proc `-` *(x: Rational): Rational = + ## Unary minus for rational numbers. + result.num = -x.num + result.den = x.den + +proc `-` *(x, y: Rational): Rational = + ## Subtract two rational numbers. + let common = lcm(x.den, y.den) + result.num = common div x.den * x.num - common div y.den * y.num + result.den = common + reduce(result) + +proc `-` *(x: Rational, y: int): Rational = + ## Subtract int `y` from rational `x`. + result.num = x.num - y * x.den + result.den = x.den + +proc `-` *(x: int, y: Rational): Rational = + ## Subtract rational `y` from int `x`. + result.num = - x * y.den + y.num + result.den = y.den + +proc `-=` *(x: var Rational, y: Rational) = + ## Subtract rational `y` from rational `x`. + let common = lcm(x.den, y.den) + x.num = common div x.den * x.num - common div y.den * y.num + x.den = common + reduce(x) + +proc `-=` *(x: var Rational, y: int) = + ## Subtract int `y` from rational `x`. + x.num -= y + +proc `*` *(x, y: Rational): Rational = + ## Multiply two rational numbers. + result.num = x.num * y.num + result.den = x.den * y.den + reduce(result) + +proc `*` *(x: Rational, y: int): Rational = + ## Multiply rational `x` with int `y`. + result.num = x.num * y + result.den = x.den + reduce(result) + +proc `*` *(x: int, y: Rational): Rational = + ## Multiply int `x` with rational `y`. + result.num = x * y.num + result.den = y.den + reduce(result) + +proc `*=` *(x: var Rational, y: Rational) = + ## Multiply rationals `y` to `x`. + x.num *= y.num + x.den *= y.den + reduce(x) + +proc `*=` *(x: var Rational, y: int) = + ## Multiply int `y` to rational `x`. + x.num *= y + reduce(x) + +proc reciprocal*(x: Rational): Rational = + ## Calculate the reciprocal of `x`. (1/x) + if x.num > 0: + result.num = x.den + result.den = x.num + elif x.num < 0: + result.num = -x.den + result.den = -x.num + else: + raise newException(DivByZeroError, "division by zero") + +proc `/`*(x, y: Rational): Rational = + ## Divide rationals `x` by `y`. + result.num = x.num * y.den + result.den = x.den * y.num + reduce(result) + +proc `/`*(x: Rational, y: int): Rational = + ## Divide rational `x` by int `y`. + result.num = x.num + result.den = x.den * y + reduce(result) + +proc `/`*(x: int, y: Rational): Rational = + ## Divide int `x` by Rational `y`. + result.num = y.num + result.den = x * y.den + reduce(result) + +proc `/=`*(x: var Rational, y: Rational): Rational = + ## Divide rationals `x` by `y` in place. + x.num *= y.den + x.den *= y.num + reduce(x) + +proc `/=`*(x: var Rational, y: int): Rational = + ## Divide rational `x` by int `y` in place. + x.den *= y + reduce(x) + +proc cmp*(x, y: Rational): int = + ## Compares two rationals. + (x - y).num + +proc `<` *(x, y: Rational): bool = + (x - y).num < 0 + +proc `<=` *(x, y: Rational): bool = + (x - y).num <= 0 + +proc `==` *(x, y: Rational): bool = + (x - y).num == 0 + +proc abs*(x: Rational): Rational = + result.num = abs x.num + result.den = abs x.den + +when isMainModule: + var z = (0, 1) + var o = (1, 1) + var a = (1, 2) + var b = (-1, -2) + var m1 = (-1, 1) + var tt = (10, 2) + + assert( a == a ) + assert( (a-a) == z ) + assert( (a+b) == o ) + assert( (a/b) == o ) + assert( (a*b) == (1, 4) ) + assert( 10*a == tt ) + assert( a*10 == tt ) + assert( tt/10 == a ) + assert( a-m1 == (3, 2) ) + assert( a+m1 == (-1, 2) ) + assert( m1+tt == (16, 4) ) + assert( m1-tt == (6, -1) ) + + assert( z < o ) + assert( z <= o ) + assert( z == z ) + assert( cmp(z, o) < 0) + assert( cmp(o, z) > 0) + + assert( o == o ) + assert( o >= o ) + assert( not(o > o) ) + assert( cmp(o, o) == 0) + assert( cmp(z, z) == 0) + + assert( a == b ) + assert( a >= b ) + assert( not(b > a) ) + assert( cmp(a, b) == 0) From 232dba8f953704cf74cf487c43cee0495cfc49d2 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 2 Jan 2015 21:53:07 +0100 Subject: [PATCH 04/18] Add rational to standard library list --- doc/lib.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/lib.txt b/doc/lib.txt index 1f972179d4..85f8199617 100644 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -185,6 +185,9 @@ Math libraries * `complex `_ This module implements complex numbers and their mathematical operations. +* `rational `_ + This module implements rational numbers and their mathematical operations. + * `fenv `_ Floating-point environment. Handling of floating-point rounding and exceptions (overflow, zero-devide, etc.). From d57d1f00cd2c4a0023250ee0506c10393605f167 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 2 Jan 2015 22:26:43 +0100 Subject: [PATCH 05/18] Add shuffle to math module --- lib/pure/math.nim | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 6b1d09b901..b2a588aa87 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -284,6 +284,14 @@ proc random[T](a: openArray[T]): T = ## returns a random element from the openarray `a`. result = a[random(a.low..a.len)] +proc shuffle[T](a: var openArray[T]) = + ## Shuffles the elements in `a`. Note that ``randomize`` needs to be called + ## to initialize the random number generator, otherwise ``shuffle`` always + ## shuffles in the same way. + for i in countdown(a.high, 0): + let j = random(i + 1) + swap(a[i], a[j]) + type RunningStat* = object ## an accumulator for statistical data n*: int ## number of pushed data From b1f4eda7238fd655f3e1d7213c6b78843e84b9e9 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 3 Jan 2015 05:09:56 +0100 Subject: [PATCH 06/18] Fix += and -= for Rational --- lib/pure/rational.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/rational.nim b/lib/pure/rational.nim index f04617dcd0..edb0ca6374 100644 --- a/lib/pure/rational.nim +++ b/lib/pure/rational.nim @@ -68,7 +68,7 @@ proc `+=` *(x: var Rational, y: Rational) = proc `+=` *(x: var Rational, y: int) = ## Add int `y` to rational `x`. - x.num += y + x.num += y * x.den proc `-` *(x: Rational): Rational = ## Unary minus for rational numbers. @@ -101,7 +101,7 @@ proc `-=` *(x: var Rational, y: Rational) = proc `-=` *(x: var Rational, y: int) = ## Subtract int `y` from rational `x`. - x.num -= y + x.num -= y * x.den proc `*` *(x, y: Rational): Rational = ## Multiply two rational numbers. From aa4d119e8cd13f89a9c007b141b035a207e1af64 Mon Sep 17 00:00:00 2001 From: def Date: Mon, 12 Jan 2015 23:30:13 +0100 Subject: [PATCH 07/18] Move rational.nim to rationals.nim --- lib/pure/{rational.nim => rationals.nim} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/pure/{rational.nim => rationals.nim} (100%) diff --git a/lib/pure/rational.nim b/lib/pure/rationals.nim similarity index 100% rename from lib/pure/rational.nim rename to lib/pure/rationals.nim From 8c92a788530f2234d24c321670f9654b5fc4eceb Mon Sep 17 00:00:00 2001 From: def Date: Mon, 12 Jan 2015 23:44:14 +0100 Subject: [PATCH 08/18] Export new math procs --- lib/pure/math.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index b2a588aa87..e520720d39 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -280,11 +280,11 @@ proc random*[T](x: Slice[T]): T = ## For a slice `a .. b` returns a value in the range `a .. b-1`. result = random(x.b - x.a) + x.a -proc random[T](a: openArray[T]): T = +proc random*[T](a: openArray[T]): T = ## returns a random element from the openarray `a`. result = a[random(a.low..a.len)] -proc shuffle[T](a: var openArray[T]) = +proc shuffle*[T](a: var openArray[T]) = ## Shuffles the elements in `a`. Note that ``randomize`` needs to be called ## to initialize the random number generator, otherwise ``shuffle`` always ## shuffles in the same way. From a85b6fd3fe29ab51f3acd89bda9a034604069a82 Mon Sep 17 00:00:00 2001 From: def Date: Mon, 12 Jan 2015 23:44:50 +0100 Subject: [PATCH 09/18] Change rationals.toInt behaviour --- lib/pure/rationals.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index edb0ca6374..659f9c9189 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -23,12 +23,12 @@ proc toRational*(x: SomeInteger): Rational = proc toFloat*(x: Rational): float = ## Convert a rational number `x` to a float. - float(x.num) / float(x.den) + x.num / x.den proc toInt*(x: Rational): int = - ## Convert a rational number `x` to an int. Conversion rounds if `x` does not - ## contain an integer value. - round(toFloat(x)) + ## Convert a rational number `x` to an int. Conversion rounds down if `x` + ## does not contain an integer value. + x.num div x.den proc reduce*(x: var Rational) = ## Reduce rational `x`. From 444beab5dd65aee8590c46ad4d3d2389d5791727 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 13 Jan 2015 01:33:26 +0100 Subject: [PATCH 10/18] Fix division and add tests --- lib/pure/rationals.nim | 57 +++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index 659f9c9189..eae0bd55b0 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -157,17 +157,17 @@ proc `/`*(x: Rational, y: int): Rational = proc `/`*(x: int, y: Rational): Rational = ## Divide int `x` by Rational `y`. - result.num = y.num - result.den = x * y.den + result.num = x * y.den + result.den = y.num reduce(result) -proc `/=`*(x: var Rational, y: Rational): Rational = +proc `/=`*(x: var Rational, y: Rational) = ## Divide rationals `x` by `y` in place. x.num *= y.den x.den *= y.num reduce(x) -proc `/=`*(x: var Rational, y: int): Rational = +proc `/=`*(x: var Rational, y: int) = ## Divide rational `x` by int `y` in place. x.den *= y reduce(x) @@ -190,18 +190,23 @@ proc abs*(x: Rational): Rational = result.den = abs x.den when isMainModule: - var z = (0, 1) - var o = (1, 1) - var a = (1, 2) - var b = (-1, -2) - var m1 = (-1, 1) - var tt = (10, 2) + var + z = (0, 1) + o = (1, 1) + a = (1, 2) + b = (-1, -2) + m1 = (-1, 1) + tt = (10, 2) assert( a == a ) assert( (a-a) == z ) assert( (a+b) == o ) assert( (a/b) == o ) assert( (a*b) == (1, 4) ) + assert( (3/a) == (6,1) ) + assert( (a/3) == (1,6) ) + assert( a*b == (1,4) ) + assert( tt*z == z ) assert( 10*a == tt ) assert( a*10 == tt ) assert( tt/10 == a ) @@ -213,16 +218,38 @@ when isMainModule: assert( z < o ) assert( z <= o ) assert( z == z ) - assert( cmp(z, o) < 0) - assert( cmp(o, z) > 0) + assert( cmp(z, o) < 0 ) + assert( cmp(o, z) > 0 ) assert( o == o ) assert( o >= o ) assert( not(o > o) ) - assert( cmp(o, o) == 0) - assert( cmp(z, z) == 0) + assert( cmp(o, o) == 0 ) + assert( cmp(z, z) == 0 ) assert( a == b ) assert( a >= b ) assert( not(b > a) ) - assert( cmp(a, b) == 0) + assert( cmp(a, b) == 0 ) + + var x = (1,3) + + x *= (5,1) + assert( x == (5,3) ) + x += (2,9) + assert( x == (17,9) ) + x -= (9,18) + assert( x == (25,18) ) + x /= (1,2) + assert( x == (50,18) ) + + var y = (1,3) + + y *= 4 + assert( y == (4,3) ) + y += 5 + assert( y == (19,3) ) + y -= 2 + assert( y == (13,3) ) + y /= 9 + assert( y == (13,27) ) From 2d004dd677e3965f60c7a9a4e18ab274ce4c24fc Mon Sep 17 00:00:00 2001 From: def Date: Tue, 13 Jan 2015 12:34:27 +0100 Subject: [PATCH 11/18] Update toInt doc --- lib/pure/rationals.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index eae0bd55b0..707510bd92 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -26,8 +26,8 @@ proc toFloat*(x: Rational): float = x.num / x.den proc toInt*(x: Rational): int = - ## Convert a rational number `x` to an int. Conversion rounds down if `x` - ## does not contain an integer value. + ## Convert a rational number `x` to an int. Conversion rounds towards 0 if + ## `x` does not contain an integer value. x.num div x.den proc reduce*(x: var Rational) = From cc757d538cd9a2d030f57f71d6767af0b3a6fc90 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 16 Jan 2015 23:58:43 +0100 Subject: [PATCH 12/18] Remove shuffle again --- lib/pure/math.nim | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index e520720d39..01eee3b151 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -284,14 +284,6 @@ proc random*[T](a: openArray[T]): T = ## returns a random element from the openarray `a`. result = a[random(a.low..a.len)] -proc shuffle*[T](a: var openArray[T]) = - ## Shuffles the elements in `a`. Note that ``randomize`` needs to be called - ## to initialize the random number generator, otherwise ``shuffle`` always - ## shuffles in the same way. - for i in countdown(a.high, 0): - let j = random(i + 1) - swap(a[i], a[j]) - type RunningStat* = object ## an accumulator for statistical data n*: int ## number of pushed data From 43bc72f1fe2b1c08dd0664d3b56bc302112573c2 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 27 Jan 2015 19:55:08 +0100 Subject: [PATCH 13/18] Make gcd iterative instead of recursive --- lib/pure/math.nim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 01eee3b151..c902af381a 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -344,10 +344,11 @@ proc `^`*[T](x, y: T): T = proc gcd*[T](x, y: T): T = ## Computes the greatest common divisor of ``x`` and ``y``. - if y != 0: - gcd(y, x mod y) - else: - x.abs + var (x,y) = (x,y) + while y != 0: + x = x mod y + swap x, y + abs x proc lcm*[T](x, y: T): T = ## Computes the least common multiple of ``x`` and ``y``. From 221e633697f88be79a0ab3a708e16e7310902811 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 19:15:12 +0100 Subject: [PATCH 14/18] Fix lib link to rationals module --- doc/lib.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lib.txt b/doc/lib.txt index 85f8199617..76920c6a94 100644 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -185,7 +185,7 @@ Math libraries * `complex `_ This module implements complex numbers and their mathematical operations. -* `rational `_ +* `rationals `_ This module implements rational numbers and their mathematical operations. * `fenv `_ From c377e6883cf6b70ba7f11aa118903fb24a648cf6 Mon Sep 17 00:00:00 2001 From: def Date: Thu, 19 Feb 2015 10:54:38 +0100 Subject: [PATCH 15/18] Change author of rationals module --- lib/pure/rationals.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index 707510bd92..c3e7dfa155 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -1,7 +1,7 @@ # # # Nim's Runtime Library -# (c) Copyright 2015 Andreas Rumpf +# (c) Copyright 2015 Dennis Felsing # # See the file "copying.txt", included in this # distribution, for details about the copyright. From f6c83c32f32d69cd3681a42d01e440c11894f2c2 Mon Sep 17 00:00:00 2001 From: def Date: Thu, 19 Feb 2015 13:57:31 +0100 Subject: [PATCH 16/18] Fix typo --- lib/pure/rationals.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index c3e7dfa155..968279b2b0 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -55,7 +55,7 @@ proc `+` *(x: Rational, y: int): Rational = result.den = x.den proc `+` *(x: int, y: Rational): Rational = - ## Add int `x` to tational `y`. + ## Add int `x` to rational `y`. result.num = x * y.den + y.num result.den = y.den From f710a31344e0df9f7ee9cafc3ffba44e9b3227c6 Mon Sep 17 00:00:00 2001 From: def Date: Thu, 19 Feb 2015 20:44:13 +0100 Subject: [PATCH 17/18] Make rationals generic --- lib/pure/rationals.nim | 61 +++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index 968279b2b0..3affd3cf3b 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -13,24 +13,24 @@ import math -type Rational* = tuple[num, den: int] +type Rational*[T] = tuple[num, den: T] ## a rational number, consisting of a numerator and denominator -proc toRational*(x: SomeInteger): Rational = +proc toRational*[T](x: SomeInteger): Rational[T] = ## Convert some integer `x` to a rational number. result.num = x result.den = 1 -proc toFloat*(x: Rational): float = +proc toFloat*[T](x: Rational[T]): float = ## Convert a rational number `x` to a float. x.num / x.den -proc toInt*(x: Rational): int = +proc toInt*[T](x: Rational[T]): int = ## Convert a rational number `x` to an int. Conversion rounds towards 0 if ## `x` does not contain an integer value. x.num div x.den -proc reduce*(x: var Rational) = +proc reduce*[T](x: var Rational[T]) = ## Reduce rational `x`. let common = gcd(x.num, x.den) if x.den > 0: @@ -42,97 +42,97 @@ proc reduce*(x: var Rational) = else: raise newException(DivByZeroError, "division by zero") -proc `+` *(x, y: Rational): Rational = +proc `+` *[T](x, y: Rational[T]): Rational[T] = ## Add two rational numbers. let common = lcm(x.den, y.den) result.num = common div x.den * x.num + common div y.den * y.num result.den = common reduce(result) -proc `+` *(x: Rational, y: int): Rational = +proc `+` *[T](x: Rational[T], y: T): Rational[T] = ## Add rational `x` to int `y`. result.num = x.num + y * x.den result.den = x.den -proc `+` *(x: int, y: Rational): Rational = +proc `+` *[T](x: T, y: Rational[T]): Rational[T] = ## Add int `x` to rational `y`. result.num = x * y.den + y.num result.den = y.den -proc `+=` *(x: var Rational, y: Rational) = +proc `+=` *[T](x: var Rational[T], y: Rational[T]) = ## Add rational `y` to rational `x`. let common = lcm(x.den, y.den) x.num = common div x.den * x.num + common div y.den * y.num x.den = common reduce(x) -proc `+=` *(x: var Rational, y: int) = +proc `+=` *[T](x: var Rational[T], y: T) = ## Add int `y` to rational `x`. x.num += y * x.den -proc `-` *(x: Rational): Rational = +proc `-` *[T](x: Rational[T]): Rational[T] = ## Unary minus for rational numbers. result.num = -x.num result.den = x.den -proc `-` *(x, y: Rational): Rational = +proc `-` *[T](x, y: Rational[T]): Rational[T] = ## Subtract two rational numbers. let common = lcm(x.den, y.den) result.num = common div x.den * x.num - common div y.den * y.num result.den = common reduce(result) -proc `-` *(x: Rational, y: int): Rational = +proc `-` *[T](x: Rational[T], y: T): Rational[T] = ## Subtract int `y` from rational `x`. result.num = x.num - y * x.den result.den = x.den -proc `-` *(x: int, y: Rational): Rational = +proc `-` *[T](x: T, y: Rational[T]): Rational[T] = ## Subtract rational `y` from int `x`. result.num = - x * y.den + y.num result.den = y.den -proc `-=` *(x: var Rational, y: Rational) = +proc `-=` *[T](x: var Rational[T], y: Rational[T]) = ## Subtract rational `y` from rational `x`. let common = lcm(x.den, y.den) x.num = common div x.den * x.num - common div y.den * y.num x.den = common reduce(x) -proc `-=` *(x: var Rational, y: int) = +proc `-=` *[T](x: var Rational[T], y: T) = ## Subtract int `y` from rational `x`. x.num -= y * x.den -proc `*` *(x, y: Rational): Rational = +proc `*` *[T](x, y: Rational[T]): Rational[T] = ## Multiply two rational numbers. result.num = x.num * y.num result.den = x.den * y.den reduce(result) -proc `*` *(x: Rational, y: int): Rational = +proc `*` *[T](x: Rational[T], y: T): Rational[T] = ## Multiply rational `x` with int `y`. result.num = x.num * y result.den = x.den reduce(result) -proc `*` *(x: int, y: Rational): Rational = +proc `*` *[T](x: T, y: Rational[T]): Rational[T] = ## Multiply int `x` with rational `y`. result.num = x * y.num result.den = y.den reduce(result) -proc `*=` *(x: var Rational, y: Rational) = +proc `*=` *[T](x: var Rational[T], y: Rational[T]) = ## Multiply rationals `y` to `x`. x.num *= y.num x.den *= y.den reduce(x) -proc `*=` *(x: var Rational, y: int) = +proc `*=` *[T](x: var Rational[T], y: T) = ## Multiply int `y` to rational `x`. x.num *= y reduce(x) -proc reciprocal*(x: Rational): Rational = +proc reciprocal*[T](x: Rational[T]): Rational[T] = ## Calculate the reciprocal of `x`. (1/x) if x.num > 0: result.num = x.den @@ -143,31 +143,31 @@ proc reciprocal*(x: Rational): Rational = else: raise newException(DivByZeroError, "division by zero") -proc `/`*(x, y: Rational): Rational = +proc `/`*[T](x, y: Rational[T]): Rational[T] = ## Divide rationals `x` by `y`. result.num = x.num * y.den result.den = x.den * y.num reduce(result) -proc `/`*(x: Rational, y: int): Rational = +proc `/`*[T](x: Rational[T], y: T): Rational[T] = ## Divide rational `x` by int `y`. result.num = x.num result.den = x.den * y reduce(result) -proc `/`*(x: int, y: Rational): Rational = +proc `/`*[T](x: T, y: Rational[T]): Rational[T] = ## Divide int `x` by Rational `y`. result.num = x * y.den result.den = y.num reduce(result) -proc `/=`*(x: var Rational, y: Rational) = +proc `/=`*[T](x: var Rational[T], y: Rational[T]) = ## Divide rationals `x` by `y` in place. x.num *= y.den x.den *= y.num reduce(x) -proc `/=`*(x: var Rational, y: int) = +proc `/=`*[T](x: var Rational[T], y: T) = ## Divide rational `x` by int `y` in place. x.den *= y reduce(x) @@ -185,7 +185,7 @@ proc `<=` *(x, y: Rational): bool = proc `==` *(x, y: Rational): bool = (x - y).num == 0 -proc abs*(x: Rational): Rational = +proc abs*[T](x: Rational[T]): Rational[T] = result.num = abs x.num result.den = abs x.den @@ -253,3 +253,8 @@ when isMainModule: assert( y == (13,3) ) y /= 9 assert( y == (13,27) ) + + assert toRational[int, int](5) == (5,1) + assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 + assert toInt(z) == 0 + echo 2 + (4,3) From 77f506bd709752598db1a4fac7e6293293b9a5a9 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 24 Feb 2015 19:54:27 +0100 Subject: [PATCH 18/18] Make Rational an object --- lib/pure/rationals.nim | 67 +++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index 3affd3cf3b..40c61f1d9d 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -13,8 +13,14 @@ import math -type Rational*[T] = tuple[num, den: T] +type Rational*[T] = object ## a rational number, consisting of a numerator and denominator + num*, den*: T + +proc initRational*[T](num, den: T): Rational[T] = + ## Create a new rational number. + result.num = num + result.den = den proc toRational*[T](x: SomeInteger): Rational[T] = ## Convert some integer `x` to a rational number. @@ -191,29 +197,29 @@ proc abs*[T](x: Rational[T]): Rational[T] = when isMainModule: var - z = (0, 1) - o = (1, 1) - a = (1, 2) - b = (-1, -2) - m1 = (-1, 1) - tt = (10, 2) + z = Rational[int](num: 0, den: 1) + o = initRational(num=1, den=1) + a = initRational(1, 2) + b = initRational(-1, -2) + m1 = initRational(-1, 1) + tt = initRational(10, 2) assert( a == a ) assert( (a-a) == z ) assert( (a+b) == o ) assert( (a/b) == o ) - assert( (a*b) == (1, 4) ) - assert( (3/a) == (6,1) ) - assert( (a/3) == (1,6) ) - assert( a*b == (1,4) ) + assert( (a*b) == initRational(1, 4) ) + assert( (3/a) == initRational(6,1) ) + assert( (a/3) == initRational(1,6) ) + assert( a*b == initRational(1,4) ) assert( tt*z == z ) assert( 10*a == tt ) assert( a*10 == tt ) assert( tt/10 == a ) - assert( a-m1 == (3, 2) ) - assert( a+m1 == (-1, 2) ) - assert( m1+tt == (16, 4) ) - assert( m1-tt == (6, -1) ) + assert( a-m1 == initRational(3, 2) ) + assert( a+m1 == initRational(-1, 2) ) + assert( m1+tt == initRational(16, 4) ) + assert( m1-tt == initRational(6, -1) ) assert( z < o ) assert( z <= o ) @@ -232,29 +238,28 @@ when isMainModule: assert( not(b > a) ) assert( cmp(a, b) == 0 ) - var x = (1,3) + var x = initRational(1,3) - x *= (5,1) - assert( x == (5,3) ) - x += (2,9) - assert( x == (17,9) ) - x -= (9,18) - assert( x == (25,18) ) - x /= (1,2) - assert( x == (50,18) ) + x *= initRational(5,1) + assert( x == initRational(5,3) ) + x += initRational(2,9) + assert( x == initRational(17,9) ) + x -= initRational(9,18) + assert( x == initRational(25,18) ) + x /= initRational(1,2) + assert( x == initRational(50,18) ) - var y = (1,3) + var y = initRational(1,3) y *= 4 - assert( y == (4,3) ) + assert( y == initRational(4,3) ) y += 5 - assert( y == (19,3) ) + assert( y == initRational(19,3) ) y -= 2 - assert( y == (13,3) ) + assert( y == initRational(13,3) ) y /= 9 - assert( y == (13,27) ) + assert( y == initRational(13,27) ) - assert toRational[int, int](5) == (5,1) + assert toRational[int, int](5) == initRational(5,1) assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 assert toInt(z) == 0 - echo 2 + (4,3)