summaryrefslogtreecommitdiff
path: root/lib/rational.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rational.rb')
-rw-r--r--lib/rational.rb361
1 files changed, 361 insertions, 0 deletions
diff --git a/lib/rational.rb b/lib/rational.rb
new file mode 100644
index 0000000000..d4112c2956
--- /dev/null
+++ b/lib/rational.rb
@@ -0,0 +1,361 @@
+#
+# rational.rb -
+# $Release Version: 0.5 $
+# $Revision: 1.1 $
+# $Date: 1996/11/11 04:25:14 $
+# by Keiju ISHITSUKA(SHL Japan Inc.)
+#
+# --
+# Usage:
+# class Rational < Numeric
+# (include Compareable)
+#
+# Rational(a, b) --> a/b
+#
+# Rational::+
+# Rational::-
+# Rational::*
+# Rational::/
+# Rational::**
+# Rational::%
+# Rational::divmod
+# Rational::abs
+# Rational::<=>
+# Rational::to_i
+# Rational::to_f
+# Rational::to_s
+#
+# Integer::gcd
+# Integer::lcm
+# Integer::gcdlcm
+# Integer::to_r
+#
+# Fixnum::**
+# Bignum::**
+#
+#
+
+def Rational(a, b = 1)
+ if a.kind_of?(Rational) && b == 1
+ a
+ else
+ Rational.reduce(a, b)
+ end
+end
+
+class Rational < Numeric
+ def Rational.reduce(num, den = 1)
+ if den < 0
+ num = -num
+ den = -den
+ end
+ gcd = num.gcd(den)
+ num = num.div(gcd)
+ den = den.div(gcd)
+ if den == 1 && defined?(Unify)
+ num
+ else
+ new!(num, den)
+ end
+ end
+
+ def Rational.new!(num, den = 1)
+ new(num, den)
+ end
+
+ def initialize(num, den)
+ if den < 0
+ num = -num
+ den = -den
+ end
+ if num.kind_of?(Integer) and den.kind_of?(Integer)
+ @numerator = num
+ @denominator = den
+ else
+ @numerator = num.to_i
+ @denoninator = den.to_i
+ end
+ end
+
+ def + (a)
+ if a.kind_of?(Rational)
+ num = @numerator * a.denominator
+ num_a = a.numerator * @denominator
+ Rational(num + num_a, @denominator * a.denominator)
+ elsif a.kind_of?(Integer)
+ self + Rational.new!(a, 1)
+ elsif a.kind_of?(Float)
+ Float(self) + a
+ else
+ x , y = a.coerce(self)
+ x + y
+ end
+ end
+
+ def - (a)
+ if a.kind_of?(Rational)
+ num = @numerator * a.denominator
+ num_a = a.numerator * @denominator
+ Rational(num - num_a, @denominator*a.denominator)
+ elsif a.kind_of?(Integer)
+ self - Rational.new!(a, 1)
+ elsif a.kind_of?(Float)
+ Float(self) - a
+ else
+ x , y = a.coerce(self)
+ x - y
+ end
+ end
+
+ def * (a)
+ if a.kind_of?(Rational)
+ num = @numerator * a.numerator
+ den = @denominator * a.denominator
+ Rational(num, den)
+ elsif a.kind_of?(Integer)
+ self * Rational.new!(a, 1)
+ elsif a.kind_of?(Float)
+ Float(self) * a
+ else
+ x , y = a.coerce(self)
+ x * y
+ end
+ end
+
+ def / (a)
+ if a.kind_of?(Rational)
+ num = @numerator * a.denominator
+ den = @denominator * a.numerator
+ Rational(num, den)
+ elsif a.kind_of?(Integer)
+ self / Rational.new!(a, 1)
+ elsif a.kind_of?(Float)
+ Float(self) / a
+ else
+ x , y = a.coerce(self)
+ x / y
+ end
+ end
+
+ def ** (other)
+ if other.kind_of?(Rational)
+ Float(self) ** other
+ elsif other.kind_of?(Integer)
+ if other > 0
+ num = @numerator ** other
+ den = @denominator ** other
+ elsif other < 0
+ num = @denominator ** -other
+ den = @numerator ** -other
+ elsif other == 0
+ num = 1
+ den = 1
+ end
+ Rational.new!(num, den)
+ elsif other.kind_of?(Float)
+ Float(self) ** other
+ else
+ x , y = other.coerce(self)
+ x ** y
+ end
+ end
+
+ def % (other)
+ value = (self / other).to_i
+ return self - other * value
+ end
+
+ def divmod(other)
+ value = (self / other).to_i
+ return value, self - other * value
+ end
+
+ def abs
+ if @numerator > 0
+ Rational.new!(@numerator, @denominator)
+ else
+ Rational.new!(-@numerator, @denominator)
+ end
+ end
+
+ def <=> (other)
+ if other.kind_of?(Rational)
+ num = @numerator * other.denominator
+ num_a = other.numerator * @denominator
+ v = num - num_a
+ if v > 0
+ return 1
+ elsif v < 0
+ return -1
+ else
+ return 0
+ end
+ elsif other.kind_of?(Integer)
+ return self <=> Rational.new!(other, 1)
+ elsif other.kind_of?(Float)
+ return Float(self) <=> other
+ else
+ x , y = other.coerce(self)
+ return x <=> y
+ end
+ end
+
+ def coerce(other)
+ if other.kind_of?(Float)
+ return other, self.to_f
+ elsif other.kind_of?(Integer)
+ return Rational.new!(other, 1), self
+ else
+ super
+ end
+ end
+
+ def to_i
+ Integer(@numerator.div(@denominator))
+ end
+
+ def to_f
+ @numerator.to_f/@denominator.to_f
+ end
+
+ def to_s
+ if @denominator == 1
+ @numerator.to_s
+ else
+ @numerator.to_s+"/"+@denominator.to_s
+ end
+ end
+
+ def to_r
+ self
+ end
+
+ def hash
+ @numerator ^ @denominator
+ end
+
+ attr :numerator
+ attr :denominator
+
+ private :initialize
+end
+
+class Integer
+ def numerator
+ self
+ end
+
+ def denomerator
+ 1
+ end
+
+ def to_r
+ Rational(self, 1)
+ end
+
+ def gcd(int)
+ a = self.abs
+ b = int.abs
+
+ a, b = b, a if a < b
+
+ while b != 0
+ void, a = a.divmod(b)
+ a, b = b, a
+ end
+ return a
+ end
+
+ def lcm(int)
+ a = self.abs
+ b = int.abs
+ gcd = a.gcd(b)
+ (a.div(gcd)) * b
+ end
+
+ def gcdlcm(int)
+ a = self.abs
+ b = int.abs
+ gcd = a.gcd(b)
+ return gcd, (a.div(gcd)) * b
+ end
+
+end
+
+class Fixnum
+ alias div! /;
+ def div(other)
+ if other.kind_of?(Fixnum)
+ self.div!(other)
+ elsif other.kind_of?(Bignum)
+ x, y = other.coerce(self)
+ x.div!(y)
+ else
+ x, y = other.coerce(self)
+ x / y
+ end
+ end
+
+# alias divmod! divmod
+
+ if not defined? Complex
+ alias power! **;
+ end
+
+# def rdiv(other)
+# if other.kind_of?(Fixnum)
+# Rational(self, other)
+# elsif
+# x, y = other.coerce(self)
+# if defined?(x.div())
+# x.div(y)
+# else
+# x / y
+# end
+# end
+ # end
+
+ def rdiv(other)
+ Rational.new!(self,1) / other
+ end
+
+ def rpower (other)
+ if other >= 0
+ self.power!(other)
+ else
+ Rational.new!(self,1)**other
+ end
+ end
+
+ if not defined? Complex
+ alias ** rpower
+ end
+end
+
+class Bignum
+ alias div! /;
+ alias div /;
+ alias divmod! divmod
+
+ if not defined? power!
+ alias power! **
+ end
+
+ def rdiv(other)
+ Rational.new!(self,1) / other
+ end
+
+ def rpower (other)
+ if other >= 0
+ self.power!(other)
+ else
+ Rational.new!(self, 1)**other
+ end
+ end
+
+ if not defined? Complex
+ alias ** rpower
+ end
+
+end
+