259 lines
5 KiB
Ruby
Vendored
259 lines
5 KiB
Ruby
Vendored
class Complex < Numeric
|
|
#
|
|
# call-seq:
|
|
# Complex.polar(abs [, arg]) -> complex
|
|
#
|
|
# Returns a complex number in terms of its polar coordinates.
|
|
# abs is the absolute value (magnitude) and arg is the argument (angle).
|
|
#
|
|
# Complex.polar(3, 0) #=> (3+0i)
|
|
# Complex.polar(3, Math::PI/2) #=> (1.836909530733566e-16+3.0i)
|
|
# Complex.polar(3, Math::PI) #=> (-3.0+3.673819061467132e-16i)
|
|
#
|
|
def self.polar(abs, arg = 0)
|
|
Complex(abs * Math.cos(arg), abs * Math.sin(arg))
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.inspect -> string
|
|
#
|
|
# Returns the value as a string for inspection.
|
|
#
|
|
# Complex(2).inspect #=> "(2+0i)"
|
|
# Complex(-8, 6).inspect #=> "(-8+6i)"
|
|
# Complex(1, 2).inspect #=> "(1+2i)"
|
|
#
|
|
def inspect
|
|
"(#{to_s})"
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.to_s -> string
|
|
#
|
|
# Returns the value as a string.
|
|
#
|
|
# Complex(2).to_s #=> "2+0i"
|
|
# Complex(-8, 6).to_s #=> "-8+6i"
|
|
# Complex(1, -2).to_s #=> "1-2i"
|
|
#
|
|
def to_s
|
|
"#{real}#{'+' unless imaginary < 0}#{imaginary}#{'*' unless imaginary.finite?}i"
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# +cmp -> cmp
|
|
#
|
|
# Returns self.
|
|
#
|
|
# +Complex(1, 2) #=> (1+2i)
|
|
#
|
|
def +@
|
|
self
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# -cmp -> complex
|
|
#
|
|
# Returns the negation of self.
|
|
#
|
|
# -Complex(1, 2) #=> (-1-2i)
|
|
# -Complex(-1, 2) #=> (1-2i)
|
|
#
|
|
def -@
|
|
Complex(-real, -imaginary)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp <=> numeric -> -1, 0, +1, or nil
|
|
#
|
|
# Returns -1, 0, or +1 depending on whether cmp is less than, equal to,
|
|
# or greater than numeric. This is the basis for the tests in the Comparable module.
|
|
# Returns nil if the two values are incomparable.
|
|
#
|
|
# Complex(2, 3) <=> Complex(2, 3) #=> 0
|
|
# Complex(5) <=> 5 #=> 0
|
|
# Complex(2, 3) <=> 1 #=> 1
|
|
#
|
|
def <=>(other)
|
|
return nil unless other.kind_of?(Numeric)
|
|
self.to_f <=> other.to_f
|
|
rescue
|
|
nil
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.abs -> real
|
|
# cmp.magnitude -> real
|
|
#
|
|
# Returns the absolute part of its polar form.
|
|
#
|
|
# Complex(-1).abs #=> 1.0
|
|
# Complex(3.0, -4.0).abs #=> 5.0
|
|
#
|
|
def abs
|
|
Math.hypot(imaginary, real)
|
|
end
|
|
alias_method :magnitude, :abs
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.abs2 -> real
|
|
#
|
|
# Returns square of the absolute value.
|
|
#
|
|
# Complex(-1).abs2 #=> 1
|
|
# Complex(3.0, -4.0).abs2 #=> 25.0
|
|
#
|
|
def abs2
|
|
real * real + imaginary * imaginary
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.arg -> float
|
|
# cmp.angle -> float
|
|
# cmp.phase -> float
|
|
#
|
|
# Returns the angle part of its polar form.
|
|
#
|
|
# Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
|
|
#
|
|
def arg
|
|
Math.atan2(imaginary, real)
|
|
end
|
|
alias_method :angle, :arg
|
|
alias_method :phase, :arg
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.conjugate -> complex
|
|
# cmp.conj -> complex
|
|
#
|
|
# Returns the complex conjugate.
|
|
#
|
|
# Complex(1, 2).conjugate #=> (1-2i)
|
|
#
|
|
def conjugate
|
|
Complex(real, -imaginary)
|
|
end
|
|
alias_method :conj, :conjugate
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.fdiv(numeric) -> complex
|
|
#
|
|
# Performs division as each part is a float, even if the parts are not floats.
|
|
#
|
|
# Complex(11, 22).fdiv(3) #=> (3.6666666666666665+7.333333333333333i)
|
|
#
|
|
def fdiv(numeric)
|
|
Complex(real / numeric, imaginary / numeric)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.polar -> array
|
|
#
|
|
# Returns an array; [cmp.abs, cmp.arg].
|
|
#
|
|
# Complex(1, 2).polar #=> [2.23606797749979, 1.1071487177940904]
|
|
#
|
|
def polar
|
|
[abs, arg]
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.real? -> false
|
|
#
|
|
# Returns false.
|
|
#
|
|
# Complex(1).real? #=> false
|
|
#
|
|
def real?
|
|
false
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.rectangular -> array
|
|
# cmp.rect -> array
|
|
#
|
|
# Returns an array; [cmp.real, cmp.imag].
|
|
#
|
|
# Complex(1, 2).rectangular #=> [1, 2]
|
|
#
|
|
def rectangular
|
|
[real, imaginary]
|
|
end
|
|
alias_method :rect, :rectangular
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.to_c -> cmp
|
|
#
|
|
# Returns self.
|
|
#
|
|
# Complex(2).to_c #=> (2+0i)
|
|
# Complex(-8, 6).to_c #=> (-8+6i)
|
|
#
|
|
def to_c
|
|
self
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# cmp.to_r -> rational
|
|
#
|
|
# Returns the value as a rational if possible (the imaginary part should be exactly zero).
|
|
#
|
|
# Complex(1, 0).to_r #=> (1/1)
|
|
# Complex(1, 0.0).to_r #=> (1/1)
|
|
# Complex(1, 2).to_r #=> RangeError
|
|
#
|
|
def to_r
|
|
raise RangeError.new "can't convert #{to_s} into Rational" unless imaginary.zero?
|
|
Rational(real, 1)
|
|
end
|
|
|
|
alias_method :imag, :imaginary
|
|
|
|
Numeric.class_eval do
|
|
#
|
|
# call-seq:
|
|
# num.i -> complex
|
|
#
|
|
# Returns the Complex object created from this number and i (0+num*i).
|
|
#
|
|
# -42.i #=> (0-42i)
|
|
# 2.0.i #=> (0+2.0i)
|
|
#
|
|
def i
|
|
Complex(0, self)
|
|
end
|
|
end
|
|
undef i
|
|
end
|
|
|
|
class Numeric
|
|
#
|
|
# call-seq:
|
|
# num.to_c -> complex
|
|
#
|
|
# Returns the value as a complex.
|
|
#
|
|
# 1.to_c #=> (1+0i)
|
|
# -1.to_c #=> (-1+0i)
|
|
# 1.0.to_c #=> (1.0+0i)
|
|
# 3.14159.to_c #=> (3.14159+0i)
|
|
#
|
|
def to_c
|
|
Complex(self, 0)
|
|
end
|
|
end
|