summaryrefslogtreecommitdiff
path: root/lib/complex.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/complex.rb')
-rw-r--r--lib/complex.rb185
1 files changed, 148 insertions, 37 deletions
diff --git a/lib/complex.rb b/lib/complex.rb
index c27746a..ccf357c 100644
--- a/lib/complex.rb
+++ b/lib/complex.rb
@@ -5,48 +5,31 @@
# $Date: 1998/07/08 10:05:28 $
# by Keiju ISHITSUKA(SHL Japan Inc.)
#
-# --
-# Usage:
-# class Complex < Numeric
+# ----
#
-# Complex(x, y) --> x + yi
-# y.im --> 0 + yi
+# complex.rb implements the Complex class for complex numbers. Additionally,
+# some methods in other Numeric classes are redefined or added to allow greater
+# interoperability with Complex numbers.
#
-# Complex::polar
+# Complex numbers can be created in the following manner:
+# - <tt>Complex(a, b)</tt>
+# - <tt>Complex.new(a, b)</tt>
+# - <tt>Complex.polar(radius, theta)</tt>
+#
+# Additionally, note the following:
+# - <tt>Complex::I</tt> (the mathematical constant <i>i</i>)
+# - <tt>Numeric#im</tt> (e.g. <tt>5.im -> 0+5i</tt>)
#
-# Complex::+
-# Complex::-
-# Complex::*
-# Complex::/
-# Complex::**
-# Complex::%
-# Complex::divmod -- obsolete
-# Complex::abs
-# Complex::abs2
-# Complex::arg
-# Complex::polar
-# Complex::conjugate
-# Complex::<=>
-# Complex::==
-# Complex::to_f
-# Complex::to_r
-# Complex::to_s
+# The following +Math+ module methods are redefined to handle Complex arguments.
+# They will work as normal with non-Complex arguments.
+# sqrt exp cos sin tan log log10 atan2
#
-# Complex::I
-#
-# Numeric::im
-#
-# Math.sqrt
-# Math.exp
-# Math.cos
-# Math.sin
-# Math.tan
-# Math.log
-# Math.log10
-# Math.atan2
+
+
#
+# Creates a Complex number. +a+ and +b+ should be Numeric. The result will be
+# <tt>a+bi</tt>.
#
-
def Complex(a, b = 0)
if a.kind_of?(Complex) and b == 0
a
@@ -63,21 +46,30 @@ def Complex(a, b = 0)
end
end
+#
+# The complex number class. See complex.rb for an overview.
+#
class Complex < Numeric
@RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-'
undef step
- def Complex.generic?(other)
+ def Complex.generic?(other) # :nodoc:
other.kind_of?(Integer) or
other.kind_of?(Float) or
(defined?(Rational) and other.kind_of?(Rational))
end
+ #
+ # Creates a +Complex+ number in terms of +r+ (radius) and +theta+ (angle).
+ #
def Complex.polar(r, theta)
Complex(r*Math.cos(theta), r*Math.sin(theta))
end
+ #
+ # Creates a +Complex+ number <tt>a</tt>+<tt>b</tt><i>i</i>.
+ #
def initialize(a, b = 0)
raise "non numeric 1st arg `#{a.inspect}'" if !a.kind_of? Numeric
raise "non numeric 2nd arg `#{b.inspect}'" if !b.kind_of? Numeric
@@ -85,6 +77,9 @@ class Complex < Numeric
@image = b
end
+ #
+ # Addition with real or complex number.
+ #
def + (other)
if other.kind_of?(Complex)
re = @real + other.real
@@ -98,6 +93,9 @@ class Complex < Numeric
end
end
+ #
+ # Subtraction with real or complex number.
+ #
def - (other)
if other.kind_of?(Complex)
re = @real - other.real
@@ -111,6 +109,9 @@ class Complex < Numeric
end
end
+ #
+ # Multiplication with real or complex number.
+ #
def * (other)
if other.kind_of?(Complex)
re = @real*other.real - @image*other.image
@@ -124,6 +125,9 @@ class Complex < Numeric
end
end
+ #
+ # Division by real or complex number.
+ #
def / (other)
if other.kind_of?(Complex)
self*other.conjugate/other.abs2
@@ -135,6 +139,9 @@ class Complex < Numeric
end
end
+ #
+ # Raise this complex number to the given (real or complex) power.
+ #
def ** (other)
if other == 0
return Complex(1)
@@ -177,6 +184,9 @@ class Complex < Numeric
end
end
+ #
+ # Remainder after division by a real or complex number.
+ #
def % (other)
if other.kind_of?(Complex)
Complex(@real % other.real, @image % other.image)
@@ -188,6 +198,7 @@ class Complex < Numeric
end
end
+#--
# def divmod(other)
# if other.kind_of?(Complex)
# rdiv, rmod = @real.divmod(other.real)
@@ -200,31 +211,54 @@ class Complex < Numeric
# x.divmod(y)
# end
# end
+#++
+ #
+ # Absolute value (aka modulus): distance from the zero point on the complex
+ # plane.
+ #
def abs
Math.sqrt!((@real*@real + @image*@image).to_f)
end
+ #
+ # Square of the absolute value.
+ #
def abs2
@real*@real + @image*@image
end
+ #
+ # Argument (angle from (1,0) on the complex plane).
+ #
def arg
Math.atan2(@image.to_f, @real.to_f)
end
+ #
+ # Returns the absolute value _and_ the argument.
+ #
def polar
return abs, arg
end
+ #
+ # Complex conjugate (<tt>z + z.conjugate = 2 * z.real</tt>).
+ #
def conjugate
Complex(@real, -@image)
end
+ #
+ # Compares the absolute values of the two numbers.
+ #
def <=> (other)
self.abs <=> other.abs
end
+ #
+ # Test for numerical equality (<tt>a == a + 0<i>i</i></tt>).
+ #
def == (other)
if other.kind_of?(Complex)
@real == other.real and @image == other.image
@@ -236,6 +270,9 @@ class Complex < Numeric
end
end
+ #
+ # Attempts to coerce +other+ to a Complex number.
+ #
def coerce(other)
if Complex.generic?(other)
return Complex.new(other), self
@@ -244,16 +281,25 @@ class Complex < Numeric
end
end
+ #
+ # FIXME
+ #
def denominator
@real.denominator.lcm(@image.denominator)
end
+ #
+ # FIXME
+ #
def numerator
cd = denominator
Complex(@real.numerator*(cd/@real.denominator),
@image.numerator*(cd/@image.denominator))
end
+ #
+ # Standard string representation of the complex number.
+ #
def to_s
if @real != 0
if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
@@ -278,35 +324,65 @@ class Complex < Numeric
end
end
+ #
+ # Returns a hash code for the complex number.
+ #
def hash
@real.hash ^ @image.hash
end
+ #
+ # Returns "<tt>Complex(<i>real</i>, <i>image</i>)</tt>".
+ #
def inspect
sprintf("Complex(%s, %s)", @real.inspect, @image.inspect)
end
+ #
+ # +I+ is the imaginary number. It exists at point (0,1) on the complex plane.
+ #
I = Complex(0,1)
+ # The real part of a complex number.
attr :real
+
+ # The imaginary part of a complex number.
attr :image
end
+
+#
+# Numeric is a built-in class on which Fixnum, Bignum, etc., are based. Here
+# some methods are added so that all number types can be treated to some extent
+# as Complex numbers.
+#
class Numeric
+ #
+ # Returns a Complex number <tt>(0,<i>self</i>)</tt>.
+ #
def im
Complex(0, self)
end
+ #
+ # The real part of a complex number, i.e. <i>self</i>.
+ #
def real
self
end
+ #
+ # The imaginary part of a complex number, i.e. 0.
+ #
def image
0
end
+ #
+ # See Complex#arg.
+ #
def arg
if self >= 0
return 0
@@ -315,20 +391,28 @@ class Numeric
end
end
+ #
+ # See Complex#polar.
+ #
def polar
return abs, arg
end
+ #
+ # See Complex#conjugate (short answer: returns <i>self</i>).
+ #
def conjugate
self
end
end
+
class Fixnum
if not defined? Rational
alias power! **
end
+ # Redefined to handle a Complex argument.
def ** (other)
if self < 0
Complex.new(self) ** other
@@ -367,6 +451,7 @@ module Math
alias log10! log10
alias atan2! atan2
+ # Redefined to handle a Complex argument.
def sqrt(z)
if Complex.generic?(z)
if z >= 0
@@ -379,6 +464,7 @@ module Math
end
end
+ # Redefined to handle a Complex argument.
def exp(z)
if Complex.generic?(z)
exp!(z)
@@ -387,14 +473,21 @@ module Math
end
end
+ #
+ # Hyperbolic cosine.
+ #
def cosh!(x)
(exp!(x) + exp!(-x))/2.0
end
+ #
+ # Hyperbolic sine.
+ #
def sinh!(x)
(exp!(x) - exp!(-x))/2.0
end
+ # Redefined to handle a Complex argument.
def cos(z)
if Complex.generic?(z)
cos!(z)
@@ -404,6 +497,7 @@ module Math
end
end
+ # Redefined to handle a Complex argument.
def sin(z)
if Complex.generic?(z)
sin!(z)
@@ -413,6 +507,7 @@ module Math
end
end
+ # Redefined to handle a Complex argument.
def tan(z)
if Complex.generic?(z)
tan!(z)
@@ -421,6 +516,7 @@ module Math
end
end
+ # Redefined to handle a Complex argument.
def log(z)
if Complex.generic?(z) and z >= 0
log!(z)
@@ -430,6 +526,7 @@ module Math
end
end
+ # Redefined to handle a Complex argument.
def log10(z)
if Complex.generic?(z)
log10!(z)
@@ -438,6 +535,8 @@ module Math
end
end
+ # FIXME: I don't know what the point of this is. If you give it Complex
+ # arguments, it will fail.
def atan2(x, y)
if Complex.generic?(x) and Complex.generic?(y)
atan2!(x, y)
@@ -446,10 +545,14 @@ module Math
end
end
+ #
+ # Hyperbolic arctangent.
+ #
def atanh!(x)
log((1.0 + x.to_f) / ( 1.0 - x.to_f)) / 2.0
end
+ # Redefined to handle a Complex argument.
def atan(z)
if Complex.generic?(z)
atan2!(z, 1)
@@ -490,3 +593,11 @@ module Math
module_function :atanh!
end
+
+
+# Documentation comments:
+# - source: original (researched from pickaxe)
+# - a couple of fixme's
+# - Math module methods sinh! etc. a bit fuzzy. What exactly is the intention?
+# - RDoc output for Bignum etc. is a bit short, with nothing but an
+# (undocumented) alias. No big deal.