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