From 8808219e6d51673e6fa582819703e6e5912439b0 Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Thu, 9 Aug 2018 17:09:02 +0900 Subject: Initial suffix support --- mrbgems/mruby-rational/mrbgem.rake | 5 ++++ mrbgems/mruby-rational/mrblib/rational.rb | 46 +++++++++++++++++++++++++++++++ mrbgems/mruby-rational/test/rational.rb | 3 ++ 3 files changed, 54 insertions(+) create mode 100644 mrbgems/mruby-rational/mrbgem.rake create mode 100644 mrbgems/mruby-rational/mrblib/rational.rb create mode 100644 mrbgems/mruby-rational/test/rational.rb (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake new file mode 100644 index 000000000..4b540dec4 --- /dev/null +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-rational') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Rational class' +end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb new file mode 100644 index 000000000..457c0488a --- /dev/null +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -0,0 +1,46 @@ +class Rational < Numeric + def initialize(numerator = 0, denominator = 1) + @numerator = numerator + @denominator = denominator + end + + attr_reader :numerator, :denominator +end + +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) + 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 \ No newline at end of file diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb new file mode 100644 index 000000000..6f20a6cd4 --- /dev/null +++ b/mrbgems/mruby-rational/test/rational.rb @@ -0,0 +1,3 @@ +assert 'Rational' do + assert_equal Rational, 0r.class +end \ No newline at end of file -- cgit v1.2.3 From d67d2ae8e88b93536e71dfa41a90721ce351da7c Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Sun, 9 Sep 2018 11:57:16 +0900 Subject: Basic implementation of Complex and Rational classes --- mrbgems/default.gembox | 4 +- mrbgems/mruby-complex/mrbgem.rake | 4 + mrbgems/mruby-complex/mrblib/complex.rb | 155 ++++++++++++++++++++++-------- mrbgems/mruby-complex/test/complex.rb | 129 ++++++++++++++++++++++++- mrbgems/mruby-rational/mrbgem.rake | 3 + mrbgems/mruby-rational/mrblib/rational.rb | 100 +++++++++++++------ mrbgems/mruby-rational/test/rational.rb | 41 +++++++- 7 files changed, 363 insertions(+), 73 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 501aee146..ae085309c 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -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" 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 diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 4b540dec4..496082709 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -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 diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 457c0488a..ffadd55eb 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -2,45 +2,89 @@ class Rational < Numeric def initialize(numerator = 0, denominator = 1) @numerator = numerator @denominator = denominator + + _simplify end - attr_reader :numerator, :denominator -end + def inspect + "(#{to_s})" + end -def Rational(numerator = 0, denominator = 1) - Rational.new(numerator, denominator) -end + def to_s + "#{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) - 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 __forward_operators_to_rational - __forward_operator_to_rational :+ - __forward_operator_to_rational :- - __forward_operator_to_rational :* - __forward_operator_to_rational :/ + 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 - singleton_class.undef_method :__forward_operator_to_rational - singleton_class.undef_method :__forward_operators_to_rational + 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 end -class Fixnum - extend ForwardOperatorToRational - __forward_operators_to_rational +def Rational(numerator = 0, denominator = 1) + Rational.new(numerator, denominator) end -class Float - extend ForwardOperatorToRational - __forward_operators_to_rational +[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 end \ No newline at end of file diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 6f20a6cd4..a86f00690 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -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 \ No newline at end of file -- cgit v1.2.3 From fa45cc42726720b89732bf43d1bf433970007c89 Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Sat, 22 Sep 2018 16:53:56 +0900 Subject: Fix dependencies --- mrbgems/default.gembox | 6 ------ mrbgems/mruby-complex/mrbgem.rake | 1 + mrbgems/mruby-rational/mrbgem.rake | 1 + mrbgems/mruby-rational/mrblib/rational.rb | 12 ++++++++++++ mrbgems/mruby-rational/test/rational.rb | 15 +++++++++++++++ 5 files changed, 29 insertions(+), 6 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index ae085309c..23e65fcee 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -68,12 +68,6 @@ MRuby::GemBox.new do |conf| # Use Enumerator::Lazy class (require mruby-enumerator) conf.gem :core => "mruby-enum-lazy" - # Use Complex class - # conf.gem :core => "mruby-complex" - - # Use Rational class - # conf.gem :core => "mruby-rational" - # Use toplevel object (main) methods extension conf.gem :core => "mruby-toplevel-ext" diff --git a/mrbgems/mruby-complex/mrbgem.rake b/mrbgems/mruby-complex/mrbgem.rake index 25b8966da..19612e74d 100644 --- a/mrbgems/mruby-complex/mrbgem.rake +++ b/mrbgems/mruby-complex/mrbgem.rake @@ -3,6 +3,7 @@ MRuby::Gem::Specification.new('mruby-complex') do |spec| spec.author = 'mruby developers' spec.summary = 'Complex class' + spec.add_dependency 'mruby-metaprog', core: 'mruby-metaprog' 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' diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 496082709..93f5b601c 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -3,6 +3,7 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.author = 'mruby developers' spec.summary = 'Rational class' + spec.add_dependency 'mruby-metaprog', core: 'mruby-metaprog' spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index ffadd55eb..7d5b87362 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -10,6 +10,18 @@ class Rational < Numeric "(#{to_s})" end + def to_f + @numerator.to_f / @denominator.to_f + end + + def to_i + to_f.to_i + end + + def to_r + self + end + def to_s "#{numerator}/#{denominator}" end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index a86f00690..85cebc316 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -9,6 +9,21 @@ assert 'Rational' do assert_equal [r.numerator, r.denominator], [5, 1] end +assert 'Rational#to_f' do + assert_float Rational(2).to_f, 2.0 + assert_float Rational(9, 4).to_f, 2.25 + assert_float Rational(-3, 4).to_f, -0.75 + assert_float Rational(20, 3).to_f, 6.666666666666667 +end + +assert 'Rational#to_i' do + assert_equal Rational(2, 3).to_i, 0 + assert_equal Rational(3).to_i, 3 + assert_equal Rational(300.6).to_i, 300 + assert_equal Rational(98, 71).to_i, 1 + assert_equal Rational(-30, 2).to_i, -15 +end + assert 'Rational#*' do assert_rational Rational(2, 3) * Rational(2, 3), Rational(4, 9) assert_rational Rational(900) * Rational(1), Rational(900, 1) -- cgit v1.2.3 From f5fb1307b017fb972c12b4ec4b1866d789b0ca09 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 16 May 2019 22:09:56 +0900 Subject: Fix `Rational#==` --- mrbgems/mruby-rational/mrbgem.rake | 1 - mrbgems/mruby-rational/mrblib/rational.rb | 29 +++++++++++++++--- mrbgems/mruby-rational/test/rational.rb | 49 +++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 7 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 93f5b601c..496082709 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -3,7 +3,6 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.author = 'mruby developers' spec.summary = 'Rational class' - spec.add_dependency 'mruby-metaprog', core: 'mruby-metaprog' spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 7d5b87362..dbc855af0 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -1,4 +1,7 @@ class Rational < Numeric + # Override #<, #<=, #>, #>= in Numeric + prepend Comparable + def initialize(numerator = 0, denominator = 1) @numerator = numerator @denominator = denominator @@ -66,6 +69,24 @@ class Rational < Numeric end end + def <=>(rhs) + case rhs + when Fixnum + return @numerator <=> rhs if @denominator == 1 + rhs = Rational(rhs) + when Float + return to_f <=> rhs + end + case rhs + when Rational + (@numerator * rhs.denominator - @denominator * rhs.numerator) <=> 0 + when Numeric + return rhs <=> self + else + nil + end + end + def negative? numerator.negative? end @@ -86,17 +107,17 @@ def Rational(numerator = 0, denominator = 1) end [Fixnum, Float].each do |cls| - [:+, :-, :*, :/, :==].each do |op| + [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].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) + Rational(self).__send__(op, rhs) else - send(original_operator_name, rhs) + __send__(original_operator_name, rhs) end end end end -end \ No newline at end of file +end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 85cebc316..4d3d36ccc 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -1,8 +1,18 @@ def assert_rational(real, exp) - assert_float real.numerator, exp.numerator + assert_float real.numerator, exp.numerator assert_float real.denominator, exp.denominator end +def assert_equal_rational(exp, r1, r2) + if exp + assert_operator(r1, :==, r2) + assert_not_operator(r1, :!=, r2) + else + assert_not_operator(r1, :==, r2) + assert_operator(r1, :!=, r2) + end +end + assert 'Rational' do r = 5r assert_equal Rational, r.class @@ -54,4 +64,39 @@ assert 'Rational#/' do 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 \ No newline at end of file +end + +assert 'Rational#==, Rational#!=' do + assert_equal_rational(true, Rational(1,1), Rational(1)) + assert_equal_rational(true, Rational(-1,1), -1r) + assert_equal_rational(true, Rational(13,4), 3.25) + assert_equal_rational(true, Rational(13,3.25), Rational(4,1)) + assert_equal_rational(true, Rational(-3,-4), Rational(3,4)) + assert_equal_rational(true, Rational(-4,5), Rational(4,-5)) + assert_equal_rational(true, Rational(4,2), 2) + assert_equal_rational(true, Rational(-4,2), -2) + assert_equal_rational(true, Rational(4,-2), -2) + assert_equal_rational(true, Rational(4,2), 2.0) + assert_equal_rational(true, Rational(-4,2), -2.0) + assert_equal_rational(true, Rational(4,-2), -2.0) + assert_equal_rational(true, Rational(8,6), Rational(4,3)) + assert_equal_rational(false, Rational(13,4), 3) + assert_equal_rational(false, Rational(13,4), 3.3) + assert_equal_rational(false, Rational(2,1), 1r) + assert_equal_rational(false, Rational(1), nil) + assert_equal_rational(false, Rational(1), '') +end + +assert 'Fixnum#==(Rational), Fixnum#!=(Rational)' do + assert_equal_rational(true, 2, Rational(4,2)) + assert_equal_rational(true, -2, Rational(-4,2)) + assert_equal_rational(true, -2, Rational(4,-2)) + assert_equal_rational(false, 3, Rational(13,4)) +end + +assert 'Float#==(Rational), Float#!=(Rational)' do + assert_equal_rational(true, 2.0, Rational(4,2)) + assert_equal_rational(true, -2.0, Rational(-4,2)) + assert_equal_rational(true, -2.0, Rational(4,-2)) + assert_equal_rational(false, 3.3, Rational(13,4)) +end -- cgit v1.2.3 From 0d61bcd823df74c65d8d5a3f8e36661780f92914 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:27:52 +0900 Subject: Use `div` (integer divition) instead of `/` for rational numbers. --- mrbgems/mruby-rational/mrblib/rational.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index dbc855af0..30aaef915 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -94,9 +94,9 @@ class Rational < Numeric def _simplify a = numerator b = denominator - a, b = b, a % b while !b.zero? - @numerator /= a - @denominator /= a + a, b = b, a % b until b.zero? + @numerator = @numerator.div(a) + @denominator = @denominator.div(a) end attr_reader :numerator, :denominator -- cgit v1.2.3 From 912d23634d60def0c6a370b059f69999fe363c9b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 16:18:46 +0900 Subject: Fixed wrong overloading. `float op rational` should return `float`, since float is an inexact value. --- mrbgems/mruby-rational/mrblib/rational.rb | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 30aaef915..82ae98425 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -106,18 +106,26 @@ def Rational(numerator = 0, denominator = 1) Rational.new(numerator, denominator) end -[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 +[:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| + Fixnum.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 + Float.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 + rhs = rhs.to_f + end + __send__(original_operator_name, rhs) + end + end end -- cgit v1.2.3 From cec92673ae9e24d73a6feb2d69602b5fa60dcddd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 16:22:23 +0900 Subject: Avoid direct access to instance variables in `rational.rb`. --- mrbgems/mruby-rational/mrblib/rational.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 82ae98425..a38f71407 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -72,14 +72,14 @@ class Rational < Numeric def <=>(rhs) case rhs when Fixnum - return @numerator <=> rhs if @denominator == 1 + return numerator <=> rhs if denominator == 1 rhs = Rational(rhs) when Float return to_f <=> rhs end case rhs when Rational - (@numerator * rhs.denominator - @denominator * rhs.numerator) <=> 0 + (numerator * rhs.denominator - denominator * rhs.numerator) <=> 0 when Numeric return rhs <=> self else -- cgit v1.2.3 From b6e9fab64949b91f00d07c890935642f44147615 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 16:37:34 +0900 Subject: Implement part of `Rational` in C. --- mrbgems/mruby-rational/mrblib/rational.rb | 43 +++++---------- mrbgems/mruby-rational/src/rational.c | 90 +++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 31 deletions(-) create mode 100644 mrbgems/mruby-rational/src/rational.c (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index a38f71407..54324b05f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -2,29 +2,10 @@ class Rational < Numeric # Override #<, #<=, #>, #>= in Numeric prepend Comparable - def initialize(numerator = 0, denominator = 1) - @numerator = numerator - @denominator = denominator - - _simplify - end - def inspect "(#{to_s})" end - def to_f - @numerator.to_f / @denominator.to_f - end - - def to_i - to_f.to_i - end - - def to_r - self - end - def to_s "#{numerator}/#{denominator}" end @@ -86,24 +67,24 @@ class Rational < Numeric nil end end +end - def negative? - numerator.negative? - end - - def _simplify - a = numerator - b = denominator - a, b = b, a % b until b.zero? - @numerator = @numerator.div(a) - @denominator = @denominator.div(a) +class << Numeric + def to_r + Rational(self, 1) end +end - attr_reader :numerator, :denominator +class << Rational + alias_method :_new, :new + undef_method :new end def Rational(numerator = 0, denominator = 1) - Rational.new(numerator, denominator) + a = numerator + b = denominator + a, b = b, a % b until b.zero? + Rational._new(numerator.div(a), denominator.div(a)) end [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c new file mode 100644 index 000000000..14a9b045d --- /dev/null +++ b/mrbgems/mruby-rational/src/rational.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include + +struct mrb_rational { + mrb_int numerator; + mrb_int denominator; +}; + +static struct mrb_rational* +rational_ptr(mrb_value v) +{ + return (struct mrb_rational*)mrb_istruct_ptr(v); +} + +static mrb_value +rational_numerator(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + return mrb_fixnum_value(p->numerator); +} + +static mrb_value +rational_denominator(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + return mrb_fixnum_value(p->denominator); +} + +static mrb_value +rational_initialize(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + mrb_get_args(mrb, "ii", &p->numerator, &p->denominator); + return self; +} + +static mrb_value +rational_to_f(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + mrb_float f = (mrb_float)p->numerator / (mrb_float)p->denominator; + + return mrb_float_value(mrb, f); +} + +static mrb_value +rational_to_i(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + return mrb_fixnum_value(p->numerator / p->denominator); +} + +static mrb_value +rational_to_r(mrb_state *mrb, mrb_value self) +{ + return self; +} + +static mrb_value +rational_negative_p(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + if (p->numerator < 0) { + return mrb_true_value(); + } + return mrb_false_value(); +} + +void mrb_mruby_rational_gem_init(mrb_state *mrb) +{ + struct RClass *rat; + + mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE); + rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric")); + MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT); + mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "initialize", rational_initialize, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, rat, "to_f", rational_to_f, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE()); +} + +void +mrb_mruby_rational_gem_final(mrb_state* mrb) +{ +} -- cgit v1.2.3 From eeb95e058a579a45207079369b19869cb48a39de Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 17 May 2019 19:53:31 +0900 Subject: Fix `Numeric#to_r` --- mrbgems/mruby-rational/mrblib/rational.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 54324b05f..37dcfc2a0 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -69,7 +69,7 @@ class Rational < Numeric end end -class << Numeric +class Numeric def to_r Rational(self, 1) end -- cgit v1.2.3 From aa41a5c9af4d8ee61867d4f0bfdaeab4deb7cf0e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 17 May 2019 20:44:48 +0900 Subject: Drop dependency from `mruby-rational` to `mruby-numeric-ext` --- mrbgems/mruby-rational/mrbgem.rake | 1 - mrbgems/mruby-rational/mrblib/rational.rb | 2 +- mrbgems/mruby-rational/test/rational.rb | 7 +++++++ 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 496082709..15c3429f2 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -4,5 +4,4 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| 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 diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 54324b05f..ccb67541f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -83,7 +83,7 @@ end def Rational(numerator = 0, denominator = 1) a = numerator b = denominator - a, b = b, a % b until b.zero? + a, b = b, a % b until b == 0 Rational._new(numerator.div(a), denominator.div(a)) end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 4d3d36ccc..a65926bfb 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -100,3 +100,10 @@ assert 'Float#==(Rational), Float#!=(Rational)' do assert_equal_rational(true, -2.0, Rational(4,-2)) assert_equal_rational(false, 3.3, Rational(13,4)) end + +assert 'Rational#negative?' do + assert_predicate(Rational(-2,3), :negative?) + assert_predicate(Rational(2,-3), :negative?) + assert_not_predicate(Rational(2,3), :negative?) + assert_not_predicate(Rational(0), :negative?) +end -- cgit v1.2.3 From ace0d3949b62b3541a5ab210706f939890890cc0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 08:38:45 +0900 Subject: Support `MRB_WITHOUT_FLOAT`. I assume there's no realistic usage of `Rational` with `MRB_WITHOUT_FLOAT`. But just for consistency. --- mrbgems/mruby-rational/src/rational.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 14a9b045d..03f373490 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -36,6 +36,7 @@ rational_initialize(mrb_state *mrb, mrb_value self) return self; } +#ifndef MRB_WITHOUT_FLOAT static mrb_value rational_to_f(mrb_state *mrb, mrb_value self) { @@ -44,6 +45,7 @@ rational_to_f(mrb_state *mrb, mrb_value self) return mrb_float_value(mrb, f); } +#endif static mrb_value rational_to_i(mrb_state *mrb, mrb_value self) @@ -78,7 +80,9 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb) mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "initialize", rational_initialize, MRB_ARGS_REQ(2)); +#ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, rat, "to_f", rational_to_f, MRB_ARGS_NONE()); +#endif mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE()); -- cgit v1.2.3 From bd7328f5e606a59db25c6c17534f7db6c21fc13c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 11:23:59 +0900 Subject: Implement `Rational._new` in C. --- mrbgems/mruby-rational/mrblib/rational.rb | 5 ----- mrbgems/mruby-rational/src/rational.c | 31 ++++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 10 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 37e9d8c0f..870c12242 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -75,11 +75,6 @@ class Numeric end end -class << Rational - alias_method :_new, :new - undef_method :new -end - def Rational(numerator = 0, denominator = 1) a = numerator b = denominator diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 03f373490..549715e7d 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -29,11 +29,24 @@ rational_denominator(mrb_state *mrb, mrb_value self) } static mrb_value -rational_initialize(mrb_state *mrb, mrb_value self) +rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) { - struct mrb_rational *p = rational_ptr(self); - mrb_get_args(mrb, "ii", &p->numerator, &p->denominator); - return self; + struct RClass *c = mrb_class_get(mrb, "Rational"); + struct RIStruct *s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); + mrb_value rat = mrb_obj_value(s); + struct mrb_rational *p = rational_ptr(rat); + p->numerator = numerator; + p->denominator = denominator; + return mrb_obj_value(s); +} + +static mrb_value +rational_s_new(mrb_state *mrb, mrb_value self) +{ + mrb_int numerator, denominator; + + mrb_get_args(mrb, "ii", &numerator, &denominator); + return rational_new(mrb, numerator, denominator); } #ifndef MRB_WITHOUT_FLOAT @@ -70,6 +83,12 @@ rational_negative_p(mrb_state *mrb, mrb_value self) return mrb_false_value(); } +static mrb_value +fix_to_r(mrb_state *mrb, mrb_value self) +{ + return rational_new(mrb, mrb_fixnum(self), 1); +} + void mrb_mruby_rational_gem_init(mrb_state *mrb) { struct RClass *rat; @@ -77,15 +96,17 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb) mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE); rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric")); MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT); + mrb_undef_class_method(mrb, rat, "new"); + mrb_define_class_method(mrb, rat, "_new", rational_s_new, MRB_ARGS_REQ(2)); mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE()); - mrb_define_method(mrb, rat, "initialize", rational_initialize, MRB_ARGS_REQ(2)); #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, rat, "to_f", rational_to_f, MRB_ARGS_NONE()); #endif mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, mrb->fixnum_class, "to_r", fix_to_r, MRB_ARGS_NONE()); } void -- cgit v1.2.3 From 6c9c189e4b9b5a340e220b333bc5f975fdb65adc Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 18:31:55 +0900 Subject: Move `Object#(Rational|Complex)` to `Kernel` --- mrbgems/mruby-complex/mrblib/complex.rb | 10 ++++++---- mrbgems/mruby-rational/mrblib/rational.rb | 12 +++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 266c00c36..8ae743e77 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -107,7 +107,7 @@ class Complex < Numeric def polar [abs, arg] end - + def real? false end @@ -147,8 +147,10 @@ class << Complex alias_method :rect, :rectangular end -def Complex(real, imaginary = 0) - Complex.rectangular(real, imaginary) +module Kernel + def Complex(real, imaginary = 0) + Complex.rectangular(real, imaginary) + end end [Fixnum, Float].each do |cls| @@ -165,4 +167,4 @@ end end end end -end \ No newline at end of file +end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 870c12242..19c6da9e7 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -75,11 +75,13 @@ class Numeric end end -def Rational(numerator = 0, denominator = 1) - a = numerator - b = denominator - a, b = b, a % b until b == 0 - Rational._new(numerator.div(a), denominator.div(a)) +module Kernel + def Rational(numerator = 0, denominator = 1) + a = numerator + b = denominator + a, b = b, a % b until b == 0 + Rational._new(numerator.div(a), denominator.div(a)) + end end [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| -- cgit v1.2.3 From a6eb01837b5d18d0a9b6fd5e22ab7d99241a1e2a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 19 May 2019 13:52:18 +0900 Subject: Fix `Rational#<=>(Numeric)` Reported by Sergey Ukrainskiy: https://github.com/mruby/mruby/commit/f5fb1307b017fb972c12b4ec4b1866d789b0ca09#r33590698 --- mrbgems/mruby-rational/mrblib/rational.rb | 3 +- mrbgems/mruby-rational/test/rational.rb | 168 +++++++++++++++++++++++++++++- 2 files changed, 165 insertions(+), 6 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 19c6da9e7..ad1f3ab0f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -58,11 +58,12 @@ class Rational < Numeric when Float return to_f <=> rhs end + case rhs when Rational (numerator * rhs.denominator - denominator * rhs.numerator) <=> 0 when Numeric - return rhs <=> self + (rhs <=> self)&.-@ else nil end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index a65926bfb..1ff819090 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -3,13 +3,21 @@ def assert_rational(real, exp) assert_float real.denominator, exp.denominator end -def assert_equal_rational(exp, r1, r2) +def assert_equal_rational(exp, o1, o2) if exp - assert_operator(r1, :==, r2) - assert_not_operator(r1, :!=, r2) + assert_operator(o1, :==, o2) + assert_not_operator(o1, :!=, o2) else - assert_not_operator(r1, :==, r2) - assert_operator(r1, :!=, r2) + assert_not_operator(o1, :==, o2) + assert_operator(o1, :!=, o2) + end +end + +def assert_cmp(exp, o1, o2) + if exp == (o1 <=> o2) + pass + else + flunk "", " Expected #{o1.inspect} <=> #{o2.inspect} to be #{exp}" end end @@ -101,6 +109,156 @@ assert 'Float#==(Rational), Float#!=(Rational)' do assert_equal_rational(false, 3.3, Rational(13,4)) end +assert 'Rational#<=>' do + num = Class.new(Numeric) do + def initialize(n) + @n = n + end + + def <=>(rhs) + rhs = rhs.to_i + rhs < 0 ? nil : @n <=> rhs + end + + def inspect + "num(#{@n})" + end + end + + assert_cmp(-1, Rational(-1), Rational(0)) + assert_cmp(0, Rational(0), Rational(0)) + assert_cmp(1, Rational(1), Rational(0)) + assert_cmp(-1, Rational(-1), 0) + assert_cmp(0, Rational(0), 0) + assert_cmp(1, Rational(1), 0) + assert_cmp(-1, Rational(-1), 0.0) + assert_cmp(0, Rational(0), 0.0) + assert_cmp(1, Rational(1), 0.0) + assert_cmp(-1, Rational(1,2), Rational(2,3)) + assert_cmp(0, Rational(2,3), Rational(2,3)) + assert_cmp(1, Rational(2,3), Rational(1,2)) + assert_cmp(1, Rational(2,3), Rational(1,2)) + assert_cmp(1, Rational(0), Rational(-1)) + assert_cmp(-1, Rational(0), Rational(1)) + assert_cmp(1, Rational(2,3), Rational(1,2)) + assert_cmp(0, Rational(2,3), Rational(2,3)) + assert_cmp(-1, Rational(1,2), Rational(2,3)) + assert_cmp(-1, Rational(1,2), Rational(2,3)) + assert_cmp(nil, 3r, "3") + assert_cmp(1, 3r, num.new(2)) + assert_cmp(0, 3r, num.new(3)) + assert_cmp(-1, 3r, num.new(4)) + assert_cmp(nil, Rational(-3), num.new(5)) +end + +assert 'Fixnum#<=>(Rational)' do + assert_cmp(-1, -2, Rational(-9,5)) + assert_cmp(0, 5, 5r) + assert_cmp(1, 3, Rational(8,3)) +end + +assert 'Float#<=>(Rational)' do + assert_cmp(-1, -2.1, Rational(-9,5)) + assert_cmp(0, 5.0, 5r) + assert_cmp(1, 2.7, Rational(8,3)) +end + +assert 'Rational#<' do + assert_operator(Rational(1,2), :<, Rational(2,3)) + assert_not_operator(Rational(2,3), :<, Rational(2,3)) + assert_operator(Rational(2,3), :<, 1) + assert_not_operator(2r, :<, 2) + assert_not_operator(Rational(2,3), :<, -3) + assert_operator(Rational(-4,3), :<, -0.3) + assert_not_operator(Rational(13,4), :<, 3.25) + assert_not_operator(Rational(2,3), :<, 0.6) + assert_raise(ArgumentError) { 1r < "2" } +end + +assert 'Fixnum#<(Rational)' do + assert_not_operator(1, :<, Rational(2,3)) + assert_not_operator(2, :<, 2r) + assert_operator(-3, :<, Rational(2,3)) +end + +assert 'Float#<(Rational)' do + assert_not_operator(-0.3, :<, Rational(-4,3)) + assert_not_operator(3.25, :<, Rational(13,4)) + assert_operator(0.6, :<, Rational(2,3)) +end + +assert 'Rational#<=' do + assert_operator(Rational(1,2), :<=, Rational(2,3)) + assert_operator(Rational(2,3), :<=, Rational(2,3)) + assert_operator(Rational(2,3), :<=, 1) + assert_operator(2r, :<=, 2) + assert_not_operator(Rational(2,3), :<=, -3) + assert_operator(Rational(-4,3), :<=, -0.3) + assert_operator(Rational(13,4), :<=, 3.25) + assert_not_operator(Rational(2,3), :<=, 0.6) + assert_raise(ArgumentError) { 1r <= "2" } +end + +assert 'Fixnum#<=(Rational)' do + assert_not_operator(1, :<=, Rational(2,3)) + assert_operator(2, :<=, 2r) + assert_operator(-3, :<=, Rational(2,3)) +end + +assert 'Float#<=(Rational)' do + assert_not_operator(-0.3, :<=, Rational(-4,3)) + assert_operator(3.25, :<=, Rational(13,4)) + assert_operator(0.6, :<=, Rational(2,3)) +end + +assert 'Rational#>' do + assert_not_operator(Rational(1,2), :>, Rational(2,3)) + assert_not_operator(Rational(2,3), :>, Rational(2,3)) + assert_not_operator(Rational(2,3), :>, 1) + assert_not_operator(2r, :>, 2) + assert_operator(Rational(2,3), :>, -3) + assert_not_operator(Rational(-4,3), :>, -0.3) + assert_not_operator(Rational(13,4), :>, 3.25) + assert_operator(Rational(2,3), :>, 0.6) + assert_raise(ArgumentError) { 1r > "2" } +end + +assert 'Fixnum#>(Rational)' do + assert_operator(1, :>, Rational(2,3)) + assert_not_operator(2, :>, 2r) + assert_not_operator(-3, :>, Rational(2,3)) +end + +assert 'Float#>(Rational)' do + assert_operator(-0.3, :>, Rational(-4,3)) + assert_not_operator(3.25, :>, Rational(13,4)) + assert_not_operator(0.6, :>, Rational(2,3)) +end + +assert 'Rational#>=' do + assert_not_operator(Rational(1,2), :>=, Rational(2,3)) + assert_operator(Rational(2,3), :>=, Rational(2,3)) + assert_not_operator(Rational(2,3), :>=, 1) + assert_operator(2r, :>=, 2) + assert_operator(Rational(2,3), :>=, -3) + assert_not_operator(Rational(-4,3), :>=, -0.3) + assert_operator(Rational(13,4), :>=, 3.25) + assert_operator(Rational(2,3), :>=, 0.6) + assert_raise(ArgumentError) { 1r >= "2" } +end + +assert 'Fixnum#>=(Rational)' do + assert_operator(1, :>=, Rational(2,3)) + assert_operator(2, :>=, 2r) + assert_not_operator(-3, :>=, Rational(2,3)) +end + +assert 'Float#>=(Rational)' do + assert_operator(-0.3, :>=, Rational(-4,3)) + assert_operator(3.25, :>=, Rational(13,4)) + assert_not_operator(0.6, :>=, Rational(2,3)) +end + assert 'Rational#negative?' do assert_predicate(Rational(-2,3), :negative?) assert_predicate(Rational(2,-3), :negative?) -- cgit v1.2.3 From 97600ded8d7717f327a3bf00e904a7ebb38dbd64 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 20 May 2019 18:24:18 +0900 Subject: Change the order of "expected" and "actual" in `mruby-rational` test --- mrbgems/mruby-rational/test/rational.rb | 68 ++++++++++++++++----------------- 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 1ff819090..5a1055ee7 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -1,6 +1,6 @@ -def assert_rational(real, exp) - assert_float real.numerator, exp.numerator - assert_float real.denominator, exp.denominator +def assert_rational(exp, real) + assert_float exp.numerator, real.numerator + assert_float exp.denominator, real.denominator end def assert_equal_rational(exp, o1, o2) @@ -23,55 +23,55 @@ end assert 'Rational' do r = 5r - assert_equal Rational, r.class - assert_equal [r.numerator, r.denominator], [5, 1] + assert_equal(r.class, Rational) + assert_equal([5, 1], [r.numerator, r.denominator]) end assert 'Rational#to_f' do - assert_float Rational(2).to_f, 2.0 - assert_float Rational(9, 4).to_f, 2.25 - assert_float Rational(-3, 4).to_f, -0.75 - assert_float Rational(20, 3).to_f, 6.666666666666667 + assert_float(2.0, Rational(2).to_f) + assert_float(2.25, Rational(9, 4).to_f) + assert_float(-0.75, Rational(-3, 4).to_f) + assert_float(6.666666666666667, Rational(20, 3).to_f) end assert 'Rational#to_i' do - assert_equal Rational(2, 3).to_i, 0 - assert_equal Rational(3).to_i, 3 - assert_equal Rational(300.6).to_i, 300 - assert_equal Rational(98, 71).to_i, 1 - assert_equal Rational(-30, 2).to_i, -15 + assert_equal(0, Rational(2, 3).to_i) + assert_equal(3, Rational(3).to_i) + assert_equal(300, Rational(300.6).to_i) + assert_equal(1, Rational(98, 71).to_i) + assert_equal(-15, Rational(-30, 2).to_i) 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 + assert_rational(Rational(4, 9), Rational(2, 3) * Rational(2, 3)) + assert_rational(Rational(900, 1), Rational(900) * Rational(1)) + assert_rational(Rational(1, 1), Rational(-2, 9) * Rational(-9, 2)) + assert_rational(Rational(9, 2), Rational(9, 8) * 4) + assert_float( 21.77777777777778, Rational(20, 9) * 9.8) 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 + assert_rational(Rational(4, 3), Rational(2, 3) + Rational(2, 3)) + assert_rational(Rational(901, 1), Rational(900) + Rational(1)) + assert_rational(Rational(-85, 18), Rational(-2, 9) + Rational(-9, 2)) + assert_rational(Rational(41, 8), Rational(9, 8) + 4) + assert_float( 12.022222222222222, Rational(20, 9) + 9.8) 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 + assert_rational(Rational(0, 1), Rational(2, 3) - Rational(2, 3)) + assert_rational(Rational(899, 1), Rational(900) - Rational(1)) + assert_rational(Rational(77, 18), Rational(-2, 9) - Rational(-9, 2)) + assert_rational(Rational(-23, 8), Rational(9, 8) - 4) + assert_float( -7.577777777777778, Rational(20, 9) - 9.8) 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 + assert_rational(Rational(1, 1), Rational(2, 3) / Rational(2, 3)) + assert_rational(Rational(900, 1), Rational(900) / Rational(1)) + assert_rational(Rational(4, 81), Rational(-2, 9) / Rational(-9, 2)) + assert_rational(Rational(9, 32), Rational(9, 8) / 4) + assert_float( 0.22675736961451246, Rational(20, 9) / 9.8) end assert 'Rational#==, Rational#!=' do -- cgit v1.2.3 From 3db5d7fe3d91c17719ab69a2161d1a0581e5ed2c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 20 May 2019 18:36:13 +0900 Subject: Drop dependency from `mruby-rational` to `mruby-object-ext` --- mrbgems/mruby-rational/mrbgem.rake | 2 -- mrbgems/mruby-rational/mrblib/rational.rb | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 15c3429f2..4b540dec4 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -2,6 +2,4 @@ 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' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index ad1f3ab0f..28c96c69f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -86,7 +86,7 @@ module Kernel end [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| - Fixnum.instance_exec do + Fixnum.instance_eval do original_operator_name = "__original_operator_#{op}_rational" alias_method original_operator_name, op define_method op do |rhs| @@ -97,7 +97,7 @@ end end end end - Float.instance_exec do + Float.instance_eval do original_operator_name = "__original_operator_#{op}_rational" alias_method original_operator_name, op define_method op do |rhs| -- cgit v1.2.3 From 5d6c1794ad8620279514f45770ab4e8eeb16c734 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 21 May 2019 09:31:06 +0900 Subject: Revert part of #4457 --- mrbgems/mruby-rational/test/rational.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 5a1055ee7..ea55880fe 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -23,7 +23,7 @@ end assert 'Rational' do r = 5r - assert_equal(r.class, Rational) + assert_equal(Rational, r.class) assert_equal([5, 1], [r.numerator, r.denominator]) end -- cgit v1.2.3 From 3b46831da83b4d5d5355c60261fb3ebe2a885513 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 21 May 2019 20:26:53 +0900 Subject: Move `**`,`/`,`quo`,`div` and comparison methods to Integral from Numeric Having these methods in Numeric can get in the way of creating subclasses of Numeric because they only support Fixnum and Float. --- mrbgems/mruby-rational/mrblib/rational.rb | 3 --- src/numeric.c | 37 +++++++++++++++---------------- 2 files changed, 18 insertions(+), 22 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 28c96c69f..cecede48a 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -1,7 +1,4 @@ class Rational < Numeric - # Override #<, #<=, #>, #>= in Numeric - prepend Comparable - def inspect "(#{to_s})" end diff --git a/src/numeric.c b/src/numeric.c index 3ad5721ef..c740a32e3 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -65,7 +65,7 @@ mrb_int_value(mrb_state *mrb, mrb_float f) * 2.0**3 #=> 8.0 */ static mrb_value -num_pow(mrb_state *mrb, mrb_value x) +integral_pow(mrb_state *mrb, mrb_value x) { mrb_value y; #ifndef MRB_WITHOUT_FLOAT @@ -113,7 +113,7 @@ num_pow(mrb_state *mrb, mrb_value x) } static mrb_value -num_idiv(mrb_state *mrb, mrb_value x) +integral_idiv(mrb_state *mrb, mrb_value x) { #ifdef MRB_WITHOUT_FLOAT mrb_value y; @@ -151,7 +151,7 @@ num_idiv(mrb_state *mrb, mrb_value x) */ static mrb_value -num_div(mrb_state *mrb, mrb_value x) +integral_div(mrb_state *mrb, mrb_value x) { #ifdef MRB_WITHOUT_FLOAT mrb_value y; @@ -1479,7 +1479,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) * basis for the tests in Comparable. */ static mrb_value -num_cmp(mrb_state *mrb, mrb_value self) +integral_cmp(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1499,7 +1499,7 @@ cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2) } static mrb_value -num_lt(mrb_state *mrb, mrb_value self) +integral_lt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1512,7 +1512,7 @@ num_lt(mrb_state *mrb, mrb_value self) } static mrb_value -num_le(mrb_state *mrb, mrb_value self) +integral_le(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1525,7 +1525,7 @@ num_le(mrb_state *mrb, mrb_value self) } static mrb_value -num_gt(mrb_state *mrb, mrb_value self) +integral_gt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1538,7 +1538,7 @@ num_gt(mrb_state *mrb, mrb_value self) } static mrb_value -num_ge(mrb_state *mrb, mrb_value self) +integral_ge(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1593,20 +1593,19 @@ mrb_init_numeric(mrb_state *mrb) #endif integral = mrb_define_module(mrb, "Integral"); - mrb_define_method(mrb, integral, "__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ + mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ + mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">=", integral_ge, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ - - mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ - mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ - mrb_define_method(mrb, numeric, "div", num_idiv, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ - mrb_define_method(mrb, numeric, "<", num_lt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "<=", num_le, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">", num_gt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); -- cgit v1.2.3 From b7f85b9df91168f8c6338354bc50a621ca0e098b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 20 May 2019 16:35:06 +0900 Subject: Should not refer `Float` class in case of `MRB_WITHOUT_FLOAT`. This commit removes `Float` from `rational.c`. --- mrbgems/mruby-rational/mrblib/rational.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index cecede48a..c8614ecea 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -48,12 +48,9 @@ class Rational < Numeric end def <=>(rhs) - case rhs - when Fixnum + if rhs.is_a?(Integral) return numerator <=> rhs if denominator == 1 rhs = Rational(rhs) - when Float - return to_f <=> rhs end case rhs @@ -103,5 +100,5 @@ end end __send__(original_operator_name, rhs) end - end + end if Object.const_defined?(:Float) end -- cgit v1.2.3 From fccec8964a1b30cef8ff9d97e0e01f3a348e318b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 16:11:25 +0900 Subject: Implements part of `Complex` class in C. --- mrbgems/mruby-complex/mrblib/complex.rb | 50 +++----------- mrbgems/mruby-complex/src/complex.c | 116 ++++++++++++++++++++++++++++++++ mrbgems/mruby-rational/src/rational.c | 2 +- 3 files changed, 127 insertions(+), 41 deletions(-) create mode 100644 mrbgems/mruby-complex/src/complex.c (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 8ae743e77..4c0c19c70 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -23,43 +23,43 @@ class Complex < Numeric end def +@ - Complex(real, imaginary) + Complex._new(real, imaginary) end def -@ - Complex(-real, -imaginary) + Complex._new(-real, -imaginary) end def +(rhs) if rhs.is_a? Complex - Complex(real + rhs.real, imaginary + rhs.imaginary) + Complex._new(real + rhs.real, imaginary + rhs.imaginary) elsif rhs.is_a? Numeric - Complex(real + rhs, imaginary) + Complex._new(real + rhs, imaginary) end end def -(rhs) if rhs.is_a? Complex - Complex(real - rhs.real, imaginary - rhs.imaginary) + Complex._new(real - rhs.real, imaginary - rhs.imaginary) elsif rhs.is_a? Numeric - Complex(real - rhs, imaginary) + Complex._new(real - rhs, imaginary) end end def *(rhs) if rhs.is_a? Complex - Complex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) + Complex._new(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) elsif rhs.is_a? Numeric - Complex(real * rhs, imaginary * rhs) + Complex._new(real * rhs, imaginary * rhs) end end def /(rhs) if rhs.is_a? Complex div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary - Complex((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) + Complex._new((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) elsif rhs.is_a? Numeric - Complex(real / rhs, imaginary / rhs) + Complex._new(real / rhs, imaginary / rhs) end end alias_method :quo, :/ @@ -92,14 +92,6 @@ class Complex < Numeric 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 @@ -117,36 +109,14 @@ class Complex < Numeric 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 -class << Complex - alias_method :_new, :new - undef_method :new - - alias_method :rect, :rectangular -end - module Kernel def Complex(real, imaginary = 0) Complex.rectangular(real, imaginary) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c new file mode 100644 index 000000000..5de0ae9a4 --- /dev/null +++ b/mrbgems/mruby-complex/src/complex.c @@ -0,0 +1,116 @@ +#include +#include +#include + +struct mrb_complex { + mrb_float real; + mrb_float imaginary; +}; + +#include + +static const struct mrb_data_type mrb_complex_type = {"Complex", mrb_free}; + +static mrb_value +complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) +{ + struct RClass *c = mrb_class_get(mrb, "Complex"); + struct mrb_complex *p; + + p = (struct mrb_complex*)mrb_malloc(mrb, sizeof(struct mrb_complex)); + p->real = real; + p->imaginary = imaginary; + + return mrb_obj_value(Data_Wrap_Struct(mrb, c, &mrb_complex_type, p)); +} + +static struct mrb_complex* +complex_ptr(mrb_state *mrb, mrb_value v) +{ + struct mrb_complex *p; + + p = DATA_GET_PTR(mrb, v, &mrb_complex_type, struct mrb_complex); + if (!p) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized complex"); + } + return p; +} + +static mrb_value +complex_real(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + return mrb_float_value(mrb, p->real); +} + +static mrb_value +complex_imaginary(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + return mrb_float_value(mrb, p->imaginary); +} + +static mrb_value +complex_s_new(mrb_state *mrb, mrb_value self) +{ + mrb_float real, imaginary; + + mrb_get_args(mrb, "ff", &real, &imaginary); + return complex_new(mrb, real, imaginary); +} + +#ifndef MRB_WITHOUT_FLOAT +static mrb_value +complex_to_f(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + + if (p->imaginary != 0) { + mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %S into Float", self); + } + + return mrb_float_value(mrb, p->real); +} +#endif + +static mrb_value +complex_to_i(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + + if (p->imaginary != 0) { + mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %S into Float", self); + } + return mrb_int_value(mrb, p->real); +} + +static mrb_value +complex_to_c(mrb_state *mrb, mrb_value self) +{ + return self; +} + +void mrb_mruby_complex_gem_init(mrb_state *mrb) +{ + struct RClass *comp; + +#ifdef COMPLEX_USE_ISTRUCT + mrb_assert(sizeof(struct mrb_complex) < ISTRUCT_DATA_SIZE); +#endif + comp = mrb_define_class(mrb, "Complex", mrb_class_get(mrb, "Numeric")); + //MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT); + mrb_undef_class_method(mrb, comp, "new"); + mrb_define_class_method(mrb, comp, "_new", complex_s_new, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, comp, "real", complex_real, MRB_ARGS_NONE()); + mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE()); +#ifndef MRB_WITHOUT_FLOAT + mrb_define_method(mrb, comp, "to_f", complex_to_f, MRB_ARGS_NONE()); +#endif + mrb_define_method(mrb, comp, "to_i", complex_to_i, MRB_ARGS_NONE()); + mrb_define_method(mrb, comp, "to_c", complex_to_c, MRB_ARGS_NONE()); +} + +void +mrb_mruby_complex_gem_final(mrb_state* mrb) +{ +} diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 549715e7d..2a3f6df09 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -37,7 +37,7 @@ rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) struct mrb_rational *p = rational_ptr(rat); p->numerator = numerator; p->denominator = denominator; - return mrb_obj_value(s); + return rat; } static mrb_value -- cgit v1.2.3 From 8513abd40404ef8cb8340da906f2d15101536de1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 22 May 2019 19:57:35 +0900 Subject: `Kernel#Rational` requires numerator --- mrbgems/mruby-rational/mrblib/rational.rb | 2 +- mrbgems/mruby-rational/test/rational.rb | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index c8614ecea..4936b1123 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -71,7 +71,7 @@ class Numeric end module Kernel - def Rational(numerator = 0, denominator = 1) + def Rational(numerator, denominator = 1) a = numerator b = denominator a, b = b, a % b until b == 0 diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index ea55880fe..914f8505e 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -27,6 +27,19 @@ assert 'Rational' do assert_equal([5, 1], [r.numerator, r.denominator]) end +assert 'Kernel#Rational' do + r = Rational(4,10) + assert_equal(2, r.numerator) + assert_equal(5, r.denominator) + + r = Rational(3) + assert_equal(3, r.numerator) + assert_equal(1, r.denominator) + + assert_raise(ArgumentError) { Rational() } + assert_raise(ArgumentError) { Rational(1,2,3) } +end + assert 'Rational#to_f' do assert_float(2.0, Rational(2).to_f) assert_float(2.25, Rational(9, 4).to_f) -- cgit v1.2.3 From 48903850e9041e74c526fef5e63857007d2cac38 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 23 May 2019 13:40:49 +0900 Subject: Freeze `Rational` and `Complex` objects --- mrbgems/mruby-complex/src/complex.c | 1 + mrbgems/mruby-complex/test/complex.rb | 8 +++++++- mrbgems/mruby-rational/src/rational.c | 1 + mrbgems/mruby-rational/test/rational.rb | 6 ++++++ 4 files changed, 15 insertions(+), 1 deletion(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index c6fb7a829..1b030c317 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -24,6 +24,7 @@ complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) struct mrb_complex *p = complex_ptr(mrb, comp); p->real = real; p->imaginary = imaginary; + MRB_SET_FROZEN_FLAG(s); return comp; } diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index e7fcc7322..6996eb214 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,5 +1,5 @@ def assert_complex(real, exp) - assert_float real.real, exp.real + assert_float real.real, exp.real assert_float real.imaginary, exp.imaginary end @@ -126,3 +126,9 @@ assert 'Complex::to_i' do Complex(1, 2).to_i end end + +assert 'Complex#frozen?' do + assert_predicate(1i, :frozen?) + assert_predicate(Complex(2,3), :frozen?) + assert_predicate(4+5i, :frozen?) +end diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 2a3f6df09..fa061c0b8 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -37,6 +37,7 @@ rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) struct mrb_rational *p = rational_ptr(rat); p->numerator = numerator; p->denominator = denominator; + MRB_SET_FROZEN_FLAG(s); return rat; } diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 914f8505e..1ed3b3a07 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -278,3 +278,9 @@ assert 'Rational#negative?' do assert_not_predicate(Rational(2,3), :negative?) assert_not_predicate(Rational(0), :negative?) end + +assert 'Rational#frozen?' do + assert_predicate(1r, :frozen?) + assert_predicate(Rational(2,3), :frozen?) + assert_predicate(4/5r, :frozen?) +end -- cgit v1.2.3 From 902b2ce3c669d4e3b5c20b2c90a3b3982f17d820 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 27 May 2019 21:29:49 +0900 Subject: Fix `Rational#==(Complex)` Consider a Numreic class like `Complex` that does not have `<=>` but `==` works (`0i == 0r` is `true`). --- mrbgems/mruby-rational/mrblib/rational.rb | 13 +++++++ mrbgems/mruby-rational/test/rational.rb | 58 ++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 20 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 4936b1123..54d9a955f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -62,6 +62,19 @@ class Rational < Numeric nil end end + + def ==(rhs) + if rhs.is_a?(Integral) + return numerator == rhs if denominator == 1 + rhs = Rational(rhs) + end + + if rhs.is_a?(Rational) + numerator * rhs.denominator == denominator * rhs.numerator + else + rhs == self + end + end end class Numeric diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 1ed3b3a07..5e9d9ea48 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -1,3 +1,27 @@ +class UserDefinedNumeric < Numeric + def initialize(n) + @n = n + end + + def <=>(rhs) + return nil unless rhs.respond_to?(:to_i) + rhs = rhs.to_i + rhs < 0 ? nil : @n <=> rhs + end + + def inspect + "#{self.class}(#{@n})" + end +end + +class ComplexLikeNumeric < UserDefinedNumeric + def ==(rhs) + @n == 0 && rhs == 0 + end + + undef <=> +end + def assert_rational(exp, real) assert_float exp.numerator, real.numerator assert_float exp.denominator, real.denominator @@ -17,7 +41,7 @@ def assert_cmp(exp, o1, o2) if exp == (o1 <=> o2) pass else - flunk "", " Expected #{o1.inspect} <=> #{o2.inspect} to be #{exp}" + flunk "", " Expected #{o1.inspect} <=> #{o2.inspect} to be #{exp}." end end @@ -106,6 +130,13 @@ assert 'Rational#==, Rational#!=' do assert_equal_rational(false, Rational(2,1), 1r) assert_equal_rational(false, Rational(1), nil) assert_equal_rational(false, Rational(1), '') + assert_equal_rational(true, 0r, UserDefinedNumeric.new(0)) + assert_equal_rational(true, 1r, UserDefinedNumeric.new(1)) + assert_equal_rational(false, 1r, UserDefinedNumeric.new(2)) + assert_equal_rational(false, -1r, UserDefinedNumeric.new(-1)) + assert_equal_rational(true, 0r, ComplexLikeNumeric.new(0)) + assert_equal_rational(false, 1r, ComplexLikeNumeric.new(1)) + assert_equal_rational(false, 1r, ComplexLikeNumeric.new(2)) end assert 'Fixnum#==(Rational), Fixnum#!=(Rational)' do @@ -123,21 +154,6 @@ assert 'Float#==(Rational), Float#!=(Rational)' do end assert 'Rational#<=>' do - num = Class.new(Numeric) do - def initialize(n) - @n = n - end - - def <=>(rhs) - rhs = rhs.to_i - rhs < 0 ? nil : @n <=> rhs - end - - def inspect - "num(#{@n})" - end - end - assert_cmp(-1, Rational(-1), Rational(0)) assert_cmp(0, Rational(0), Rational(0)) assert_cmp(1, Rational(1), Rational(0)) @@ -158,10 +174,12 @@ assert 'Rational#<=>' do assert_cmp(-1, Rational(1,2), Rational(2,3)) assert_cmp(-1, Rational(1,2), Rational(2,3)) assert_cmp(nil, 3r, "3") - assert_cmp(1, 3r, num.new(2)) - assert_cmp(0, 3r, num.new(3)) - assert_cmp(-1, 3r, num.new(4)) - assert_cmp(nil, Rational(-3), num.new(5)) + assert_cmp(1, 3r, UserDefinedNumeric.new(2)) + assert_cmp(0, 3r, UserDefinedNumeric.new(3)) + assert_cmp(-1, 3r, UserDefinedNumeric.new(4)) + assert_cmp(nil, Rational(-3), UserDefinedNumeric.new(5)) + assert_raise(NoMethodError) { 0r <=> ComplexLikeNumeric.new(0) } + assert_raise(NoMethodError) { 1r <=> ComplexLikeNumeric.new(2) } end assert 'Fixnum#<=>(Rational)' do -- cgit v1.2.3 From 855f2cdeea5c305e71721ef3c146eaa6472815b8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 May 2019 11:49:21 +0900 Subject: Slightly simplify `Rational#==`; ref #4475 --- mrbgems/mruby-rational/mrblib/rational.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 54d9a955f..93af72b96 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -64,11 +64,10 @@ class Rational < Numeric end def ==(rhs) - if rhs.is_a?(Integral) - return numerator == rhs if denominator == 1 - rhs = Rational(rhs) + return true if self.equal?(rhs) + if rhs.is_a?(Integral) && denominator == 1 + return numerator == rhs end - if rhs.is_a?(Rational) numerator * rhs.denominator == denominator * rhs.numerator else -- cgit v1.2.3 From 5e69760d919dd468ea8c8285f0f24affb52d3045 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 2 Jun 2019 17:21:33 +0900 Subject: Fix build error if `struct mrb_rational` is bigger than `RIStruct` In that case, to be switched implementation with `RData`. It is based to "complex". --- mrbgems/mruby-rational/src/rational.c | 69 ++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 14 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index fa061c0b8..db9a8fbb9 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -1,30 +1,71 @@ #include #include #include -#include struct mrb_rational { mrb_int numerator; mrb_int denominator; }; +#if MRB_INT_MAX <= INTPTR_MAX + +#define RATIONAL_USE_ISTRUCT +/* use TT_ISTRUCT */ +#include + +#define rational_ptr(mrb, v) (struct mrb_rational*)mrb_istruct_ptr(v) + +static struct RBasic* +rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p) +{ + struct RIStruct *s; + + s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); + *p = (struct mrb_rational*)s->inline_data; + + return (struct RBasic*)s; +} + +#else +/* use TT_DATA */ +#include + +static const struct mrb_data_type mrb_rational_type = {"Rational", mrb_free}; + +static struct RBasic* +rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p) +{ + struct RData *d; + + Data_Make_Struct(mrb, c, struct mrb_rational, &mrb_rational_type, *p, d); + + return (struct RBasic*)d; +} + static struct mrb_rational* -rational_ptr(mrb_value v) +rational_ptr(mrb_state *mrb, mrb_value v) { - return (struct mrb_rational*)mrb_istruct_ptr(v); + struct mrb_rational *p; + + p = DATA_GET_PTR(mrb, v, &mrb_rational_type, struct mrb_rational); + if (!p) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized rational"); + } + return p; } +#endif static mrb_value rational_numerator(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); return mrb_fixnum_value(p->numerator); } static mrb_value rational_denominator(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); return mrb_fixnum_value(p->denominator); } @@ -32,13 +73,12 @@ static mrb_value rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) { struct RClass *c = mrb_class_get(mrb, "Rational"); - struct RIStruct *s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); - mrb_value rat = mrb_obj_value(s); - struct mrb_rational *p = rational_ptr(rat); + struct mrb_rational *p; + struct RBasic *rat = rational_alloc(mrb, c, &p); p->numerator = numerator; p->denominator = denominator; - MRB_SET_FROZEN_FLAG(s); - return rat; + MRB_SET_FROZEN_FLAG(rat); + return mrb_obj_value(rat); } static mrb_value @@ -54,7 +94,7 @@ rational_s_new(mrb_state *mrb, mrb_value self) static mrb_value rational_to_f(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); mrb_float f = (mrb_float)p->numerator / (mrb_float)p->denominator; return mrb_float_value(mrb, f); @@ -64,7 +104,7 @@ rational_to_f(mrb_state *mrb, mrb_value self) static mrb_value rational_to_i(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); return mrb_fixnum_value(p->numerator / p->denominator); } @@ -77,7 +117,7 @@ rational_to_r(mrb_state *mrb, mrb_value self) static mrb_value rational_negative_p(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); if (p->numerator < 0) { return mrb_true_value(); } @@ -94,9 +134,10 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb) { struct RClass *rat; +#ifdef COMPLEX_USE_RATIONAL mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE); +#endif rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric")); - MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT); mrb_undef_class_method(mrb, rat, "new"); mrb_define_class_method(mrb, rat, "_new", rational_s_new, MRB_ARGS_REQ(2)); mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE()); -- cgit v1.2.3 From 64b3d452ec1cc3d5547da9ca37179f0e4406cc92 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 2 Jun 2019 18:00:54 +0900 Subject: Drop precisions for rational when big numbers --- mrbgems/mruby-rational/src/rational.c | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index db9a8fbb9..31471e934 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -1,6 +1,7 @@ #include #include #include +#include struct mrb_rational { mrb_int numerator; @@ -86,7 +87,52 @@ rational_s_new(mrb_state *mrb, mrb_value self) { mrb_int numerator, denominator; +#ifdef MRB_WITHOUT_FLOAT mrb_get_args(mrb, "ii", &numerator, &denominator); +#else + +#define DROP_PRECISION(cond, num, denom) \ + do { \ + while (cond) { \ + num /= 2; \ + denom /= 2; \ + } \ + } while (0) + + mrb_value numv, denomv; + + mrb_get_args(mrb, "oo", &numv, &denomv); + if (mrb_fixnum_p(numv)) { + numerator = mrb_fixnum(numv); + + if (mrb_fixnum_p(denomv)) { + denominator = mrb_fixnum(denomv); + } + else { + mrb_float denomf = mrb_to_flo(mrb, denomv); + + DROP_PRECISION(denomf < MRB_INT_MIN || denomf > MRB_INT_MAX, numerator, denomf); + denominator = denomf; + } + } + else { + mrb_float numf = mrb_to_flo(mrb, numv); + + if (mrb_fixnum_p(denomv)) { + denominator = mrb_fixnum(denomv); + } + else { + mrb_float denomf = mrb_to_flo(mrb, denomv); + + DROP_PRECISION(denomf < MRB_INT_MIN || denomf > MRB_INT_MAX, numf, denomf); + denominator = denomf; + } + + DROP_PRECISION(numf < MRB_INT_MIN || numf > MRB_INT_MAX, numf, denominator); + numerator = numf; + } +#endif + return rational_new(mrb, numerator, denominator); } @@ -105,6 +151,9 @@ static mrb_value rational_to_i(mrb_state *mrb, mrb_value self) { struct mrb_rational *p = rational_ptr(mrb, self); + if (p->denominator == 0) { + mrb_raise(mrb, mrb_exc_get(mrb, "StandardError"), "divided by 0"); + } return mrb_fixnum_value(p->numerator / p->denominator); } -- cgit v1.2.3 From a215292b6ad4315a5a0edef49a1df65e3f27b46a Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 28 Jun 2019 23:13:29 +0900 Subject: Use nested `assert` --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 8 +++++--- mrbgems/mruby-complex/test/complex.rb | 6 ++++-- mrbgems/mruby-io/test/io.rb | 32 +++++++++++++++++--------------- mrbgems/mruby-pack/test/pack.rb | 6 ++++-- mrbgems/mruby-rational/test/rational.rb | 20 ++++++++++++-------- 5 files changed, 42 insertions(+), 30 deletions(-) (limited to 'mrbgems/mruby-rational') diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index 09350ff49..5dbbc5592 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -3,9 +3,11 @@ require 'open3' def assert_mruby(exp_out, exp_err, exp_success, args) out, err, stat = Open3.capture3(cmd("mruby"), *args) - assert_operator(exp_out, :===, out, "standard output") - assert_operator(exp_err, :===, err, "standard error") - assert_equal(exp_success, stat.success?, "exit success?") + assert do + assert_operator(exp_out, :===, out, "standard output") + assert_operator(exp_err, :===, err, "standard error") + assert_equal(exp_success, stat.success?, "exit success?") + end end assert('regression for #1564') do diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index 6996eb214..ab882664e 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,6 +1,8 @@ def assert_complex(real, exp) - assert_float real.real, exp.real - assert_float real.imaginary, exp.imaginary + assert do + assert_float real.real, exp.real + assert_float real.imaginary, exp.imaginary + end end assert 'Complex' do diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index ef0b49643..1491a4cfe 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -5,24 +5,26 @@ MRubyIOTestUtil.io_test_setup $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] def assert_io_open(meth) - fd = IO.sysopen($mrbtest_io_rfname) - assert_equal Fixnum, fd.class - io1 = IO.__send__(meth, fd) - begin - assert_equal IO, io1.class - assert_equal $mrbtest_io_msg, io1.read - ensure - io1.close - end + assert do + fd = IO.sysopen($mrbtest_io_rfname) + assert_equal Fixnum, fd.class + io1 = IO.__send__(meth, fd) + begin + assert_equal IO, io1.class + assert_equal $mrbtest_io_msg, io1.read + ensure + io1.close + end - io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io| - if meth == :open - assert_equal $mrbtest_io_msg, io.read - else - flunk "IO.#{meth} does not take block" + io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io| + if meth == :open + assert_equal $mrbtest_io_msg, io.read + else + flunk "IO.#{meth} does not take block" + end end + io2.close unless meth == :open end - io2.close unless meth == :open end assert('IO.class', '15.2.20') do diff --git a/mrbgems/mruby-pack/test/pack.rb b/mrbgems/mruby-pack/test/pack.rb index 110aee5db..eb24e8d1f 100644 --- a/mrbgems/mruby-pack/test/pack.rb +++ b/mrbgems/mruby-pack/test/pack.rb @@ -2,8 +2,10 @@ PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 def assert_pack tmpl, packed, unpacked t = tmpl.inspect - assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" - assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" + assert do + assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" + assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" + end end # pack & unpack 'm' (base64) diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 5e9d9ea48..11737034b 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -23,17 +23,21 @@ class ComplexLikeNumeric < UserDefinedNumeric end def assert_rational(exp, real) - assert_float exp.numerator, real.numerator - assert_float exp.denominator, real.denominator + assert do + assert_float exp.numerator, real.numerator + assert_float exp.denominator, real.denominator + end end def assert_equal_rational(exp, o1, o2) - if exp - assert_operator(o1, :==, o2) - assert_not_operator(o1, :!=, o2) - else - assert_not_operator(o1, :==, o2) - assert_operator(o1, :!=, o2) + assert do + if exp + assert_operator(o1, :==, o2) + assert_not_operator(o1, :!=, o2) + else + assert_not_operator(o1, :==, o2) + assert_operator(o1, :!=, o2) + end end end -- cgit v1.2.3