home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / complex.rb < prev    next >
Encoding:
Ruby Source  |  2003-07-31  |  12.3 KB  |  632 lines

  1. #
  2. #   complex.rb - 
  3. #       $Release Version: 0.5 $
  4. #       $Revision: 1.3 $
  5. #       $Date: 1998/07/08 10:05:28 $
  6. #       by Keiju ISHITSUKA(SHL Japan Inc.)
  7. #
  8. # ----
  9. #
  10. # complex.rb implements the Complex class for complex numbers.  Additionally,
  11. # some methods in other Numeric classes are redefined or added to allow greater
  12. # interoperability with Complex numbers.
  13. #
  14. # Complex numbers can be created in the following manner:
  15. # - <tt>Complex(a, b)</tt>
  16. # - <tt>Complex.polar(radius, theta)</tt>
  17. #   
  18. # Additionally, note the following:
  19. # - <tt>Complex::I</tt> (the mathematical constant <i>i</i>)
  20. # - <tt>Numeric#im</tt> (e.g. <tt>5.im -> 0+5i</tt>)
  21. #
  22. # The following +Math+ module methods are redefined to handle Complex arguments.
  23. # They will work as normal with non-Complex arguments.
  24. #    sqrt exp cos sin tan log log10
  25. #    cosh sinh tanh acos asin atan atan2 acosh asinh atanh
  26. #
  27.  
  28.  
  29. #
  30. # Numeric is a built-in class on which Fixnum, Bignum, etc., are based.  Here
  31. # some methods are added so that all number types can be treated to some extent
  32. # as Complex numbers.
  33. #
  34. class Numeric
  35.   #
  36.   # Returns a Complex number <tt>(0,<i>self</i>)</tt>.
  37.   #
  38.   def im
  39.     Complex(0, self)
  40.   end
  41.   
  42.   #
  43.   # The real part of a complex number, i.e. <i>self</i>.
  44.   #
  45.   def real
  46.     self
  47.   end
  48.   
  49.   #
  50.   # The imaginary part of a complex number, i.e. 0.
  51.   #
  52.   def image
  53.     0
  54.   end
  55.   alias imag image
  56.   
  57.   #
  58.   # See Complex#arg.
  59.   #
  60.   def arg
  61.     if self >= 0
  62.       return 0
  63.     else
  64.       return Math::PI
  65.     end
  66.   end
  67.   alias angle arg
  68.   
  69.   #
  70.   # See Complex#polar.
  71.   #
  72.   def polar
  73.     return abs, arg
  74.   end
  75.   
  76.   #
  77.   # See Complex#conjugate (short answer: returns <i>self</i>).
  78.   #
  79.   def conjugate
  80.     self
  81.   end
  82.   alias conj conjugate
  83. end
  84.  
  85.  
  86. #
  87. # Creates a Complex number.  +a+ and +b+ should be Numeric.  The result will be
  88. # <tt>a+bi</tt>.
  89. #
  90. def Complex(a, b = 0)
  91.   if b == 0 and (a.kind_of?(Complex) or defined? Complex::Unify)
  92.     a
  93.   else
  94.     Complex.new( a.real-b.imag, a.imag+b.real )
  95.   end
  96. end
  97.  
  98. #
  99. # The complex number class.  See complex.rb for an overview.
  100. #
  101. class Complex < Numeric
  102.   @RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-'
  103.  
  104.   undef step
  105.  
  106.   def Complex.generic?(other) # :nodoc:
  107.     other.kind_of?(Integer) or
  108.     other.kind_of?(Float) or
  109.     (defined?(Rational) and other.kind_of?(Rational))
  110.   end
  111.  
  112.   #
  113.   # Creates a +Complex+ number in terms of +r+ (radius) and +theta+ (angle).
  114.   #
  115.   def Complex.polar(r, theta)
  116.     Complex(r*Math.cos(theta), r*Math.sin(theta))
  117.   end
  118.  
  119.   #
  120.   # Creates a +Complex+ number <tt>a</tt>+<tt>b</tt><i>i</i>.
  121.   #
  122.   def Complex.new!(a, b=0)
  123.     new(a,b)
  124.   end
  125.  
  126.   def initialize(a, b)
  127.     raise TypeError, "non numeric 1st arg `#{a.inspect}'" if !a.kind_of? Numeric
  128.     raise TypeError, "`#{a.inspect}' for 1st arg" if a.kind_of? Complex
  129.     raise TypeError, "non numeric 2nd arg `#{b.inspect}'" if !b.kind_of? Numeric
  130.     raise TypeError, "`#{b.inspect}' for 2nd arg" if b.kind_of? Complex
  131.     @real = a
  132.     @image = b
  133.   end
  134.  
  135.   #
  136.   # Addition with real or complex number.
  137.   #
  138.   def + (other)
  139.     if other.kind_of?(Complex)
  140.       re = @real + other.real
  141.       im = @image + other.image
  142.       Complex(re, im)
  143.     elsif Complex.generic?(other)
  144.       Complex(@real + other, @image)
  145.     else
  146.       x , y = other.coerce(self)
  147.       x + y
  148.     end
  149.   end
  150.   
  151.   #
  152.   # Subtraction with real or complex number.
  153.   #
  154.   def - (other)
  155.     if other.kind_of?(Complex)
  156.       re = @real - other.real
  157.       im = @image - other.image
  158.       Complex(re, im)
  159.     elsif Complex.generic?(other)
  160.       Complex(@real - other, @image)
  161.     else
  162.       x , y = other.coerce(self)
  163.       x - y
  164.     end
  165.   end
  166.   
  167.   #
  168.   # Multiplication with real or complex number.
  169.   #
  170.   def * (other)
  171.     if other.kind_of?(Complex)
  172.       re = @real*other.real - @image*other.image
  173.       im = @real*other.image + @image*other.real
  174.       Complex(re, im)
  175.     elsif Complex.generic?(other)
  176.       Complex(@real * other, @image * other)
  177.     else
  178.       x , y = other.coerce(self)
  179.       x * y
  180.     end
  181.   end
  182.   
  183.   #
  184.   # Division by real or complex number.
  185.   #
  186.   def / (other)
  187.     if other.kind_of?(Complex)
  188.       self*other.conjugate/other.abs2
  189.     elsif Complex.generic?(other)
  190.       Complex(@real/other, @image/other)
  191.     else
  192.       x, y = other.coerce(self)
  193.       x/y
  194.     end
  195.   end
  196.   
  197.   #
  198.   # Raise this complex number to the given (real or complex) power.
  199.   #
  200.   def ** (other)
  201.     if other == 0
  202.       return Complex(1)
  203.     end
  204.     if other.kind_of?(Complex)
  205.       r, theta = polar
  206.       ore = other.real
  207.       oim = other.image
  208.       nr = Math.exp!(ore*Math.log!(r) - oim * theta)
  209.       ntheta = theta*ore + oim*Math.log!(r)
  210.       Complex.polar(nr, ntheta)
  211.     elsif other.kind_of?(Integer)
  212.       if other > 0
  213.     x = self
  214.     z = x
  215.     n = other - 1
  216.     while n != 0
  217.       while (div, mod = n.divmod(2)
  218.          mod == 0)
  219.         x = Complex(x.real*x.real - x.image*x.image, 2*x.real*x.image)
  220.         n = div
  221.       end
  222.       z *= x
  223.       n -= 1
  224.     end
  225.     z
  226.       else
  227.     if defined? Rational
  228.       (Rational(1) / self) ** -other
  229.     else
  230.       self ** Float(other)
  231.     end
  232.       end
  233.     elsif Complex.generic?(other)
  234.       r, theta = polar
  235.       Complex.polar(r**other, theta*other)
  236.     else
  237.       x, y = other.coerce(self)
  238.       x**y
  239.     end
  240.   end
  241.   
  242.   #
  243.   # Remainder after division by a real or complex number.
  244.   #
  245.   def % (other)
  246.     if other.kind_of?(Complex)
  247.       Complex(@real % other.real, @image % other.image)
  248.     elsif Complex.generic?(other)
  249.       Complex(@real % other, @image % other)
  250.     else
  251.       x , y = other.coerce(self)
  252.       x % y
  253.     end
  254.   end
  255.   
  256. #--
  257. #    def divmod(other)
  258. #      if other.kind_of?(Complex)
  259. #        rdiv, rmod = @real.divmod(other.real)
  260. #        idiv, imod = @image.divmod(other.image)
  261. #        return Complex(rdiv, idiv), Complex(rmod, rmod)
  262. #      elsif Complex.generic?(other)
  263. #        Complex(@real.divmod(other), @image.divmod(other))
  264. #      else
  265. #        x , y = other.coerce(self)
  266. #        x.divmod(y)
  267. #      end
  268. #    end
  269. #++
  270.   
  271.   #
  272.   # Absolute value (aka modulus): distance from the zero point on the complex
  273.   # plane.
  274.   #
  275.   def abs
  276.     Math.hypot(@real, @image)
  277.   end
  278.   
  279.   #
  280.   # Square of the absolute value.
  281.   #
  282.   def abs2
  283.     @real*@real + @image*@image
  284.   end
  285.   
  286.   #
  287.   # Argument (angle from (1,0) on the complex plane).
  288.   #
  289.   def arg
  290.     Math.atan2!(@image, @real)
  291.   end
  292.   alias angle arg
  293.   
  294.   #
  295.   # Returns the absolute value _and_ the argument.
  296.   #
  297.   def polar
  298.     return abs, arg
  299.   end
  300.   
  301.   #
  302.   # Complex conjugate (<tt>z + z.conjugate = 2 * z.real</tt>).
  303.   #
  304.   def conjugate
  305.     Complex(@real, -@image)
  306.   end
  307.   alias conj conjugate
  308.   
  309.   #
  310.   # Compares the absolute values of the two numbers.
  311.   #
  312.   def <=> (other)
  313.     self.abs <=> other.abs
  314.   end
  315.   
  316.   #
  317.   # Test for numerical equality (<tt>a == a + 0<i>i</i></tt>).
  318.   #
  319.   def == (other)
  320.     if other.kind_of?(Complex)
  321.       @real == other.real and @image == other.image
  322.     elsif Complex.generic?(other)
  323.       @real == other and @image == 0
  324.     else
  325.       other == self
  326.     end
  327.   end
  328.  
  329.   #
  330.   # Attempts to coerce +other+ to a Complex number.
  331.   #
  332.   def coerce(other)
  333.     if Complex.generic?(other)
  334.       return Complex.new!(other), self
  335.     else
  336.       super
  337.     end
  338.   end
  339.  
  340.   #
  341.   # FIXME
  342.   #
  343.   def denominator
  344.     @real.denominator.lcm(@image.denominator)
  345.   end
  346.   
  347.   #
  348.   # FIXME
  349.   #
  350.   def numerator
  351.     cd = denominator
  352.     Complex(@real.numerator*(cd/@real.denominator),
  353.         @image.numerator*(cd/@image.denominator))
  354.   end
  355.   
  356.   #
  357.   # Standard string representation of the complex number.
  358.   #
  359.   def to_s
  360.     if @real != 0
  361.       if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
  362.     if @image >= 0
  363.       @real.to_s+"+("+@image.to_s+")i"
  364.     else
  365.       @real.to_s+"-("+(-@image).to_s+")i"
  366.     end
  367.       else
  368.     if @image >= 0
  369.       @real.to_s+"+"+@image.to_s+"i"
  370.     else
  371.       @real.to_s+"-"+(-@image).to_s+"i"
  372.     end
  373.       end
  374.     else
  375.       if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
  376.     "("+@image.to_s+")i"
  377.       else
  378.     @image.to_s+"i"
  379.       end
  380.     end
  381.   end
  382.   
  383.   #
  384.   # Returns a hash code for the complex number.
  385.   #
  386.   def hash
  387.     @real.hash ^ @image.hash
  388.   end
  389.   
  390.   #
  391.   # Returns "<tt>Complex(<i>real</i>, <i>image</i>)</tt>".
  392.   #
  393.   def inspect
  394.     sprintf("Complex(%s, %s)", @real.inspect, @image.inspect)
  395.   end
  396.  
  397.   
  398.   #
  399.   # +I+ is the imaginary number.  It exists at point (0,1) on the complex plane.
  400.   #
  401.   I = Complex(0,1)
  402.   
  403.   # The real part of a complex number.
  404.   attr :real
  405.  
  406.   # The imaginary part of a complex number.
  407.   attr :image
  408.   alias imag image
  409.   
  410. end
  411.  
  412.  
  413.  
  414.  
  415. module Math
  416.   alias sqrt! sqrt
  417.   alias exp! exp
  418.   alias log! log
  419.   alias log10! log10
  420.   alias cos! cos
  421.   alias sin! sin
  422.   alias tan! tan
  423.   alias cosh! cosh
  424.   alias sinh! sinh
  425.   alias tanh! tanh
  426.   alias acos! acos
  427.   alias asin! asin
  428.   alias atan! atan
  429.   alias atan2! atan2
  430.   alias acosh! acosh
  431.   alias asinh! asinh
  432.   alias atanh! atanh  
  433.  
  434.   # Redefined to handle a Complex argument.
  435.   def sqrt(z)
  436.     if Complex.generic?(z)
  437.       if z >= 0
  438.     sqrt!(z)
  439.       else
  440.     Complex(0,sqrt!(-z))
  441.       end
  442.     else
  443.       if z.image < 0
  444.     sqrt(z.conjugate).conjugate
  445.       else
  446.     r = z.abs
  447.     x = z.real
  448.     Complex( sqrt!((r+x)/2), sqrt!((r-x)/2) )
  449.       end
  450.     end
  451.   end
  452.   
  453.   # Redefined to handle a Complex argument.
  454.   def exp(z)
  455.     if Complex.generic?(z)
  456.       exp!(z)
  457.     else
  458.       Complex(exp!(z.real) * cos!(z.image), exp!(z.real) * sin!(z.image))
  459.     end
  460.   end
  461.   
  462.   # Redefined to handle a Complex argument.
  463.   def cos(z)
  464.     if Complex.generic?(z)
  465.       cos!(z)
  466.     else
  467.       Complex(cos!(z.real)*cosh!(z.image),
  468.           -sin!(z.real)*sinh!(z.image))
  469.     end
  470.   end
  471.     
  472.   # Redefined to handle a Complex argument.
  473.   def sin(z)
  474.     if Complex.generic?(z)
  475.       sin!(z)
  476.     else
  477.       Complex(sin!(z.real)*cosh!(z.image),
  478.           cos!(z.real)*sinh!(z.image))
  479.     end
  480.   end
  481.   
  482.   # Redefined to handle a Complex argument.
  483.   def tan(z)
  484.     if Complex.generic?(z)
  485.       tan!(z)
  486.     else
  487.       sin(z)/cos(z)
  488.     end
  489.   end
  490.  
  491.   def sinh(z)
  492.     if Complex.generic?(z)
  493.       sinh!(z)
  494.     else
  495.       Complex( sinh!(z.real)*cos!(z.image), cosh!(z.real)*sin!(z.image) )
  496.     end
  497.   end
  498.  
  499.   def cosh(z)
  500.     if Complex.generic?(z)
  501.       cosh!(z)
  502.     else
  503.       Complex( cosh!(z.real)*cos!(z.image), sinh!(z.real)*sin!(z.image) )
  504.     end
  505.   end
  506.  
  507.   def tanh(z)
  508.     if Complex.generic?(z)
  509.       tanh!(z)
  510.     else
  511.       sinh(z)/cosh(z)
  512.     end
  513.   end
  514.   
  515.   # Redefined to handle a Complex argument.
  516.   def log(z)
  517.     if Complex.generic?(z) and z >= 0
  518.       log!(z)
  519.     else
  520.       r, theta = z.polar
  521.       Complex(log!(r.abs), theta)
  522.     end
  523.   end
  524.   
  525.   # Redefined to handle a Complex argument.
  526.   def log10(z)
  527.     if Complex.generic?(z)
  528.       log10!(z)
  529.     else
  530.       log(z)/log!(10)
  531.     end
  532.   end
  533.  
  534.   def acos(z)
  535.     if Complex.generic?(z) and z >= -1 and z <= 1
  536.       acos!(z)
  537.     else
  538.       -1.0.im * log( z + 1.0.im * sqrt(1.0-z*z) )
  539.     end
  540.   end
  541.  
  542.   def asin(z)
  543.     if Complex.generic?(z) and z >= -1 and z <= 1
  544.       asin!(z)
  545.     else
  546.       -1.0.im * log( 1.0.im * z + sqrt(1.0-z*z) )
  547.     end
  548.   end
  549.  
  550.   def atan(z)
  551.     if Complex.generic?(z)
  552.       atan!(z)
  553.     else
  554.       1.0.im * log( (1.0.im+z) / (1.0.im-z) ) / 2.0
  555.     end
  556.   end
  557.  
  558.   def atan2(y,x)
  559.     if Complex.generic?(y) and Complex.generic?(x)
  560.       atan2!(y,x)
  561.     else
  562.       -1.0.im * log( (x+1.0.im*y) / sqrt(x*x+y*y) )
  563.     end
  564.   end
  565.  
  566.   def acosh(z)
  567.     if Complex.generic?(z) and z >= 1
  568.       acosh!(z)
  569.     else
  570.       log( z + sqrt(z*z-1.0) )
  571.     end
  572.   end
  573.  
  574.   def asinh(z)
  575.     if Complex.generic?(z)
  576.       asinh!(z)
  577.     else
  578.       log( z + sqrt(1.0+z*z) )
  579.     end
  580.   end
  581.  
  582.   def atanh(z)
  583.     if Complex.generic?(z) and z >= -1 and z <= 1
  584.       atanh!(z)
  585.     else
  586.       log( (1.0+z) / (1.0-z) ) / 2.0
  587.     end
  588.   end
  589.  
  590.   module_function :sqrt!
  591.   module_function :sqrt
  592.   module_function :exp!
  593.   module_function :exp
  594.   module_function :log!
  595.   module_function :log
  596.   module_function :log10!
  597.   module_function :log10
  598.   module_function :cosh!
  599.   module_function :cosh
  600.   module_function :cos!
  601.   module_function :cos
  602.   module_function :sinh!
  603.   module_function :sinh
  604.   module_function :sin!
  605.   module_function :sin
  606.   module_function :tan!
  607.   module_function :tan
  608.   module_function :tanh!
  609.   module_function :tanh
  610.   module_function :acos!
  611.   module_function :acos
  612.   module_function :asin!
  613.   module_function :asin
  614.   module_function :atan!
  615.   module_function :atan
  616.   module_function :atan2!
  617.   module_function :atan2
  618.   module_function :acosh!
  619.   module_function :acosh
  620.   module_function :asinh!
  621.   module_function :asinh
  622.   module_function :atanh!
  623.   module_function :atanh
  624.   
  625. end
  626.  
  627. # Documentation comments:
  628. #  - source: original (researched from pickaxe)
  629. #  - a couple of fixme's
  630. #  - RDoc output for Bignum etc. is a bit short, with nothing but an
  631. #    (undocumented) alias.  No big deal.
  632.