mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Basic implementation of Complex and Rational classes
This commit is contained in:
committed by
Yukihiro "Matz" Matsumoto
parent
79c3335e8d
commit
d67d2ae8e8
@@ -69,10 +69,10 @@ MRuby::GemBox.new do |conf|
|
||||
conf.gem :core => "mruby-enum-lazy"
|
||||
|
||||
# Use Complex class
|
||||
#conf.gem :core => "mruby-complex"
|
||||
# conf.gem :core => "mruby-complex"
|
||||
|
||||
# Use Rational class
|
||||
#conf.gem :core => "mruby-rational"
|
||||
# conf.gem :core => "mruby-rational"
|
||||
|
||||
# Use toplevel object (main) methods extension
|
||||
conf.gem :core => "mruby-toplevel-ext"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, :/
|
||||
|
||||
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 abs
|
||||
Math.sqrt(abs2)
|
||||
end
|
||||
alias_method :magnitude, :abs
|
||||
|
||||
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 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
|
||||
|
||||
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
|
||||
|
||||
def Complex(real = 0, imaginary = 0)
|
||||
Complex.new(real, imaginary)
|
||||
class << Complex
|
||||
alias_method :_new, :new
|
||||
undef_method :new
|
||||
|
||||
alias_method :rect, :rectangular
|
||||
end
|
||||
|
||||
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)
|
||||
def Complex(real, imaginary = 0)
|
||||
Complex.rectangular(real, imaginary)
|
||||
end
|
||||
|
||||
[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
|
||||
|
||||
def __forward_operators_to_complex
|
||||
__forward_operator_to_complex :+
|
||||
__forward_operator_to_complex :-
|
||||
__forward_operator_to_complex :*
|
||||
__forward_operator_to_complex :/
|
||||
|
||||
singleton_class.undef_method :__forward_operator_to_complex
|
||||
singleton_class.undef_method :__forward_operators_to_complex
|
||||
end
|
||||
end
|
||||
|
||||
class Fixnum
|
||||
extend ForwardOperatorToComplex
|
||||
__forward_operators_to_complex
|
||||
end
|
||||
|
||||
class Float
|
||||
extend ForwardOperatorToComplex
|
||||
__forward_operators_to_complex
|
||||
end
|
||||
@@ -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
|
||||
@@ -2,4 +2,7 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'Rational class'
|
||||
|
||||
spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext'
|
||||
spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext'
|
||||
end
|
||||
|
||||
@@ -2,6 +2,68 @@ class Rational < Numeric
|
||||
def initialize(numerator = 0, denominator = 1)
|
||||
@numerator = numerator
|
||||
@denominator = denominator
|
||||
|
||||
_simplify
|
||||
end
|
||||
|
||||
def inspect
|
||||
"(#{to_s})"
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{numerator}/#{denominator}"
|
||||
end
|
||||
|
||||
def *(rhs)
|
||||
if rhs.is_a? Rational
|
||||
Rational(numerator * rhs.numerator, denominator * rhs.denominator)
|
||||
elsif rhs.is_a? Integer
|
||||
Rational(numerator * rhs, denominator)
|
||||
elsif rhs.is_a? Numeric
|
||||
numerator * rhs / denominator
|
||||
end
|
||||
end
|
||||
|
||||
def +(rhs)
|
||||
if rhs.is_a? Rational
|
||||
Rational(numerator * rhs.denominator + rhs.numerator * denominator, denominator * rhs.denominator)
|
||||
elsif rhs.is_a? Integer
|
||||
Rational(numerator + rhs * denominator, denominator)
|
||||
elsif rhs.is_a? Numeric
|
||||
(numerator + rhs * denominator) / denominator
|
||||
end
|
||||
end
|
||||
|
||||
def -(rhs)
|
||||
if rhs.is_a? Rational
|
||||
Rational(numerator * rhs.denominator - rhs.numerator * denominator, denominator * rhs.denominator)
|
||||
elsif rhs.is_a? Integer
|
||||
Rational(numerator - rhs * denominator, denominator)
|
||||
elsif rhs.is_a? Numeric
|
||||
(numerator - rhs * denominator) / denominator
|
||||
end
|
||||
end
|
||||
|
||||
def /(rhs)
|
||||
if rhs.is_a? Rational
|
||||
Rational(numerator * rhs.denominator, denominator * rhs.numerator)
|
||||
elsif rhs.is_a? Integer
|
||||
Rational(numerator, denominator * rhs)
|
||||
elsif rhs.is_a? Numeric
|
||||
numerator / rhs / denominator
|
||||
end
|
||||
end
|
||||
|
||||
def negative?
|
||||
numerator.negative?
|
||||
end
|
||||
|
||||
def _simplify
|
||||
a = numerator
|
||||
b = denominator
|
||||
a, b = b, a % b while !b.zero?
|
||||
@numerator /= a
|
||||
@denominator /= a
|
||||
end
|
||||
|
||||
attr_reader :numerator, :denominator
|
||||
@@ -11,36 +73,18 @@ def Rational(numerator = 0, denominator = 1)
|
||||
Rational.new(numerator, denominator)
|
||||
end
|
||||
|
||||
module ForwardOperatorToRational
|
||||
def __forward_operator_to_rational(op, &b)
|
||||
original_operator_name = "__original_operator_#{op}_rational"
|
||||
alias_method original_operator_name, op
|
||||
define_method op do |rhs|
|
||||
if rhs.is_a? Rational
|
||||
Rational.new(self).send(op, rhs)
|
||||
else
|
||||
send(original_operator_name, rhs)
|
||||
[Fixnum, Float].each do |cls|
|
||||
[:+, :-, :*, :/, :==].each do |op|
|
||||
cls.instance_exec do
|
||||
original_operator_name = "__original_operator_#{op}_rational"
|
||||
alias_method original_operator_name, op
|
||||
define_method op do |rhs|
|
||||
if rhs.is_a? Rational
|
||||
Rational(self).send(op, rhs)
|
||||
else
|
||||
send(original_operator_name, rhs)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def __forward_operators_to_rational
|
||||
__forward_operator_to_rational :+
|
||||
__forward_operator_to_rational :-
|
||||
__forward_operator_to_rational :*
|
||||
__forward_operator_to_rational :/
|
||||
|
||||
singleton_class.undef_method :__forward_operator_to_rational
|
||||
singleton_class.undef_method :__forward_operators_to_rational
|
||||
end
|
||||
end
|
||||
|
||||
class Fixnum
|
||||
extend ForwardOperatorToRational
|
||||
__forward_operators_to_rational
|
||||
end
|
||||
|
||||
class Float
|
||||
extend ForwardOperatorToRational
|
||||
__forward_operators_to_rational
|
||||
end
|
||||
@@ -1,3 +1,42 @@
|
||||
def assert_rational(real, exp)
|
||||
assert_float real.numerator, exp.numerator
|
||||
assert_float real.denominator, exp.denominator
|
||||
end
|
||||
|
||||
assert 'Rational' do
|
||||
assert_equal Rational, 0r.class
|
||||
r = 5r
|
||||
assert_equal Rational, r.class
|
||||
assert_equal [r.numerator, r.denominator], [5, 1]
|
||||
end
|
||||
|
||||
assert 'Rational#*' do
|
||||
assert_rational Rational(2, 3) * Rational(2, 3), Rational(4, 9)
|
||||
assert_rational Rational(900) * Rational(1), Rational(900, 1)
|
||||
assert_rational Rational(-2, 9) * Rational(-9, 2), Rational(1, 1)
|
||||
assert_rational Rational(9, 8) * 4, Rational(9, 2)
|
||||
assert_float Rational(20, 9) * 9.8, 21.77777777777778
|
||||
end
|
||||
|
||||
assert 'Rational#+' do
|
||||
assert_rational Rational(2, 3) + Rational(2, 3), Rational(4, 3)
|
||||
assert_rational Rational(900) + Rational(1), Rational(901, 1)
|
||||
assert_rational Rational(-2, 9) + Rational(-9, 2), Rational(-85, 18)
|
||||
assert_rational Rational(9, 8) + 4, Rational(41, 8)
|
||||
assert_float Rational(20, 9) + 9.8, 12.022222222222222
|
||||
end
|
||||
|
||||
assert 'Rational#-' do
|
||||
assert_rational Rational(2, 3) - Rational(2, 3), Rational(0, 1)
|
||||
assert_rational Rational(900) - Rational(1), Rational(899, 1)
|
||||
assert_rational Rational(-2, 9) - Rational(-9, 2), Rational(77, 18)
|
||||
assert_rational Rational(9, 8) - 4, Rational(-23, 8)
|
||||
assert_float Rational(20, 9) - 9.8, -7.577777777777778
|
||||
end
|
||||
|
||||
assert 'Rational#/' do
|
||||
assert_rational Rational(2, 3) / Rational(2, 3), Rational(1, 1)
|
||||
assert_rational Rational(900) / Rational(1), Rational(900, 1)
|
||||
assert_rational Rational(-2, 9) / Rational(-9, 2), Rational(4, 81)
|
||||
assert_rational Rational(9, 8) / 4, Rational(9, 32)
|
||||
assert_float Rational(20, 9) / 9.8, 0.22675736961451246
|
||||
end
|
||||
Reference in New Issue
Block a user