summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-01-17 23:08:10 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-01-17 23:08:10 +0000
commit94db3129237412315f31afd07a09b9b91d223494 (patch)
tree4c579fc569ffee059ca4d03aba0ae586392aa9a7
parenta5dae936e095be836b7aa88c339d4f1bd5f04a22 (diff)
merge revision(s) 66681,66682,66684,66688,66697,66751,66693,66694: [Backport #15491]
complex.c: Optimize Complex#+ for some conditions Optimize f_add defined in complex.c for some specific conditions. It makes Complex#+ about 1.4x faster than r66678. Compared to r66678: ``` mrkn-mbp15-late2016:complex-optim-o3 mrkn$ make benchmark ITEM=complex_float_ COMPARE_RUBY=/Users/mrkn/.rbenv/versions/trunk-o3/bin/ruby /Users/mrkn/src/github.com/ruby/ruby/revision.h unchanged /Users/mrkn/.rbenv/shims/ruby --disable=gems -rrubygems -I/Users/mrkn/src/github.com/ruby/ruby/benchmark/lib /Users/mrkn/src/github.com/ruby/ruby/benchmark/benchmark-driver/exe/benchmark-driver \ --executables="compare-ruby::/Users/mrkn/.rbenv/versions/trunk-o3/bin/ruby -I.ext/common --disable-gem" \ --executables="built-ruby::./miniruby -I/Users/mrkn/src/github.com/ruby/ruby/lib -I. -I.ext/common -r/Users/mrkn/src/github.com/ruby/ruby/prelude --disable-gem" \ $(find /Users/mrkn/src/github.com/ruby/ruby/benchmark -maxdepth 1 -name '*complex_float_*.yml' -o -name '*complex_float_*.rb' | sort) Calculating ------------------------------------- compare-ruby built-ruby complex_float_add 9.132M 12.864M i/s - 1.000M times in 0.109511s 0.077734s complex_float_div 600.723k 627.878k i/s - 1.000M times in 1.664662s 1.592666s complex_float_mul 2.320M 2.347M i/s - 1.000M times in 0.431039s 0.426113s complex_float_new 1.473M 1.489M i/s - 1.000M times in 0.678791s 0.671750s complex_float_power 1.690M 1.722M i/s - 1.000M times in 0.591863s 0.580775s complex_float_sub 8.870M 9.516M i/s - 1.000M times in 0.112740s 0.105091s Comparison: complex_float_add built-ruby: 12864383.7 i/s compare-ruby: 9131502.8 i/s - 1.41x slower complex_float_div built-ruby: 627878.0 i/s compare-ruby: 600722.5 i/s - 1.05x slower complex_float_mul built-ruby: 2346795.3 i/s compare-ruby: 2319975.7 i/s - 1.01x slower complex_float_new built-ruby: 1488649.1 i/s compare-ruby: 1473207.5 i/s - 1.01x slower complex_float_power built-ruby: 1721837.2 i/s compare-ruby: 1689580.2 i/s - 1.02x slower complex_float_sub built-ruby: 9515562.7 i/s compare-ruby: 8869966.3 i/s - 1.07x slower ``` suppress warning: method redefined; discarding old + introduced at r66681 complex.c: fix indentation complex.c: fix against redefining component methods This fixes the incompatibility (maybe unintentionally) introduced by removal of `#ifndef PRESERVE_SIGNEDZERO` guards in f_add, f_mul, and f_sub functions in r62701. [Bug #15491] [ruby-core:90843] complex.c: Optimize Complex#* and Complex#** Optimize f_mul for the core numeric class components. This change improves the computation time of Complex#* and Complex#**. ``` $ make benchmark ITEM=complex_float_ COMPARE_RUBY=/Users/mrkn/.rbenv/versions/2.6.0/bin/ruby generating known_errors.inc known_errors.inc unchanged /Users/mrkn/src/github.com/ruby/ruby/revision.h unchanged /Users/mrkn/.rbenv/shims/ruby --disable=gems -rrubygems -I/Users/mrkn/src/github.com/ruby/ruby/benchmark/lib /Users/mrkn/src/github.com/ruby/ruby/benchmark/benchmark-driver/exe/benchmark-driver \ --executables="compare-ruby::/Users/mrkn/.rbenv/versions/2.6.0/bin/ruby -I.ext/common --disable-gem" \ --executables="built-ruby::./miniruby -I/Users/mrkn/src/github.com/ruby/ruby/lib -I. -I.ext/common -r/Users/mrkn/src/github.com/ruby/ruby/prelude --disable-gem" \ $(find /Users/mrkn/src/github.com/ruby/ruby/benchmark -maxdepth 1 -name '*complex_float_*.yml' -o -name '*complex_float_*.rb' | sort) Calculating ------------------------------------- compare-ruby built-ruby complex_float_add 6.558M 13.012M i/s - 1.000M times in 0.152480s 0.076850s complex_float_div 576.821k 567.969k i/s - 1.000M times in 1.733640s 1.760660s complex_float_mul 1.690M 2.628M i/s - 1.000M times in 0.591786s 0.380579s complex_float_new 1.350M 1.268M i/s - 1.000M times in 0.740669s 0.788762s complex_float_power 1.571M 1.835M i/s - 1.000M times in 0.636507s 0.544909s complex_float_sub 8.635M 8.779M i/s - 1.000M times in 0.115814s 0.113906s Comparison: complex_float_add built-ruby: 13012361.7 i/s compare-ruby: 6558237.1 i/s - 1.98x slower complex_float_div compare-ruby: 576821.0 i/s built-ruby: 567968.8 i/s - 1.02x slower complex_float_mul built-ruby: 2627575.4 i/s compare-ruby: 1689800.0 i/s - 1.55x slower complex_float_new compare-ruby: 1350130.8 i/s built-ruby: 1267809.6 i/s - 1.06x slower complex_float_power built-ruby: 1835168.8 i/s compare-ruby: 1571074.6 i/s - 1.17x slower complex_float_sub built-ruby: 8779168.8 i/s compare-ruby: 8634534.7 i/s - 1.02x slower ``` complex.c: replace misused UNLIKELY with LIKELY test_complex.rb: fix tests for RUBYOPT="-w" test_complex.rb: use the same approach to fix failures as r66682. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_6@66854 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--complex.c58
-rw-r--r--internal.h3
-rw-r--r--numeric.c12
-rw-r--r--rational.c8
-rw-r--r--test/ruby/test_complex.rb102
-rw-r--r--version.h2
6 files changed, 163 insertions, 22 deletions
diff --git a/complex.c b/complex.c
index 64065b68cc..ab50daabaf 100644
--- a/complex.c
+++ b/complex.c
@@ -71,10 +71,27 @@ f_##n(VALUE x, VALUE y)\
inline static VALUE
f_add(VALUE x, VALUE y)
{
- if (FIXNUM_ZERO_P(y))
- return x;
- if (FIXNUM_ZERO_P(x))
- return y;
+ if (RB_INTEGER_TYPE_P(x) &&
+ LIKELY(rb_method_basic_definition_p(rb_cInteger, idPLUS))) {
+ if (FIXNUM_ZERO_P(x))
+ return y;
+ if (FIXNUM_ZERO_P(y))
+ return x;
+ return rb_int_plus(x, y);
+ }
+ else if (RB_FLOAT_TYPE_P(x) &&
+ LIKELY(rb_method_basic_definition_p(rb_cFloat, idPLUS))) {
+ if (FIXNUM_ZERO_P(y))
+ return x;
+ return rb_float_plus(x, y);
+ }
+ else if (RB_TYPE_P(x, T_RATIONAL) &&
+ LIKELY(rb_method_basic_definition_p(rb_cRational, idPLUS))) {
+ if (FIXNUM_ZERO_P(y))
+ return x;
+ return rb_rational_plus(x, y);
+ }
+
return rb_funcall(x, '+', 1, y);
}
@@ -106,20 +123,39 @@ f_gt_p(VALUE x, VALUE y)
inline static VALUE
f_mul(VALUE x, VALUE y)
{
- if (FIXNUM_ZERO_P(y) && RB_INTEGER_TYPE_P(x))
- return ZERO;
- if (FIXNUM_ZERO_P(x) && RB_INTEGER_TYPE_P(y))
- return ZERO;
- if (y == ONE) return x;
- if (x == ONE) return y;
+ if (RB_INTEGER_TYPE_P(x) &&
+ LIKELY(rb_method_basic_definition_p(rb_cInteger, idMULT))) {
+ if (FIXNUM_ZERO_P(y))
+ return ZERO;
+ if (FIXNUM_ZERO_P(x) && RB_INTEGER_TYPE_P(y))
+ return ZERO;
+ if (x == ONE) return y;
+ if (y == ONE) return x;
+ return rb_int_mul(x, y);
+ }
+ else if (RB_FLOAT_TYPE_P(x) &&
+ LIKELY(rb_method_basic_definition_p(rb_cFloat, idMULT))) {
+ if (y == ONE) return x;
+ return rb_float_mul(x, y);
+ }
+ else if (RB_TYPE_P(x, T_RATIONAL) &&
+ LIKELY(rb_method_basic_definition_p(rb_cRational, idMULT))) {
+ if (y == ONE) return x;
+ return rb_rational_mul(x, y);
+ }
+ else if (LIKELY(rb_method_basic_definition_p(CLASS_OF(x), idMULT))) {
+ if (y == ONE) return x;
+ }
return rb_funcall(x, '*', 1, y);
}
inline static VALUE
f_sub(VALUE x, VALUE y)
{
- if (FIXNUM_ZERO_P(y))
+ if (FIXNUM_ZERO_P(y) &&
+ LIKELY(rb_method_basic_definition_p(CLASS_OF(x), idMINUS))) {
return x;
+ }
return rb_funcall(x, '-', 1, y);
}
diff --git a/internal.h b/internal.h
index 433ab6635d..d107fbe7c7 100644
--- a/internal.h
+++ b/internal.h
@@ -1677,8 +1677,10 @@ VALUE rb_int_pred(VALUE num);
VALUE rb_int_uminus(VALUE num);
VALUE rb_float_uminus(VALUE num);
VALUE rb_int_plus(VALUE x, VALUE y);
+VALUE rb_float_plus(VALUE x, VALUE y);
VALUE rb_int_minus(VALUE x, VALUE y);
VALUE rb_int_mul(VALUE x, VALUE y);
+VALUE rb_float_mul(VALUE x, VALUE y);
VALUE rb_int_idiv(VALUE x, VALUE y);
VALUE rb_int_modulo(VALUE x, VALUE y);
VALUE rb_int_round(VALUE num, int ndigits, enum ruby_num_rounding_mode mode);
@@ -1970,6 +1972,7 @@ void rb_last_status_clear(void);
VALUE rb_rational_canonicalize(VALUE x);
VALUE rb_rational_uminus(VALUE self);
VALUE rb_rational_plus(VALUE self, VALUE other);
+VALUE rb_rational_mul(VALUE self, VALUE other);
VALUE rb_lcm(VALUE x, VALUE y);
VALUE rb_rational_reciprocal(VALUE x);
VALUE rb_cstr_to_rat(const char *, int);
diff --git a/numeric.c b/numeric.c
index ef7c58e870..4d8fd0bf09 100644
--- a/numeric.c
+++ b/numeric.c
@@ -1018,8 +1018,8 @@ rb_float_uminus(VALUE flt)
* Returns a new Float which is the sum of +float+ and +other+.
*/
-static VALUE
-flo_plus(VALUE x, VALUE y)
+VALUE
+rb_float_plus(VALUE x, VALUE y)
{
if (RB_TYPE_P(y, T_FIXNUM)) {
return DBL2NUM(RFLOAT_VALUE(x) + (double)FIX2LONG(y));
@@ -1066,8 +1066,8 @@ flo_minus(VALUE x, VALUE y)
* Returns a new Float which is the product of +float+ and +other+.
*/
-static VALUE
-flo_mul(VALUE x, VALUE y)
+VALUE
+rb_float_mul(VALUE x, VALUE y)
{
if (RB_TYPE_P(y, T_FIXNUM)) {
return DBL2NUM(RFLOAT_VALUE(x) * (double)FIX2LONG(y));
@@ -5674,9 +5674,9 @@ Init_Numeric(void)
rb_define_alias(rb_cFloat, "inspect", "to_s");
rb_define_method(rb_cFloat, "coerce", flo_coerce, 1);
rb_define_method(rb_cFloat, "-@", rb_float_uminus, 0);
- rb_define_method(rb_cFloat, "+", flo_plus, 1);
+ rb_define_method(rb_cFloat, "+", rb_float_plus, 1);
rb_define_method(rb_cFloat, "-", flo_minus, 1);
- rb_define_method(rb_cFloat, "*", flo_mul, 1);
+ rb_define_method(rb_cFloat, "*", rb_float_mul, 1);
rb_define_method(rb_cFloat, "/", flo_div, 1);
rb_define_method(rb_cFloat, "quo", flo_quo, 1);
rb_define_method(rb_cFloat, "fdiv", flo_quo, 1);
diff --git a/rational.c b/rational.c
index f668cc4691..236bc08e39 100644
--- a/rational.c
+++ b/rational.c
@@ -877,8 +877,8 @@ f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
* Rational(9, 8) * 4 #=> (9/2)
* Rational(20, 9) * 9.8 #=> 21.77777777777778
*/
-static VALUE
-nurat_mul(VALUE self, VALUE other)
+VALUE
+rb_rational_mul(VALUE self, VALUE other)
{
if (RB_INTEGER_TYPE_P(other)) {
{
@@ -1396,7 +1396,7 @@ f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE))
rb_raise(rb_eTypeError, "not an integer");
b = f_expt10(n);
- s = nurat_mul(self, b);
+ s = rb_rational_mul(self, b);
if (k_float_p(s)) {
if (INT_NEGATIVE_P(n))
@@ -2734,7 +2734,7 @@ Init_Rational(void)
rb_define_method(rb_cRational, "-@", rb_rational_uminus, 0);
rb_define_method(rb_cRational, "+", rb_rational_plus, 1);
rb_define_method(rb_cRational, "-", nurat_sub, 1);
- rb_define_method(rb_cRational, "*", nurat_mul, 1);
+ rb_define_method(rb_cRational, "*", rb_rational_mul, 1);
rb_define_method(rb_cRational, "/", nurat_div, 1);
rb_define_method(rb_cRational, "quo", nurat_div, 1);
rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
diff --git a/test/ruby/test_complex.rb b/test/ruby/test_complex.rb
index 1180e9acb0..4aa3eda1d4 100644
--- a/test/ruby/test_complex.rb
+++ b/test/ruby/test_complex.rb
@@ -269,6 +269,39 @@ class Complex_Test < Test::Unit::TestCase
assert_equal(Complex(Rational(5,3),Rational(2)), c + Rational(2,3))
end
+ def test_add_with_redefining_int_plus
+ assert_in_out_err([], <<-'end;', ['true'], [])
+ class Integer
+ remove_method :+
+ def +(other); 42; end
+ end
+ a = Complex(1, 2) + Complex(0, 1)
+ puts a == Complex(42, 42)
+ end;
+ end
+
+ def test_add_with_redefining_float_plus
+ assert_in_out_err([], <<-'end;', ['true'], [])
+ class Float
+ remove_method :+
+ def +(other); 42.0; end
+ end
+ a = Complex(1.0, 2.0) + Complex(0, 1)
+ puts a == Complex(42.0, 42.0)
+ end;
+ end
+
+ def test_add_with_redefining_rational_plus
+ assert_in_out_err([], <<-'end;', ['true'], [])
+ class Rational
+ remove_method :+
+ def +(other); 355/113r; end
+ end
+ a = Complex(1r, 2r) + Complex(0, 1)
+ puts a == Complex(355/113r, 355/113r)
+ end;
+ end
+
def test_sub
c = Complex(1,2)
c2 = Complex(2,3)
@@ -282,6 +315,39 @@ class Complex_Test < Test::Unit::TestCase
assert_equal(Complex(Rational(1,3),Rational(2)), c - Rational(2,3))
end
+ def test_sub_with_redefining_int_minus
+ assert_in_out_err([], <<-'end;', ['true'], [])
+ class Integer
+ remove_method :-
+ def -(other); 42; end
+ end
+ a = Complex(1, 2) - Complex(0, 1)
+ puts a == Complex(42, 42)
+ end;
+ end
+
+ def test_sub_with_redefining_float_minus
+ assert_in_out_err([], <<-'end;', ['true'], [])
+ class Float
+ remove_method :-
+ def -(other); 42.0; end
+ end
+ a = Complex(1.0, 2.0) - Complex(0, 1)
+ puts a == Complex(42.0, 42.0)
+ end;
+ end
+
+ def test_sub_with_redefining_rational_minus
+ assert_in_out_err([], <<-'end;', ['true'], [])
+ class Rational
+ remove_method :-
+ def -(other); 355/113r; end
+ end
+ a = Complex(1r, 2r) - Complex(0, 1)
+ puts a == Complex(355/113r, 355/113r)
+ end;
+ end
+
def test_mul
c = Complex(1,2)
c2 = Complex(2,3)
@@ -300,6 +366,42 @@ class Complex_Test < Test::Unit::TestCase
c = Complex(0, Float::INFINITY)
assert_equal(Complex(0, Float::INFINITY), c * Complex(1, 0))
assert_equal(Complex(-Float::INFINITY, 0), c * Complex(0, 1))
+
+ assert_equal(Complex(-0.0, -0.0), Complex(-0.0, 0) * Complex(0, 0))
+ end
+
+ def test_mul_with_redefining_int_mult
+ assert_in_out_err([], <<-'end;', ['true'], [])
+ class Integer
+ remove_method :*
+ def *(other); 42; end
+ end
+ a = Complex(2, 0) * Complex(1, 2)
+ puts a == Complex(0, 84)
+ end;
+ end
+
+ def test_mul_with_redefining_float_mult
+ assert_in_out_err([], <<-'end;', ['true'], [])
+ class Float
+ remove_method :*
+ def *(other); 42.0; end
+ end
+ a = Complex(2.0, 0.0) * Complex(1, 2)
+ puts a == Complex(0.0, 84.0)
+ end;
+ end
+
+
+ def test_mul_with_redefining_rational_mult
+ assert_in_out_err([], <<-'end;', ['true'], [])
+ class Rational
+ remove_method :*
+ def *(other); 355/113r; end
+ end
+ a = Complex(2r, 0r) * Complex(1, 2)
+ puts a == Complex(0r, 2*355/113r)
+ end;
end
def test_div
diff --git a/version.h b/version.h
index 16a74518e8..3c581a4441 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.6.0"
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
-#define RUBY_PATCHLEVEL 22
+#define RUBY_PATCHLEVEL 23
#define RUBY_RELEASE_YEAR 2019
#define RUBY_RELEASE_MONTH 1