2011-05-17 15:54:40 -04:00
|
|
|
##
|
2011-05-17 17:09:39 -04:00
|
|
|
# CMath is a library that provides trigonometric and transcendental
|
|
|
|
# functions for complex numbers.
|
|
|
|
#
|
|
|
|
# == Usage
|
|
|
|
#
|
|
|
|
# To start using this library, simply:
|
|
|
|
#
|
|
|
|
# require "cmath"
|
|
|
|
#
|
|
|
|
# Square root of a negative number is a complex number.
|
|
|
|
#
|
|
|
|
# CMath.sqrt(-9) #=> 0+3.0i
|
|
|
|
#
|
2011-05-17 15:54:40 -04:00
|
|
|
|
2008-04-05 10:25:40 -04:00
|
|
|
module CMath
|
|
|
|
|
|
|
|
include Math
|
|
|
|
|
|
|
|
alias exp! exp
|
|
|
|
alias log! log
|
2010-04-26 07:14:40 -04:00
|
|
|
alias log2! log2
|
2008-04-05 10:25:40 -04:00
|
|
|
alias log10! log10
|
|
|
|
alias sqrt! sqrt
|
2010-04-26 07:14:40 -04:00
|
|
|
alias cbrt! cbrt
|
2008-04-05 10:25:40 -04:00
|
|
|
|
|
|
|
alias sin! sin
|
|
|
|
alias cos! cos
|
|
|
|
alias tan! tan
|
|
|
|
|
|
|
|
alias sinh! sinh
|
|
|
|
alias cosh! cosh
|
|
|
|
alias tanh! tanh
|
|
|
|
|
|
|
|
alias asin! asin
|
|
|
|
alias acos! acos
|
|
|
|
alias atan! atan
|
|
|
|
alias atan2! atan2
|
|
|
|
|
|
|
|
alias asinh! asinh
|
|
|
|
alias acosh! acosh
|
|
|
|
alias atanh! atanh
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
2011-05-17 17:09:39 -04:00
|
|
|
# Math::E raised to the +z+ power
|
|
|
|
#
|
|
|
|
# exp(Complex(0,0)) #=> 1.0+0.0i
|
|
|
|
# exp(Complex(0,PI)) #=> -1.0+1.2246467991473532e-16i
|
|
|
|
# exp(Complex(0,PI/2.0)) #=> 6.123233995736766e-17+1.0i
|
2008-04-05 10:25:40 -04:00
|
|
|
def exp(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real?
|
2014-08-08 21:36:49 -04:00
|
|
|
exp!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
ere = exp!(z.real)
|
|
|
|
Complex(ere * cos!(z.imag),
|
|
|
|
ere * sin!(z.imag))
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
2011-05-17 17:09:39 -04:00
|
|
|
# Returns the natural logarithm of Complex. If a second argument is given,
|
|
|
|
# it will be the base of logarithm.
|
|
|
|
#
|
|
|
|
# log(Complex(0,0)) #=> -Infinity+0.0i
|
2015-02-24 18:53:21 -05:00
|
|
|
def log(z, b=::Math::E)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
2015-02-24 18:53:21 -05:00
|
|
|
if z.real? && z >= 0 && b >= 0
|
|
|
|
log!(z, b)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2015-02-24 18:53:21 -05:00
|
|
|
Complex(log!(z.abs), z.arg) / log(b)
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
2011-05-17 17:09:39 -04:00
|
|
|
# returns the base 2 logarithm of +z+
|
2010-04-26 07:14:40 -04:00
|
|
|
def log2(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real? and z >= 0
|
2014-08-08 21:36:49 -04:00
|
|
|
log2!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
log(z) / log!(2)
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2010-04-26 07:14:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
2011-05-17 17:09:39 -04:00
|
|
|
# returns the base 10 logarithm of +z+
|
2008-04-05 10:25:40 -04:00
|
|
|
def log10(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real? and z >= 0
|
2014-08-08 21:36:49 -04:00
|
|
|
log10!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
log(z) / log!(10)
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
2011-05-17 17:09:39 -04:00
|
|
|
# Returns the non-negative square root of Complex.
|
|
|
|
# sqrt(-1) #=> 0+1.0i
|
|
|
|
# sqrt(Complex(-1,0)) #=> 0.0+1.0i
|
|
|
|
# sqrt(Complex(0,8)) #=> 2.0+2.0i
|
2008-04-05 10:25:40 -04:00
|
|
|
def sqrt(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real?
|
2014-08-08 21:36:49 -04:00
|
|
|
if z < 0
|
|
|
|
Complex(0, sqrt!(-z))
|
|
|
|
else
|
|
|
|
sqrt!(z)
|
|
|
|
end
|
2008-04-05 10:25:40 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
if z.imag < 0 ||
|
|
|
|
(z.imag == 0 && z.imag.to_s[0] == '-')
|
|
|
|
sqrt(z.conjugate).conjugate
|
|
|
|
else
|
|
|
|
r = z.abs
|
|
|
|
x = z.real
|
|
|
|
Complex(sqrt!((r + x) / 2.0), sqrt!((r - x) / 2.0))
|
|
|
|
end
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
2011-06-29 11:31:37 -04:00
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
2011-06-13 01:36:59 -04:00
|
|
|
# returns the principal value of the cube root of +z+
|
2010-04-26 07:14:40 -04:00
|
|
|
def cbrt(z)
|
2011-07-23 08:14:43 -04:00
|
|
|
z ** (1.0/3)
|
2010-04-26 07:14:40 -04:00
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
|
|
|
# returns the sine of +z+, where +z+ is given in radians
|
2008-04-05 10:25:40 -04:00
|
|
|
def sin(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real?
|
2014-08-08 21:36:49 -04:00
|
|
|
sin!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
Complex(sin!(z.real) * cosh!(z.imag),
|
|
|
|
cos!(z.real) * sinh!(z.imag))
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
|
|
|
# returns the cosine of +z+, where +z+ is given in radians
|
2008-04-05 10:25:40 -04:00
|
|
|
def cos(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real?
|
2014-08-08 21:36:49 -04:00
|
|
|
cos!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
Complex(cos!(z.real) * cosh!(z.imag),
|
|
|
|
-sin!(z.real) * sinh!(z.imag))
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
|
|
|
# returns the tangent of +z+, where +z+ is given in radians
|
2008-04-05 10:25:40 -04:00
|
|
|
def tan(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real?
|
2014-08-08 21:36:49 -04:00
|
|
|
tan!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
sin(z) / cos(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
2011-05-17 17:09:39 -04:00
|
|
|
# returns the hyperbolic sine of +z+, where +z+ is given in radians
|
2008-04-05 10:25:40 -04:00
|
|
|
def sinh(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real?
|
2014-08-08 21:36:49 -04:00
|
|
|
sinh!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
Complex(sinh!(z.real) * cos!(z.imag),
|
|
|
|
cosh!(z.real) * sin!(z.imag))
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
2011-05-17 17:09:39 -04:00
|
|
|
# returns the hyperbolic cosine of +z+, where +z+ is given in radians
|
2008-04-05 10:25:40 -04:00
|
|
|
def cosh(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real?
|
2014-08-08 21:36:49 -04:00
|
|
|
cosh!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
Complex(cosh!(z.real) * cos!(z.imag),
|
|
|
|
sinh!(z.real) * sin!(z.imag))
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
2011-05-17 17:09:39 -04:00
|
|
|
# returns the hyperbolic tangent of +z+, where +z+ is given in radians
|
2008-04-05 10:25:40 -04:00
|
|
|
def tanh(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real?
|
2014-08-08 21:36:49 -04:00
|
|
|
tanh!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
sinh(z) / cosh(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
|
|
|
# returns the arc sine of +z+
|
2008-04-05 10:25:40 -04:00
|
|
|
def asin(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real? and z >= -1 and z <= 1
|
2014-08-08 21:36:49 -04:00
|
|
|
asin!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
(-1.0).i * log(1.0.i * z + sqrt(1.0 - z * z))
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
|
|
|
# returns the arc cosine of +z+
|
2008-04-05 10:25:40 -04:00
|
|
|
def acos(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real? and z >= -1 and z <= 1
|
2014-08-08 21:36:49 -04:00
|
|
|
acos!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
(-1.0).i * log(z + 1.0.i * sqrt(1.0 - z * z))
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
|
|
|
# returns the arc tangent of +z+
|
2008-04-05 10:25:40 -04:00
|
|
|
def atan(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real?
|
2014-08-08 21:36:49 -04:00
|
|
|
atan!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
1.0.i * log((1.0.i + z) / (1.0.i - z)) / 2.0
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
2011-05-17 17:09:39 -04:00
|
|
|
# returns the arc tangent of +y+ divided by +x+ using the signs of +y+ and
|
|
|
|
# +x+ to determine the quadrant
|
2008-04-05 10:25:40 -04:00
|
|
|
def atan2(y,x)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if y.real? and x.real?
|
2014-08-08 21:36:49 -04:00
|
|
|
atan2!(y,x)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
(-1.0).i * log((x + 1.0.i * y) / sqrt(x * x + y * y))
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
|
|
|
# returns the inverse hyperbolic sine of +z+
|
2008-04-05 10:25:40 -04:00
|
|
|
def asinh(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real?
|
2014-08-08 21:36:49 -04:00
|
|
|
asinh!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
log(z + sqrt(1.0 + z * z))
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
|
|
|
# returns the inverse hyperbolic cosine of +z+
|
2009-06-11 08:08:30 -04:00
|
|
|
def acosh(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real? and z >= 1
|
2014-08-08 21:36:49 -04:00
|
|
|
acosh!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
log(z + sqrt(z * z - 1.0))
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2009-06-11 08:08:30 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-17 15:54:40 -04:00
|
|
|
##
|
|
|
|
# returns the inverse hyperbolic tangent of +z+
|
2008-04-05 10:25:40 -04:00
|
|
|
def atanh(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
begin
|
|
|
|
if z.real? and z >= -1 and z <= 1
|
2014-08-08 21:36:49 -04:00
|
|
|
atanh!(z)
|
2011-06-29 11:31:37 -04:00
|
|
|
else
|
2014-08-08 21:36:49 -04:00
|
|
|
log((1.0 + z) / (1.0 - z)) / 2.0
|
2011-06-29 11:31:37 -04:00
|
|
|
end
|
|
|
|
rescue NoMethodError
|
|
|
|
handle_no_method_error
|
2008-04-05 10:25:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module_function :exp!
|
|
|
|
module_function :exp
|
|
|
|
module_function :log!
|
|
|
|
module_function :log
|
2010-04-26 07:14:40 -04:00
|
|
|
module_function :log2!
|
|
|
|
module_function :log2
|
2008-04-05 10:25:40 -04:00
|
|
|
module_function :log10!
|
|
|
|
module_function :log10
|
|
|
|
module_function :sqrt!
|
|
|
|
module_function :sqrt
|
2010-04-26 07:14:40 -04:00
|
|
|
module_function :cbrt!
|
|
|
|
module_function :cbrt
|
2008-04-05 10:25:40 -04:00
|
|
|
|
|
|
|
module_function :sin!
|
|
|
|
module_function :sin
|
|
|
|
module_function :cos!
|
|
|
|
module_function :cos
|
|
|
|
module_function :tan!
|
|
|
|
module_function :tan
|
|
|
|
|
|
|
|
module_function :sinh!
|
|
|
|
module_function :sinh
|
|
|
|
module_function :cosh!
|
|
|
|
module_function :cosh
|
|
|
|
module_function :tanh!
|
|
|
|
module_function :tanh
|
|
|
|
|
|
|
|
module_function :asin!
|
|
|
|
module_function :asin
|
|
|
|
module_function :acos!
|
|
|
|
module_function :acos
|
|
|
|
module_function :atan!
|
|
|
|
module_function :atan
|
|
|
|
module_function :atan2!
|
|
|
|
module_function :atan2
|
|
|
|
|
|
|
|
module_function :asinh!
|
|
|
|
module_function :asinh
|
|
|
|
module_function :acosh!
|
|
|
|
module_function :acosh
|
|
|
|
module_function :atanh!
|
|
|
|
module_function :atanh
|
|
|
|
|
2008-10-18 18:43:06 -04:00
|
|
|
module_function :frexp
|
|
|
|
module_function :ldexp
|
|
|
|
module_function :hypot
|
|
|
|
module_function :erf
|
|
|
|
module_function :erfc
|
|
|
|
module_function :gamma
|
|
|
|
module_function :lgamma
|
|
|
|
|
2011-06-29 11:31:37 -04:00
|
|
|
private
|
2011-06-29 20:22:32 -04:00
|
|
|
def handle_no_method_error # :nodoc:
|
2011-06-29 11:31:37 -04:00
|
|
|
if $!.name == :real?
|
|
|
|
raise TypeError, "Numeric Number required"
|
|
|
|
else
|
|
|
|
raise
|
|
|
|
end
|
2011-06-13 06:48:12 -04:00
|
|
|
end
|
2011-06-29 11:31:37 -04:00
|
|
|
module_function :handle_no_method_error
|
|
|
|
|
2011-06-13 06:48:12 -04:00
|
|
|
end
|