diff options
Diffstat (limited to 'lib/cmath.rb')
-rw-r--r-- | lib/cmath.rb | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/lib/cmath.rb b/lib/cmath.rb new file mode 100644 index 0000000..d613a3f --- /dev/null +++ b/lib/cmath.rb @@ -0,0 +1,402 @@ +## +# = CMath +# +# 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 +# + +module CMath + + include Math + + alias exp! exp + alias log! log + alias log2! log2 + alias log10! log10 + alias sqrt! sqrt + alias cbrt! cbrt + + 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 + + ## + # 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 + def exp(z) + begin + if z.real? + exp!(z) + else + ere = exp!(z.real) + Complex(ere * cos!(z.imag), + ere * sin!(z.imag)) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # 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 + def log(*args) + begin + z, b = args + unless b.nil? || b.kind_of?(Numeric) + raise TypeError, "Numeric Number required" + end + if z.real? and z >= 0 and (b.nil? or b >= 0) + log!(*args) + else + a = Complex(log!(z.abs), z.arg) + if b + a /= log(b) + end + a + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the base 2 logarithm of +z+ + def log2(z) + begin + if z.real? and z >= 0 + log2!(z) + else + log(z) / log!(2) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the base 10 logarithm of +z+ + def log10(z) + begin + if z.real? and z >= 0 + log10!(z) + else + log(z) / log!(10) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # 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 + def sqrt(z) + begin + if z.real? + if z < 0 + Complex(0, sqrt!(-z)) + else + sqrt!(z) + end + else + 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 + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the principal value of the cube root of +z+ + def cbrt(z) + z ** (1.0/3) + end + + ## + # returns the sine of +z+, where +z+ is given in radians + def sin(z) + begin + if z.real? + sin!(z) + else + Complex(sin!(z.real) * cosh!(z.imag), + cos!(z.real) * sinh!(z.imag)) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the cosine of +z+, where +z+ is given in radians + def cos(z) + begin + if z.real? + cos!(z) + else + Complex(cos!(z.real) * cosh!(z.imag), + -sin!(z.real) * sinh!(z.imag)) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the tangent of +z+, where +z+ is given in radians + def tan(z) + begin + if z.real? + tan!(z) + else + sin(z) / cos(z) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the hyperbolic sine of +z+, where +z+ is given in radians + def sinh(z) + begin + if z.real? + sinh!(z) + else + Complex(sinh!(z.real) * cos!(z.imag), + cosh!(z.real) * sin!(z.imag)) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the hyperbolic cosine of +z+, where +z+ is given in radians + def cosh(z) + begin + if z.real? + cosh!(z) + else + Complex(cosh!(z.real) * cos!(z.imag), + sinh!(z.real) * sin!(z.imag)) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the hyperbolic tangent of +z+, where +z+ is given in radians + def tanh(z) + begin + if z.real? + tanh!(z) + else + sinh(z) / cosh(z) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the arc sine of +z+ + def asin(z) + begin + if z.real? and z >= -1 and z <= 1 + asin!(z) + else + (-1.0).i * log(1.0.i * z + sqrt(1.0 - z * z)) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the arc cosine of +z+ + def acos(z) + begin + if z.real? and z >= -1 and z <= 1 + acos!(z) + else + (-1.0).i * log(z + 1.0.i * sqrt(1.0 - z * z)) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the arc tangent of +z+ + def atan(z) + begin + if z.real? + atan!(z) + else + 1.0.i * log((1.0.i + z) / (1.0.i - z)) / 2.0 + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the arc tangent of +y+ divided by +x+ using the signs of +y+ and + # +x+ to determine the quadrant + def atan2(y,x) + begin + if y.real? and x.real? + atan2!(y,x) + else + (-1.0).i * log((x + 1.0.i * y) / sqrt(x * x + y * y)) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the inverse hyperbolic sine of +z+ + def asinh(z) + begin + if z.real? + asinh!(z) + else + log(z + sqrt(1.0 + z * z)) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the inverse hyperbolic cosine of +z+ + def acosh(z) + begin + if z.real? and z >= 1 + acosh!(z) + else + log(z + sqrt(z * z - 1.0)) + end + rescue NoMethodError + handle_no_method_error + end + end + + ## + # returns the inverse hyperbolic tangent of +z+ + def atanh(z) + begin + if z.real? and z >= -1 and z <= 1 + atanh!(z) + else + log((1.0 + z) / (1.0 - z)) / 2.0 + end + rescue NoMethodError + handle_no_method_error + end + end + + module_function :exp! + module_function :exp + module_function :log! + module_function :log + module_function :log2! + module_function :log2 + module_function :log10! + module_function :log10 + module_function :sqrt! + module_function :sqrt + module_function :cbrt! + module_function :cbrt + + 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 + + module_function :frexp + module_function :ldexp + module_function :hypot + module_function :erf + module_function :erfc + module_function :gamma + module_function :lgamma + + private + def handle_no_method_error # :nodoc: + if $!.name == :real? + raise TypeError, "Numeric Number required" + else + raise + end + end + module_function :handle_no_method_error + +end + |