1class Complex < Numeric
2  def self.polar(abs, arg = 0)
3    Complex(abs * Math.cos(arg), abs * Math.sin(arg))
4  end
5
6  def inspect
7    "(#{to_s})"
8  end
9
10  def to_s
11    "#{real}#{'+' unless imaginary < 0}#{imaginary}i"
12  end
13
14  def +@
15    Complex(real, imaginary)
16  end
17
18  def -@
19    Complex(-real, -imaginary)
20  end
21
22  def +(rhs)
23    if rhs.is_a? Complex
24      Complex(real + rhs.real, imaginary + rhs.imaginary)
25    elsif rhs.is_a? Numeric
26      Complex(real + rhs, imaginary)
27    end
28  end
29
30  def -(rhs)
31    if rhs.is_a? Complex
32      Complex(real - rhs.real, imaginary - rhs.imaginary)
33    elsif rhs.is_a? Numeric
34      Complex(real - rhs, imaginary)
35    end
36  end
37
38  def *(rhs)
39    if rhs.is_a? Complex
40      Complex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary)
41    elsif rhs.is_a? Numeric
42      Complex(real * rhs, imaginary * rhs)
43    end
44  end
45
46  def /(rhs)
47    if rhs.is_a? Complex
48      __div__(rhs)
49    elsif rhs.is_a? Numeric
50      Complex(real / rhs, imaginary / rhs)
51    end
52  end
53  alias_method :quo, :/
54
55  def ==(rhs)
56    if rhs.is_a? Complex
57      real == rhs.real && imaginary == rhs.imaginary
58    elsif rhs.is_a? Numeric
59      imaginary == 0 && real == rhs
60    end
61  end
62
63  def abs
64    Math.hypot imaginary, real
65  end
66  alias_method :magnitude, :abs
67
68  def abs2
69    real * real + imaginary * imaginary
70  end
71
72  def arg
73    Math.atan2 imaginary, real
74  end
75  alias_method :angle, :arg
76  alias_method :phase, :arg
77
78  def conjugate
79    Complex(real, -imaginary)
80  end
81  alias_method :conj, :conjugate
82
83  def fdiv(numeric)
84    Complex(real.to_f / numeric, imaginary.to_f / numeric)
85  end
86
87  def polar
88    [abs, arg]
89  end
90
91  def real?
92    false
93  end
94
95  def rectangular
96    [real, imaginary]
97  end
98  alias_method :rect, :rectangular
99
100  def to_r
101    raise RangeError.new "can't convert #{to_s} into Rational" unless imaginary.zero?
102    Rational(real, 1)
103  end
104
105  alias_method :imag, :imaginary
106
107  [Fixnum, Float].each do |cls|
108    [:+, :-, :*, :/, :==].each do |op|
109      cls.instance_eval do
110        original_operator_name = :"__original_operator_#{op}_complex"
111        alias_method original_operator_name, op
112        define_method op do |rhs|
113          if rhs.is_a? Complex
114            Complex(self).__send__(op, rhs)
115          else
116            __send__(original_operator_name, rhs)
117          end
118        end
119      end
120    end
121  end
122end
123