lib/rational.rb
DEFINITIONS
This source file includes following functions.
1 #
2 # rational.rb -
3 # $Release Version: 0.5 $
4 # $Revision: 1.7 $
5 # $Date: 1999/08/24 12:49:28 $
6 # by Keiju ISHITSUKA(SHL Japan Inc.)
7 #
8 # --
9 # Usage:
10 # class Rational < Numeric
11 # (include Comparable)
12 #
13 # Rational(a, b) --> a/b
14 #
15 # Rational::+
16 # Rational::-
17 # Rational::*
18 # Rational::/
19 # Rational::**
20 # Rational::%
21 # Rational::divmod
22 # Rational::abs
23 # Rational::<=>
24 # Rational::to_i
25 # Rational::to_f
26 # Rational::to_s
27 #
28 # Integer::gcd
29 # Integer::lcm
30 # Integer::gcdlcm
31 # Integer::to_r
32 #
33 # Fixnum::**
34 # Bignum::**
35 #
36 #
37
38 def Rational(a, b = 1)
39 if a.kind_of?(Rational) && b == 1
40 a
41 else
42 Rational.reduce(a, b)
43 end
44 end
45
46 class Rational < Numeric
47 @RCS_ID='-$Id: rational.rb,v 1.7 1999/08/24 12:49:28 keiju Exp keiju $-'
48
49 def Rational.reduce(num, den = 1)
50 raise ZeroDivisionError, "denominator is 0" if den == 0
51
52 if den < 0
53 num = -num
54 den = -den
55 end
56 gcd = num.gcd(den)
57 num = num.div(gcd)
58 den = den.div(gcd)
59 if den == 1 && defined?(Unify)
60 num
61 else
62 new!(num, den)
63 end
64 end
65
66 def Rational.new!(num, den = 1)
67 new(num, den)
68 end
69
70 def initialize(num, den)
71 if den < 0
72 num = -num
73 den = -den
74 end
75 if num.kind_of?(Integer) and den.kind_of?(Integer)
76 @numerator = num
77 @denominator = den
78 else
79 @numerator = num.to_i
80 @denominator = den.to_i
81 end
82 end
83
84 def + (a)
85 if a.kind_of?(Rational)
86 num = @numerator * a.denominator
87 num_a = a.numerator * @denominator
88 Rational(num + num_a, @denominator * a.denominator)
89 elsif a.kind_of?(Integer)
90 self + Rational.new!(a, 1)
91 elsif a.kind_of?(Float)
92 Float(self) + a
93 else
94 x , y = a.coerce(self)
95 x + y
96 end
97 end
98
99 def - (a)
100 if a.kind_of?(Rational)
101 num = @numerator * a.denominator
102 num_a = a.numerator * @denominator
103 Rational(num - num_a, @denominator*a.denominator)
104 elsif a.kind_of?(Integer)
105 self - Rational.new!(a, 1)
106 elsif a.kind_of?(Float)
107 Float(self) - a
108 else
109 x , y = a.coerce(self)
110 x - y
111 end
112 end
113
114 def * (a)
115 if a.kind_of?(Rational)
116 num = @numerator * a.numerator
117 den = @denominator * a.denominator
118 Rational(num, den)
119 elsif a.kind_of?(Integer)
120 self * Rational.new!(a, 1)
121 elsif a.kind_of?(Float)
122 Float(self) * a
123 else
124 x , y = a.coerce(self)
125 x * y
126 end
127 end
128
129 def / (a)
130 if a.kind_of?(Rational)
131 num = @numerator * a.denominator
132 den = @denominator * a.numerator
133 Rational(num, den)
134 elsif a.kind_of?(Integer)
135 raise ZeroDivisionError, "divided by 0" if a == 0
136 self / Rational.new!(a, 1)
137 elsif a.kind_of?(Float)
138 Float(self) / a
139 else
140 x , y = a.coerce(self)
141 x / y
142 end
143 end
144
145 def ** (other)
146 if other.kind_of?(Rational)
147 Float(self) ** other
148 elsif other.kind_of?(Integer)
149 if other > 0
150 num = @numerator ** other
151 den = @denominator ** other
152 elsif other < 0
153 num = @denominator ** -other
154 den = @numerator ** -other
155 elsif other == 0
156 num = 1
157 den = 1
158 end
159 Rational.new!(num, den)
160 elsif other.kind_of?(Float)
161 Float(self) ** other
162 else
163 x , y = other.coerce(self)
164 x ** y
165 end
166 end
167
168 def % (other)
169 value = (self / other).to_i
170 return self - other * value
171 end
172
173 def divmod(other)
174 value = (self / other).to_i
175 return value, self - other * value
176 end
177
178 def abs
179 if @numerator > 0
180 Rational.new!(@numerator, @denominator)
181 else
182 Rational.new!(-@numerator, @denominator)
183 end
184 end
185
186 def <=> (other)
187 if other.kind_of?(Rational)
188 num = @numerator * other.denominator
189 num_a = other.numerator * @denominator
190 v = num - num_a
191 if v > 0
192 return 1
193 elsif v < 0
194 return -1
195 else
196 return 0
197 end
198 elsif other.kind_of?(Integer)
199 return self <=> Rational.new!(other, 1)
200 elsif other.kind_of?(Float)
201 return Float(self) <=> other
202 else
203 x , y = other.coerce(self)
204 return x <=> y
205 end
206 end
207
208 def coerce(other)
209 if other.kind_of?(Float)
210 return other, self.to_f
211 elsif other.kind_of?(Integer)
212 return Rational.new!(other, 1), self
213 else
214 super
215 end
216 end
217
218 def to_i
219 Integer(@numerator.div(@denominator))
220 end
221
222 def to_f
223 @numerator.to_f/@denominator.to_f
224 end
225
226 def to_s
227 if @denominator == 1
228 @numerator.to_s
229 else
230 @numerator.to_s+"/"+@denominator.to_s
231 end
232 end
233
234 def to_r
235 self
236 end
237
238 def inspect
239 sprintf("Rational(%s, %s)", @numerator.inspect, @denominator.inspect)
240 end
241
242 def hash
243 @numerator.hash ^ @denominator.hash
244 end
245
246 attr :numerator
247 attr :denominator
248
249 private :initialize
250 end
251
252 class Integer
253 def numerator
254 self
255 end
256
257 def denomerator
258 1
259 end
260
261 def to_r
262 Rational(self, 1)
263 end
264
265 def gcd(n)
266 m = self.abs
267 n = n.abs
268
269 return n if m == 0
270 return m if n == 0
271
272 b = 0
273 while n[0] == 0 && m[0] == 0
274 b += 1; n >>= 1; m >>= 1
275 end
276 m >>= 1 while m[0] == 0
277 n >>= 1 while n[0] == 0
278 while m != n
279 m, n = n, m if n > m
280 m -= n; m >>= 1 while m[0] == 0
281 end
282 m << b
283 end
284
285 def gcd2(int)
286 a = self.abs
287 b = int.abs
288
289 a, b = b, a if a < b
290
291 while b != 0
292 void, a = a.divmod(b)
293 a, b = b, a
294 end
295 return a
296 end
297
298 def lcm(int)
299 a = self.abs
300 b = int.abs
301 gcd = a.gcd(b)
302 (a.div(gcd)) * b
303 end
304
305 def gcdlcm(int)
306 a = self.abs
307 b = int.abs
308 gcd = a.gcd(b)
309 return gcd, (a.div(gcd)) * b
310 end
311
312 end
313
314 class Fixnum
315 alias div! /;
316 def div(other)
317 if other.kind_of?(Fixnum)
318 self.div!(other)
319 elsif other.kind_of?(Bignum)
320 x, y = other.coerce(self)
321 x.div!(y)
322 else
323 x, y = other.coerce(self)
324 x / y
325 end
326 end
327
328 # alias divmod! divmod
329
330 if not defined? Complex
331 alias power! **;
332 end
333
334 # def rdiv(other)
335 # if other.kind_of?(Fixnum)
336 # Rational(self, other)
337 # elsif
338 # x, y = other.coerce(self)
339 # if defined?(x.div())
340 # x.div(y)
341 # else
342 # x / y
343 # end
344 # end
345 # end
346
347 def rdiv(other)
348 Rational.new!(self,1) / other
349 end
350
351 def rpower (other)
352 if other >= 0
353 self.power!(other)
354 else
355 Rational.new!(self,1)**other
356 end
357 end
358
359 if not defined? Complex
360 alias ** rpower
361 end
362 end
363
364 class Bignum
365 alias div! /;
366 alias div /;
367 alias divmod! divmod
368
369 if not defined? power!
370 alias power! **
371 end
372
373 def rdiv(other)
374 Rational.new!(self,1) / other
375 end
376
377 def rpower (other)
378 if other >= 0
379 self.power!(other)
380 else
381 Rational.new!(self, 1)**other
382 end
383 end
384
385 if not defined? Complex
386 alias ** rpower
387 end
388
389 end
390