summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-complex
diff options
context:
space:
mode:
authorUkrainskiy Sergey <[email protected]>2018-09-09 11:57:16 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2019-05-15 16:57:21 +0900
commitd67d2ae8e88b93536e71dfa41a90721ce351da7c (patch)
tree25b8e534e0864817bf05dee8022004fa04e22fc7 /mrbgems/mruby-complex
parent79c3335e8d22ec76340b3028a7bbc658d631b17c (diff)
downloadmruby-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.rake4
-rw-r--r--mrbgems/mruby-complex/mrblib/complex.rb155
-rw-r--r--mrbgems/mruby-complex/test/complex.rb129
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