From: Gavin Sinclair Date: 2005-10-24T23:03:24+09:00 Subject: [PATCH] lib/rational.rb documentation Hi, Please inspect and commit the following patch. Thanks, Gavin Index: lib/rational.rb =================================================================== RCS file: /src/ruby/lib/rational.rb,v retrieving revision 1.13.2.1 diff -u -b -r1.13.2.1 rational.rb --- lib/rational.rb 7 May 2004 08:48:23 -0000 1.13.2.1 +++ lib/rational.rb 24 Oct 2005 14:02:21 -0000 @@ -5,37 +5,29 @@ # $Date: 1999/08/24 12:49:28 $ # by Keiju ISHITSUKA(SHL Japan Inc.) # -# -- -# Usage: -# class Rational < Numeric -# (include Comparable) -# -# 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::** -# Fixnum::quo -# Bignum::** -# Bignum::quo +# Documentation by Kevin Jackson and Gavin Sinclair. # +# When you require 'rational', all interactions between numbers +# potentially return a rational result. For example: +# +# 1.quo(2) # -> 0.5 +# require 'rational' +# 1.quo(2) # -> Rational(1,2) +# +# See Rational for full documentation. +# + +# +# Creates a Rational number (i.e. a fraction). +a+ and +b+ should be Integers: +# +# Rational(1,3) # -> 1/3 +# +# Note: trying to construct a Rational with floating point or real values +# produces errors: +# +# Rational(1.1, 2.3) # -> NoMethodError +# def Rational(a, b = 1) if a.kind_of?(Rational) && b == 1 a @@ -44,9 +36,38 @@ end end +# +# Rational implements a rational class for numbers. +# +# A rational number is a number that can be expressed as a fraction p/q +# where p and q are integers and q != 0. A rational number p/q is said to have +# numerator p and denominator q. Numbers that are not rational are called +# irrational numbers. (http://mathworld.wolfram.com/RationalNumber.html) +# +# To create a Rational Number: +# Rational(a,b) # -> a/b +# Rational.new!(a,b) # -> a/b +# +# Examples: +# Rational(5,6) # -> 5/6 +# Rational(5) # -> 5/1 +# +# Rational numbers are reduced to their lowest terms: +# Rational(6,10) # -> 3/5 +# +# But not if you use the unusual method "new!": +# Rational.new!(6,10) # -> 6/10 +# +# Division by zero is obviously not allowed: +# Rational(3,0) # -> ZeroDivisionError +# class Rational < Numeric @RCS_ID='-$Id: rational.rb,v 1.7 1999/08/24 12:49:28 keiju Exp keiju $-' + # + # Reduces the given numerator and denominator to their lowest terms. Use + # Rational() instead. + # def Rational.reduce(num, den = 1) raise ZeroDivisionError, "denominator is zero" if den == 0 @@ -64,12 +85,20 @@ end end + # + # Implements the constructor. This method does not reduce to lowest terms or + # check for division by zero. Therefore #Rational() should be preferred in + # normal use. + # def Rational.new!(num, den = 1) new(num, den) end private_class_method :new + # + # This method is actually private. + # def initialize(num, den) if den < 0 num = -num @@ -84,6 +113,14 @@ end end + # + # Returns the addition of this value and +a+. + # + # Examples: + # r = Rational(3,4) # -> Rational(3,4) + # r + 1 # -> Rational(7,4) + # r + 0.5 # -> 1.25 + # def + (a) if a.kind_of?(Rational) num = @numerator * a.denominator @@ -99,6 +136,15 @@ end end + # + # Returns the difference of this value and +a+. + # subtracted. + # + # Examples: + # r = Rational(3,4) # -> Rational(3,4) + # r - 1 # -> Rational(-1,4) + # r - 0.5 # -> 0.25 + # def - (a) if a.kind_of?(Rational) num = @numerator * a.denominator @@ -114,6 +160,16 @@ end end + # + # Returns the product of this value and +a+. + # + # Examples: + # r = Rational(3,4) # -> Rational(3,4) + # r * 2 # -> Rational(3,2) + # r * 4 # -> Rational(3,1) + # r * 0.5 # -> 0.375 + # r * Rational(1,2) # -> Rational(3,8) + # def * (a) if a.kind_of?(Rational) num = @numerator * a.numerator @@ -129,6 +185,13 @@ end end + # + # Returns the quotient of this value and +a+. + # r = Rational(3,4) # -> Rational(3,4) + # r / 2 # -> Rational(3,8) + # r / 2.0 # -> 0.375 + # r / Rational(1,2) # -> Rational(3,2) + # def / (a) if a.kind_of?(Rational) num = @numerator * a.denominator @@ -145,6 +208,15 @@ end end + # + # Returns this value raised to the given power. + # + # Examples: + # r = Rational(3,4) # -> Rational(3,4) + # r ** 2 # -> Rational(9,16) + # r ** 2.0 # -> 0.5625 + # r ** Rational(1,2) # -> 0.866025403784439 + # def ** (other) if other.kind_of?(Rational) Float(self) ** other @@ -168,16 +240,36 @@ end end + # + # Returns the remainder when this value is divided by +other+. + # + # Examples: + # r = Rational(7,4) # -> Rational(7,4) + # r % Rational(1,2) # -> Rational(1,4) + # r % 1 # -> Rational(3,4) + # r % Rational(1,7) # -> Rational(1,28) + # r % 0.26 # -> 0.19 + # def % (other) value = (self / other).to_i return self - other * value end + # + # Returns the quotient _and_ remainder. + # + # Examples: + # r = Rational(7,4) # -> Rational(7,4) + # r.divmod Rational(1,2) # -> [3, Rational(1,4)] + # def divmod(other) value = (self / other).to_i return value, self - other * value end + # + # Returns the absolute value. + # def abs if @numerator > 0 Rational.new!(@numerator, @denominator) @@ -186,6 +278,15 @@ end end + # + # Returns +true+ iff this value is numerically equal to +other+. + # + # But beware: + # Rational(1,2) == Rational(4,8) # -> true + # Rational(1,2) == Rational.new!(4,8) # -> false + # + # Don't use Rational.new! + # def == (other) if other.kind_of?(Rational) @numerator == other.numerator and @denominator == other.denominator @@ -198,6 +299,9 @@ end end + # + # Standard comparison operator. + # def <=> (other) if other.kind_of?(Rational) num = @numerator * other.denominator @@ -232,14 +336,35 @@ end end + # + # Converts the rational to an Integer. Not the _nearest_ integer, the + # truncated integer. Study the following example carefully: + # Rational(+7,4).to_i # -> 1 + # Rational(-7,4).to_i # -> -2 + # (-1.75).to_i # -> -1 + # + # In other words: + # Rational(-7,4) == -1.75 # -> true + # Rational(-7,4).to_i == (-1.75).to_i # false + # def to_i Integer(@numerator.div(@denominator)) end + # + # Converts the rational to a Float. + # def to_f @numerator.to_f/@denominator.to_f end + # + # Returns a string representation of the rational number. + # + # Example: + # Rational(3,4).to_s # "3/4" + # Rational(8).to_s # "8" + # def to_s if @denominator == 1 @numerator.to_s @@ -248,14 +373,25 @@ end end + # + # Returns +self+. + # def to_r self end + # + # Returns a reconstructable string representation: + # + # Rational(5,8).inspect # -> "Rational(5, 8)" + # def inspect sprintf("Rational(%s, %s)", @numerator.inspect, @denominator.inspect) end + # + # Returns a hash code for the object. + # def hash @numerator.hash ^ @denominator.hash end @@ -267,18 +403,38 @@ end class Integer + # + # In an integer, the value _is_ the numerator of its rational equivalent. + # Therefore, this method returns +self+. + # def numerator self end + # + # In an integer, the denominator is 1. Therefore, this method returns 1. + # def denominator 1 end + # + # Returns a Rational representation of this integer. + # def to_r Rational(self, 1) end + # + # Returns the greatest common denominator of the two numbers (+self+ + # and +n+). + # + # Examples: + # 72.gcd 168 # -> 24 + # 19.gcd 36 # -> 1 + # + # The result is positive, no matter the sign of the arguments. + # def gcd(n) m = self.abs n = n.abs @@ -312,29 +468,49 @@ return a end - def lcm(int) - a = self.abs - b = int.abs - gcd = a.gcd(b) - (a.div(gcd)) * b + # + # Returns the lowest common multiple (LCM) of the two arguments + # (+self+ and +other+). + # + # Examples: + # 6.lcm 7 # -> 42 + # 6.lcm 9 # -> 18 + # + def lcm(other) + if self.zero? or other.zero? + 0 + else + (self.div(self.gcd(other)) * other).abs end - - def gcdlcm(int) - a = self.abs - b = int.abs - gcd = a.gcd(b) - return gcd, (a.div(gcd)) * b end + # + # Returns the GCD _and_ the LCM (see #gcd and #lcm) of the two arguments + # (+self+ and +other+). This is more efficient than calculating them + # separately. + # + # Example: + # 6.gcdlcm 9 # -> [3, 18] + # + def gcdlcm(other) + gcd = self.gcd(other) + if self.zero? or other.zero? + [gcd, 0] + else + [gcd, (self.div(gcd) * other).abs] + end + end end class Fixnum undef quo + # If Rational is defined, returns a Rational number instead of a Fixnum. def quo(other) Rational.new!(self,1) / other end alias rdiv quo + # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0). def rpower (other) if other >= 0 self.power!(other) @@ -355,11 +531,13 @@ end undef quo + # If Rational is defined, returns a Rational number instead of a Bignum. def quo(other) Rational.new!(self,1) / other end alias rdiv quo + # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0). def rpower (other) if other >= 0 self.power!(other)