diff options
| author | Ukrainskiy Sergey <[email protected]> | 2018-09-09 11:57:16 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2019-05-15 16:57:21 +0900 |
| commit | d67d2ae8e88b93536e71dfa41a90721ce351da7c (patch) | |
| tree | 25b8e534e0864817bf05dee8022004fa04e22fc7 /mrbgems/mruby-complex | |
| parent | 79c3335e8d22ec76340b3028a7bbc658d631b17c (diff) | |
| download | mruby-d67d2ae8e88b93536e71dfa41a90721ce351da7c.tar.gz mruby-d67d2ae8e88b93536e71dfa41a90721ce351da7c.zip | |
Basic implementation of Complex and Rational classes
Diffstat (limited to 'mrbgems/mruby-complex')
| -rw-r--r-- | mrbgems/mruby-complex/mrbgem.rake | 4 | ||||
| -rw-r--r-- | mrbgems/mruby-complex/mrblib/complex.rb | 155 | ||||
| -rw-r--r-- | mrbgems/mruby-complex/test/complex.rb | 129 |
3 files changed, 246 insertions, 42 deletions
diff --git a/mrbgems/mruby-complex/mrbgem.rake b/mrbgems/mruby-complex/mrbgem.rake index f8f04d0b8..25b8966da 100644 --- a/mrbgems/mruby-complex/mrbgem.rake +++ b/mrbgems/mruby-complex/mrbgem.rake @@ -2,4 +2,8 @@ MRuby::Gem::Specification.new('mruby-complex') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.summary = 'Complex class' + + spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' + spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' + spec.add_dependency 'mruby-math', core: 'mruby-math' end diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 0815c9a71..266c00c36 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -1,95 +1,168 @@ class Complex < Numeric - def initialize(real = 0, imaginary = 0) + def initialize(real, imaginary) + real = real.to_f unless real.is_a? Numeric + imaginary = imaginary.to_f unless imaginary.is_a? Numeric @real = real @imaginary = imaginary end + def self.polar(abs, arg = 0) + Complex(abs * Math.cos(arg), abs * Math.sin(arg)) + end + + def self.rectangular(real, imaginary = 0) + _new(real, imaginary) + end + def inspect "(#{to_s})" end def to_s - "#{real}#{'+'}#{imaginary}i" + "#{real}#{'+' unless imaginary.negative?}#{imaginary}i" end def +@ - Complex.new(real, imaginary) + Complex(real, imaginary) end def -@ - Complex.new(-real, -imaginary) + Complex(-real, -imaginary) end def +(rhs) if rhs.is_a? Complex - Complex.new(real + rhs.real, imaginary + rhs.imaginary) + Complex(real + rhs.real, imaginary + rhs.imaginary) elsif rhs.is_a? Numeric - Complex.new(real + rhs, imaginary) + Complex(real + rhs, imaginary) end end def -(rhs) if rhs.is_a? Complex - Complex.new(real - rhs.real, imaginary - rhs.imaginary) + Complex(real - rhs.real, imaginary - rhs.imaginary) elsif rhs.is_a? Numeric - Complex.new(real - rhs, imaginary) + Complex(real - rhs, imaginary) end end def *(rhs) if rhs.is_a? Complex - Complex.new(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) + Complex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) elsif rhs.is_a? Numeric - Complex.new(real * rhs, imaginary * rhs) + Complex(real * rhs, imaginary * rhs) end end def /(rhs) if rhs.is_a? Complex div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary - Complex.new((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) + Complex((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) elsif rhs.is_a? Numeric - Complex.new(real / rhs, imaginary / rhs) + Complex(real / rhs, imaginary / rhs) end end + alias_method :quo, :/ - attr_reader :real, :imaginary -end + def ==(rhs) + if rhs.is_a? Complex + real == rhs.real && imaginary == rhs.imaginary + elsif rhs.is_a? Numeric + imaginary.zero? && real == rhs + end + end -def Complex(real = 0, imaginary = 0) - Complex.new(real, imaginary) -end + def abs + Math.sqrt(abs2) + end + alias_method :magnitude, :abs -module ForwardOperatorToComplex - def __forward_operator_to_complex(op, &b) - original_operator_name = "__original_operator_#{op}_complex" - alias_method original_operator_name, op - define_method op do |rhs| - if rhs.is_a? Complex - Complex.new(self).send(op, rhs) - else - send(original_operator_name, rhs) - end - end + def abs2 + real * real + imaginary * imaginary + end + + def arg + Math.atan2 imaginary, real + end + alias_method :angle, :arg + alias_method :phase, :arg + + def conjugate + Complex(real, -imaginary) + end + alias_method :conj, :conjugate + + def numerator + self + end + + def denominator + 1 + end + + def fdiv(numeric) + Complex(real.to_f / numeric, imaginary.to_f / numeric) + end + + def polar + [abs, arg] + end + + def real? + false end - def __forward_operators_to_complex - __forward_operator_to_complex :+ - __forward_operator_to_complex :- - __forward_operator_to_complex :* - __forward_operator_to_complex :/ + def rectangular + [real, imaginary] + end + alias_method :rect, :rectangular + + def to_c + self + end + + def to_f + raise RangeError.new "can't convert #{to_s} into Float" unless imaginary.zero? + real.to_f + end - singleton_class.undef_method :__forward_operator_to_complex - singleton_class.undef_method :__forward_operators_to_complex + def to_i + raise RangeError.new "can't convert #{to_s} into Integer" unless imaginary.zero? + real.to_i end + + def to_r + raise RangeError.new "can't convert #{to_s} into Rational" unless imaginary.zero? + Rational(real, 1) + end + + attr_reader :real, :imaginary + alias_method :imag, :imaginary +end + +class << Complex + alias_method :_new, :new + undef_method :new + + alias_method :rect, :rectangular end -class Fixnum - extend ForwardOperatorToComplex - __forward_operators_to_complex +def Complex(real, imaginary = 0) + Complex.rectangular(real, imaginary) end -class Float - extend ForwardOperatorToComplex - __forward_operators_to_complex +[Fixnum, Float].each do |cls| + [:+, :-, :*, :/, :==].each do |op| + cls.instance_exec do + original_operator_name = "__original_operator_#{op}_complex" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Complex + Complex(self).send(op, rhs) + else + send(original_operator_name, rhs) + end + end + end + end end
\ No newline at end of file diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index 890dd4ff1..ca58202c2 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,3 +1,130 @@ +def assert_complex(real, exp) + assert_float real.real, exp.real + assert_float real.imaginary, exp.imaginary +end + assert 'Complex' do - assert_equal Complex, 0i.class + c = 123i + assert_equal Complex, c.class + assert_equal [c.real, c.imaginary], [0, 123] + c = 123 + -1.23i + assert_equal Complex, c.class + assert_equal [c.real, c.imaginary], [123, -1.23] +end + +assert 'Complex::polar' do + assert_complex Complex.polar(3, 0), (3 + 0i) + assert_complex Complex.polar(3, Math::PI/2), (0 + 3i) + assert_complex Complex.polar(3, Math::PI), (-3 + 0i) + assert_complex Complex.polar(3, -Math::PI/2), (0 + -3i) +end + +assert 'Complex::rectangular' do + assert_complex Complex.rectangular(1, 2), (1 + 2i) +end + +assert 'Complex#*' do + assert_complex Complex(2, 3) * Complex(2, 3), (-5 + 12i) + assert_complex Complex(900) * Complex(1), (900 + 0i) + assert_complex Complex(-2, 9) * Complex(-9, 2), (0 - 85i) + assert_complex Complex(9, 8) * 4, (36 + 32i) + assert_complex Complex(20, 9) * 9.8, (196.0 + 88.2i) +end + +assert 'Complex#+' do + assert_complex Complex(2, 3) + Complex(2, 3) , (4 + 6i) + assert_complex Complex(900) + Complex(1) , (901 + 0i) + assert_complex Complex(-2, 9) + Complex(-9, 2), (-11 + 11i) + assert_complex Complex(9, 8) + 4 , (13 + 8i) + assert_complex Complex(20, 9) + 9.8 , (29.8 + 9i) +end + +assert 'Complex#-' do + assert_complex Complex(2, 3) - Complex(2, 3) , (0 + 0i) + assert_complex Complex(900) - Complex(1) , (899 + 0i) + assert_complex Complex(-2, 9) - Complex(-9, 2), (7 + 7i) + assert_complex Complex(9, 8) - 4 , (5 + 8i) + assert_complex Complex(20, 9) - 9.8 , (10.2 + 9i) +end + +assert 'Complex#-@' do + assert_complex -Complex(1, 2), (-1 - 2i) +end + +assert 'Complex#/' do + assert_complex Complex(2, 3) / Complex(2, 3) , (1 + 0i) + assert_complex Complex(900) / Complex(1) , (900 + 0i) + assert_complex Complex(-2, 9) / Complex(-9, 2), ((36 / 85) - (77i / 85)) + assert_complex Complex(9, 8) / 4 , ((9 / 4) + 2i) + assert_complex Complex(20, 9) / 9.8 , (2.0408163265306123 + 0.9183673469387754i) +end + +assert 'Complex#==' do + assert_true Complex(2, 3) == Complex(2, 3) + assert_true Complex(5) == 5 + assert_true Complex(0) == 0.0 + assert_false Complex('1/3') == 0.33 + assert_false Complex('1/2') == '1/2' +end + +assert 'Complex#abs' do + assert_float Complex(-1).abs, 1 + assert_float Complex(3.0, -4.0).abs, 5.0 +end + +assert 'Complex#abs2' do + assert_float Complex(-1).abs2, 1 + assert_float Complex(3.0, -4.0).abs2, 25.0 +end + +assert 'Complex#arg' do + assert_float Complex.polar(3, Math::PI/2).arg, 1.5707963267948966 +end + +assert 'Complex#conjugate' do + assert_complex Complex(1, 2).conjugate, (1 - 2i) +end + +assert 'Complex#fdiv' do + assert_complex Complex(11, 22).fdiv(3), (3.6666666666666665 + 7.333333333333333i) +end + +assert 'Complex#imaginary' do + assert_float Complex(7).imaginary , 0 + assert_float Complex(9, -4).imaginary, -4 +end + +assert 'Complex#polar' do + assert_equal Complex(1, 2).polar, [2.23606797749979, 1.1071487177940904] +end + +assert 'Complex#real' do + assert_float Complex(7).real, 7 + assert_float Complex(9, -4).real, 9 +end + +assert 'Complex#real?' do + assert_false Complex(1).real? +end + +assert 'Complex::rectangular' do + assert_equal Complex(1, 2).rectangular, [1, 2] +end + +assert 'Complex::to_c' do + assert_equal Complex(1, 2).to_c, Complex(1, 2) +end + +assert 'Complex::to_f' do + assert_float Complex(1, 0).to_f, 1.0 + assert_raise(RangeError) do + Complex(1, 2).to_f + end +end + +assert 'Complex::to_i' do + assert_equal Complex(1, 0).to_i, 1 + assert_raise(RangeError) do + Complex(1, 2).to_i + end end
\ No newline at end of file |
