1require 'test/unit'
2
3class ComplexRational_Test < Test::Unit::TestCase
4
5  def test_rat_srat
6    skip unless defined?(Rational)
7
8    c = SimpleRat(1,3)
9    cc = Rational(3,2)
10
11    assert_kind_of(Numeric, c)
12    assert_kind_of(Numeric, cc)
13
14    assert_instance_of(SimpleRat, c)
15    assert_instance_of(Rational, cc)
16
17    assert_equal(SimpleRat(1,3), +c)
18    assert_equal(SimpleRat(-1,3), -c)
19
20    assert_equal(SimpleRat(7,3), c + 2)
21    assert_equal(SimpleRat(-5,3), c - 2)
22    assert_equal(SimpleRat(2,3), c * 2)
23    assert_equal(SimpleRat(1,6), c / 2)
24    assert_equal(SimpleRat(1,9), c ** 2)
25    assert_equal(-1, c <=> 2)
26
27    assert_equal(SimpleRat(7,3), 2 + c)
28    assert_equal(SimpleRat(5,3), 2 - c)
29    assert_equal(SimpleRat(2,3), 2 * c)
30    assert_equal(SimpleRat(6,1), 2 / c)
31    assert_in_delta(1.2599, 2 ** c, 0.001)
32    assert_equal(1, 2 <=> c)
33
34    assert_equal(SimpleRat(11,6), c + cc)
35    assert_equal(SimpleRat(-7,6), c - cc)
36    assert_equal(SimpleRat(1,2), c * cc)
37    assert_equal(SimpleRat(2,9), c / cc)
38    assert_in_delta(0.1924, c ** cc, 0.001)
39    assert_equal(-1, c <=> cc)
40
41    assert_equal(SimpleRat(11,6), cc + c)
42    assert_equal(SimpleRat(7,6), cc - c)
43    assert_equal(SimpleRat(1,2), cc * c)
44    assert_equal(SimpleRat(9,2), cc / c)
45    assert_in_delta(1.1447, cc ** c, 0.001)
46    assert_equal(1, cc <=> c)
47
48    assert_equal(SimpleRat, (+c).class)
49    assert_equal(SimpleRat, (-c).class)
50
51    assert_equal(SimpleRat, (c + 2).class)
52    assert_equal(SimpleRat, (c - 2).class)
53    assert_equal(SimpleRat, (c * 2).class)
54    assert_equal(SimpleRat, (c / 2).class)
55    assert_equal(SimpleRat, (c ** 2).class)
56
57    assert_equal(SimpleRat, (2 + c).class)
58    assert_equal(SimpleRat, (2 - c).class)
59    assert_equal(SimpleRat, (2 * c).class)
60    assert_equal(SimpleRat, (2 / c).class)
61    assert_equal(Float, (2 ** c).class)
62
63    assert_equal(SimpleRat, (c + cc).class)
64    assert_equal(SimpleRat, (c - cc).class)
65    assert_equal(SimpleRat, (c * cc).class)
66    assert_equal(SimpleRat, (c / cc).class)
67    assert_equal(Float, (c ** cc).class)
68
69    assert_equal(SimpleRat, (cc + c).class)
70    assert_equal(SimpleRat, (cc - c).class)
71    assert_equal(SimpleRat, (cc * c).class)
72    assert_equal(SimpleRat, (cc / c).class)
73    assert_equal(Float, (cc ** c).class)
74
75    assert_equal(0, Rational(2,3) <=> SimpleRat(2,3))
76    assert_equal(0, SimpleRat(2,3) <=> Rational(2,3))
77    assert(Rational(2,3) == SimpleRat(2,3))
78    assert(SimpleRat(2,3) == Rational(2,3))
79
80    assert_equal(SimpleRat, (c + 0).class)
81    assert_equal(SimpleRat, (c - 0).class)
82    assert_equal(SimpleRat, (c * 0).class)
83    assert_equal(SimpleRat, (c * 1).class)
84    assert_equal(SimpleRat, (0 + c).class)
85    assert_equal(SimpleRat, (0 - c).class)
86    assert_equal(SimpleRat, (0 * c).class)
87    assert_equal(SimpleRat, (1 * c).class)
88  end
89
90  def test_comp_srat
91    skip unless defined?(Rational)
92
93    c = Complex(SimpleRat(2,3),SimpleRat(1,2))
94    cc = Complex(Rational(3,2),Rational(2,1))
95
96    assert_equal(Complex(SimpleRat(2,3),SimpleRat(1,2)), +c)
97    assert_equal(Complex(SimpleRat(-2,3),SimpleRat(-1,2)), -c)
98
99    assert_equal(Complex(SimpleRat(8,3),SimpleRat(1,2)), c + 2)
100    assert_equal(Complex(SimpleRat(-4,3),SimpleRat(1,2)), c - 2)
101    assert_equal(Complex(SimpleRat(4,3),SimpleRat(1,1)), c * 2)
102    assert_equal(Complex(SimpleRat(1,3),SimpleRat(1,4)), c / 2)
103    assert_equal(Complex(SimpleRat(7,36),SimpleRat(2,3)), c ** 2)
104    assert_raise(NoMethodError){c <=> 2}
105
106    assert_equal(Complex(SimpleRat(8,3),SimpleRat(1,2)), 2 + c)
107    assert_equal(Complex(SimpleRat(4,3),SimpleRat(-1,2)), 2 - c)
108    assert_equal(Complex(SimpleRat(4,3),SimpleRat(1,1)), 2 * c)
109    assert_equal(Complex(SimpleRat(48,25),SimpleRat(-36,25)), 2 / c)
110    r = 2 ** c
111    assert_in_delta(1.4940, r.real, 0.001)
112    assert_in_delta(0.5392, r.imag, 0.001)
113    assert_raise(NoMethodError){2 <=> c}
114
115    assert_equal(Complex(SimpleRat(13,6),SimpleRat(5,2)), c + cc)
116    assert_equal(Complex(SimpleRat(-5,6),SimpleRat(-3,2)), c - cc)
117    assert_equal(Complex(SimpleRat(0,1),SimpleRat(25,12)), c * cc)
118    assert_equal(Complex(SimpleRat(8,25),SimpleRat(-7,75)), c / cc)
119    r = c ** cc
120    assert_in_delta(0.1732, r.real, 0.001)
121    assert_in_delta(0.1186, r.imag, 0.001)
122    assert_raise(NoMethodError){c <=> cc}
123
124    assert_equal(Complex(SimpleRat(13,6),SimpleRat(5,2)), cc + c)
125    assert_equal(Complex(SimpleRat(5,6),SimpleRat(3,2)), cc - c)
126    assert_equal(Complex(SimpleRat(0,1),SimpleRat(25,12)), cc * c)
127    assert_equal(Complex(SimpleRat(72,25),SimpleRat(21,25)), cc / c)
128    r = cc ** c
129    assert_in_delta(0.5498, r.real, 0.001)
130    assert_in_delta(1.0198, r.imag, 0.001)
131    assert_raise(NoMethodError){cc <=> c}
132
133    assert_equal([SimpleRat,SimpleRat],
134		 (+c).instance_eval{[real.class, imag.class]})
135    assert_equal([SimpleRat,SimpleRat],
136		 (-c).instance_eval{[real.class, imag.class]})
137
138    assert_equal([SimpleRat,SimpleRat],
139		 (c + 2).instance_eval{[real.class, imag.class]})
140    assert_equal([SimpleRat,SimpleRat],
141		 (c - 2).instance_eval{[real.class, imag.class]})
142    assert_equal([SimpleRat,SimpleRat],
143		 (c * 2).instance_eval{[real.class, imag.class]})
144    assert_equal([SimpleRat,SimpleRat],
145		 (c / 2).instance_eval{[real.class, imag.class]})
146    assert_equal([SimpleRat,SimpleRat],
147		 (c ** 2).instance_eval{[real.class, imag.class]})
148
149    assert_equal([SimpleRat,SimpleRat],
150		 (c + cc).instance_eval{[real.class, imag.class]})
151    assert_equal([SimpleRat,SimpleRat],
152		 (c - cc).instance_eval{[real.class, imag.class]})
153    assert_equal([SimpleRat,SimpleRat],
154		 (c * cc).instance_eval{[real.class, imag.class]})
155    assert_equal([SimpleRat,SimpleRat],
156		 (c / cc).instance_eval{[real.class, imag.class]})
157    assert_equal([Float,Float],
158		 (c ** cc).instance_eval{[real.class, imag.class]})
159
160    assert_equal([SimpleRat,SimpleRat],
161		 (cc + c).instance_eval{[real.class, imag.class]})
162    assert_equal([SimpleRat,SimpleRat],
163		 (cc - c).instance_eval{[real.class, imag.class]})
164    assert_equal([SimpleRat,SimpleRat],
165		 (cc * c).instance_eval{[real.class, imag.class]})
166    assert_equal([SimpleRat,SimpleRat],
167		 (cc / c).instance_eval{[real.class, imag.class]})
168    assert_equal([Float,Float],
169		 (cc ** c).instance_eval{[real.class, imag.class]})
170
171    assert(Complex(SimpleRat(2,3),SimpleRat(3,2)) ==
172	   Complex(Rational(2,3),Rational(3,2)))
173    assert(Complex(Rational(2,3),Rational(3,2)) ==
174	   Complex(SimpleRat(2,3),SimpleRat(3,2)))
175
176    assert_equal([SimpleRat,SimpleRat],
177		 (c + 0).instance_eval{[real.class, imag.class]})
178    assert_equal([SimpleRat,SimpleRat],
179		 (c - 0).instance_eval{[real.class, imag.class]})
180    assert_equal([SimpleRat,SimpleRat],
181		 (c * 0).instance_eval{[real.class, imag.class]})
182    assert_equal([SimpleRat,SimpleRat],
183		 (c * 1).instance_eval{[real.class, imag.class]})
184    assert_equal([SimpleRat,SimpleRat],
185		 (0 + c).instance_eval{[real.class, imag.class]})
186    assert_equal([SimpleRat,SimpleRat],
187		 (0 - c).instance_eval{[real.class, imag.class]})
188    assert_equal([SimpleRat,SimpleRat],
189		 (0 * c).instance_eval{[real.class, imag.class]})
190    assert_equal([SimpleRat,SimpleRat],
191		 (1 * c).instance_eval{[real.class, imag.class]})
192  end
193
194end
195
196def SimpleRat(*a) SimpleRat.new(*a) end
197
198class SimpleRat < Numeric
199
200  def initialize(num, den = 1)
201    if den == 0
202      raise ZeroDivisionError, "divided by zero"
203    end
204    if den < 0
205      num = -num
206      den = -den
207    end
208    gcd = num.gcd(den)
209    @num = num.div(gcd)
210    @den = den.div(gcd)
211  end
212
213  def numerator() @num end
214  def denominator() @den end
215
216  def +@ () self end
217  def -@ () self.class.new(-@num, @den) end
218
219  def + (o)
220    case o
221    when SimpleRat, Rational
222      a = @num * o.denominator
223      b = o.numerator * @den
224      self.class.new(a + b, @den * o.denominator)
225    when Integer
226      self + self.class.new(o)
227    when Float
228      to_f + o
229    else
230      x, y = o.coerce(self)
231      x + y
232    end
233  end
234
235  def - (o)
236    case o
237    when SimpleRat, Rational
238      a = @num * o.denominator
239      b = o.numerator * @den
240      self.class.new(a - b, @den * o.denominator)
241    when Integer
242      self - self.class.new(o)
243    when Float
244      to_f - o
245    else
246      x, y = o.coerce(self)
247      x - y
248    end
249  end
250
251  def * (o)
252    case o
253    when SimpleRat, Rational
254      a = @num * o.numerator
255      b = @den * o.denominator
256      self.class.new(a, b)
257    when Integer
258      self * self.class.new(o)
259    when Float
260      to_f * o
261    else
262      x, y = o.coerce(self)
263      x * y
264    end
265  end
266
267  def quo(o)
268    case o
269    when SimpleRat, Rational
270      a = @num * o.denominator
271      b = @den * o.numerator
272      self.class.new(a, b)
273    when Integer
274      if o == 0
275	raise raise ZeroDivisionError, "divided by zero"
276      end
277      self.quo(self.class.new(o))
278    when Float
279      to_f.quo(o)
280    else
281      x, y = o.coerce(self)
282      x.quo(y)
283    end
284  end
285
286  alias / quo
287
288  def floor
289    @num.div(@den)
290  end
291
292  def ceil
293    -((-@num).div(@den))
294  end
295
296  def truncate
297    if @num < 0
298      return -((-@num).div(@den))
299    end
300    @num.div(@den)
301  end
302
303  alias to_i truncate
304
305  def round
306    if @num < 0
307      num = -@num
308      num = num * 2 + @den
309      den = @den * 2
310      -(num.div(den))
311    else
312      num = @num * 2 + @den
313      den = @den * 2
314      num.div(den)
315    end
316  end
317
318  def div(o) (self / o).floor end
319  def quot(o) (self / o).truncate end
320
321  def modulo(o)
322    q = div(o)
323    self - o * q
324  end
325
326  def remainder(o)
327    q = quot(o)
328    self - o * q
329  end
330
331  alias % modulo
332
333  def divmod(o) [div(o), modulo(o)] end
334  def quotrem(o) [quot(o), remainder(o)] end
335
336  def ** (o)
337    case o
338    when SimpleRat, Rational
339      Float(self) ** o
340    when Integer
341      if o > 0
342	a = @num ** o
343	b = @den ** o
344      elsif o < 0
345	a = @den ** -o
346	b = @num ** -o
347      else
348	a = b = 1
349      end
350      self.class.new(a, b)
351    when Float
352      to_f ** o
353    else
354      x, y = o.coerce(self)
355      x ** y
356    end
357  end
358
359  def <=> (o)
360    case o
361    when SimpleRat, Rational
362      a = @num * o.denominator
363      b = o.numerator * @den
364      return a <=> b
365    when Integer
366      self <=> self.class.new(o)
367    when Float
368      to_f <=> o
369    else
370      x, y = o.coerce(self)
371      x <=> y
372    end
373  end
374
375  def == (o)
376    begin
377      (self <=> o) == 0
378    rescue
379      false
380    end
381  end
382
383  def coerce(o)
384    case o
385    when Rational
386      [self.class.new(o.numerator, o.denominator), self]
387    when Integer
388      [self.class.new(o), self]
389    when Float
390      [o, self.to_f]
391    else
392      super
393    end
394  end
395
396  def hash() @num.hash ^ @den.hash end
397
398  def to_f() @num.to_f / @den.to_f end
399  def to_r() self end
400  def to_s() format('%s/%s', @num, @den) end
401
402  def inspect() format('#SR(%s)', to_s) end
403
404  def marshal_dump() [@num, @den] end
405  def marshal_load(a) @num, @den = a end
406
407end
408