1class Rational < Numeric 2 def inspect 3 "(#{to_s})" 4 end 5 6 def to_s 7 "#{numerator}/#{denominator}" 8 end 9 10 def *(rhs) 11 if rhs.is_a? Rational 12 Rational(numerator * rhs.numerator, denominator * rhs.denominator) 13 elsif rhs.is_a? Integer 14 Rational(numerator * rhs, denominator) 15 elsif rhs.is_a? Numeric 16 numerator * rhs / denominator 17 end 18 end 19 20 def +(rhs) 21 if rhs.is_a? Rational 22 Rational(numerator * rhs.denominator + rhs.numerator * denominator, denominator * rhs.denominator) 23 elsif rhs.is_a? Integer 24 Rational(numerator + rhs * denominator, denominator) 25 elsif rhs.is_a? Numeric 26 (numerator + rhs * denominator) / denominator 27 end 28 end 29 30 def -(rhs) 31 if rhs.is_a? Rational 32 Rational(numerator * rhs.denominator - rhs.numerator * denominator, denominator * rhs.denominator) 33 elsif rhs.is_a? Integer 34 Rational(numerator - rhs * denominator, denominator) 35 elsif rhs.is_a? Numeric 36 (numerator - rhs * denominator) / denominator 37 end 38 end 39 40 def /(rhs) 41 if rhs.is_a? Rational 42 Rational(numerator * rhs.denominator, denominator * rhs.numerator) 43 elsif rhs.is_a? Integer 44 Rational(numerator, denominator * rhs) 45 elsif rhs.is_a? Numeric 46 numerator / rhs / denominator 47 end 48 end 49 50 def <=>(rhs) 51 if rhs.is_a?(Integral) 52 return numerator <=> rhs if denominator == 1 53 rhs = Rational(rhs) 54 end 55 56 case rhs 57 when Rational 58 (numerator * rhs.denominator - denominator * rhs.numerator) <=> 0 59 when Numeric 60 (rhs <=> self)&.-@ 61 else 62 nil 63 end 64 end 65 66 def ==(rhs) 67 return true if self.equal?(rhs) 68 if rhs.is_a?(Integral) && denominator == 1 69 return numerator == rhs 70 end 71 if rhs.is_a?(Rational) 72 numerator * rhs.denominator == denominator * rhs.numerator 73 else 74 rhs == self 75 end 76 end 77end 78 79class Numeric 80 def to_r 81 Rational(self, 1) 82 end 83end 84 85module Kernel 86 def Rational(numerator, denominator = 1) 87 a = numerator 88 b = denominator 89 a, b = b, a % b until b == 0 90 Rational._new(numerator.div(a), denominator.div(a)) 91 end 92 93 [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| 94 original_operator_name = :"__original_operator_#{op}_rational" 95 Fixnum.instance_eval do 96 alias_method original_operator_name, op 97 define_method op do |rhs| 98 if rhs.is_a? Rational 99 Rational(self).__send__(op, rhs) 100 else 101 __send__(original_operator_name, rhs) 102 end 103 end 104 end 105 Float.instance_eval do 106 alias_method original_operator_name, op 107 define_method op do |rhs| 108 if rhs.is_a? Rational 109 rhs = rhs.to_f 110 end 111 __send__(original_operator_name, rhs) 112 end 113 end if Object.const_defined?(:Float) 114 end 115end 116