mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Optimize Array#max (#3325)
The benchmark result is below: | |compare-ruby|built-ruby| |:---------------|-----------:|---------:| |ary2.max | 38.837M| 40.830M| | | -| 1.05x| |ary10.max | 23.035M| 32.626M| | | -| 1.42x| |ary100.max | 5.490M| 11.020M| | | -| 2.01x| |ary500.max | 1.324M| 2.679M| | | -| 2.02x| |ary1000.max | 699.167k| 1.403M| | | -| 2.01x| |ary2000.max | 284.321k| 570.446k| | | -| 2.01x| |ary3000.max | 282.613k| 571.683k| | | -| 2.02x| |ary5000.max | 145.120k| 285.546k| | | -| 1.97x| |ary10000.max | 72.102k| 142.831k| | | -| 1.98x| |ary20000.max | 36.065k| 72.077k| | | -| 2.00x| |ary50000.max | 14.343k| 29.139k| | | -| 2.03x| |ary100000.max | 7.586k| 14.472k| | | -| 1.91x| |ary1000000.max | 726.915| 1.495k| | | -| 2.06x|
This commit is contained in:
parent
9f60ceec54
commit
a63f520971
Notes:
git
2020-07-18 23:45:25 +09:00
Merged-By: mrkn <mrkn@ruby-lang.org>
5 changed files with 200 additions and 7 deletions
107
array.c
107
array.c
|
@ -6177,6 +6177,95 @@ rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
|
|||
return ary_union;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ary_max_generic(VALUE ary, long i, VALUE vmax)
|
||||
{
|
||||
RUBY_ASSERT(i > 0 && i < RARRAY_LEN(ary));
|
||||
|
||||
VALUE v;
|
||||
for (; i < RARRAY_LEN(ary); ++i) {
|
||||
v = RARRAY_AREF(ary, i);
|
||||
|
||||
if (rb_cmpint(rb_funcallv(vmax, id_cmp, 1, &v), vmax, v) < 0) {
|
||||
vmax = v;
|
||||
}
|
||||
}
|
||||
|
||||
return vmax;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ary_max_opt_fixnum(VALUE ary, long i, VALUE vmax)
|
||||
{
|
||||
const long n = RARRAY_LEN(ary);
|
||||
RUBY_ASSERT(i > 0 && i < n);
|
||||
RUBY_ASSERT(FIXNUM_P(vmax));
|
||||
|
||||
VALUE v;
|
||||
for (; i < n; ++i) {
|
||||
v = RARRAY_AREF(ary, i);
|
||||
|
||||
if (FIXNUM_P(v)) {
|
||||
if ((long)vmax < (long)v) {
|
||||
vmax = v;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ary_max_generic(ary, i, vmax);
|
||||
}
|
||||
}
|
||||
|
||||
return vmax;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ary_max_opt_float(VALUE ary, long i, VALUE vmax)
|
||||
{
|
||||
const long n = RARRAY_LEN(ary);
|
||||
RUBY_ASSERT(i > 0 && i < n);
|
||||
RUBY_ASSERT(RB_FLOAT_TYPE_P(vmax));
|
||||
|
||||
VALUE v;
|
||||
for (; i < n; ++i) {
|
||||
v = RARRAY_AREF(ary, i);
|
||||
|
||||
if (RB_FLOAT_TYPE_P(v)) {
|
||||
if (rb_float_cmp(vmax, v) < 0) {
|
||||
vmax = v;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ary_max_generic(ary, i, vmax);
|
||||
}
|
||||
}
|
||||
|
||||
return vmax;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ary_max_opt_string(VALUE ary, long i, VALUE vmax)
|
||||
{
|
||||
const long n = RARRAY_LEN(ary);
|
||||
RUBY_ASSERT(i > 0 && i < n);
|
||||
RUBY_ASSERT(STRING_P(vmax));
|
||||
|
||||
VALUE v;
|
||||
for (; i < n; ++i) {
|
||||
v = RARRAY_AREF(ary, i);
|
||||
|
||||
if (STRING_P(v)) {
|
||||
if (rb_str_cmp(vmax, v) < 0) {
|
||||
vmax = v;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ary_max_generic(ary, i, vmax);
|
||||
}
|
||||
}
|
||||
|
||||
return vmax;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* ary.max -> obj
|
||||
|
@ -6210,6 +6299,7 @@ rb_ary_max(int argc, VALUE *argv, VALUE ary)
|
|||
if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
|
||||
return rb_nmin_run(ary, num, 0, 1, 1);
|
||||
|
||||
const long n = RARRAY_LEN(ary);
|
||||
if (rb_block_given_p()) {
|
||||
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
||||
v = RARRAY_AREF(ary, i);
|
||||
|
@ -6218,11 +6308,20 @@ rb_ary_max(int argc, VALUE *argv, VALUE ary)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (n > 0) {
|
||||
result = RARRAY_AREF(ary, 0);
|
||||
if (n > 1) {
|
||||
if (FIXNUM_P(result) && CMP_OPTIMIZABLE(cmp_opt, Integer)) {
|
||||
return ary_max_opt_fixnum(ary, 1, result);
|
||||
}
|
||||
else if (STRING_P(result) && CMP_OPTIMIZABLE(cmp_opt, String)) {
|
||||
return ary_max_opt_string(ary, 1, result);
|
||||
}
|
||||
else if (RB_FLOAT_TYPE_P(result) && CMP_OPTIMIZABLE(cmp_opt, Float)) {
|
||||
return ary_max_opt_float(ary, 1, result);
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
||||
v = RARRAY_AREF(ary, i);
|
||||
if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) > 0) {
|
||||
result = v;
|
||||
return ary_max_generic(ary, 1, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
30
benchmark/array_max_float.yml
Normal file
30
benchmark/array_max_float.yml
Normal file
|
@ -0,0 +1,30 @@
|
|||
prelude: |
|
||||
ary2 = 2.times.map(&:to_f).shuffle
|
||||
ary10 = 10.times.map(&:to_f).shuffle
|
||||
ary100 = 100.times.map(&:to_f).shuffle
|
||||
ary500 = 500.times.map(&:to_f).shuffle
|
||||
ary1000 = 1000.times.map(&:to_f).shuffle
|
||||
ary2000 = 2500.times.map(&:to_f).shuffle
|
||||
ary3000 = 2500.times.map(&:to_f).shuffle
|
||||
ary5000 = 5000.times.map(&:to_f).shuffle
|
||||
ary10000 = 10000.times.map(&:to_f).shuffle
|
||||
ary20000 = 20000.times.map(&:to_f).shuffle
|
||||
ary50000 = 50000.times.map(&:to_f).shuffle
|
||||
ary100000 = 100000.times.map(&:to_f).shuffle
|
||||
|
||||
benchmark:
|
||||
ary2.max: ary2.max
|
||||
ary10.max: ary10.max
|
||||
ary100.max: ary100.max
|
||||
ary500.max: ary500.max
|
||||
ary1000.max: ary1000.max
|
||||
ary2000.max: ary2000.max
|
||||
ary3000.max: ary3000.max
|
||||
ary5000.max: ary5000.max
|
||||
ary10000.max: ary10000.max
|
||||
ary20000.max: ary20000.max
|
||||
ary50000.max: ary50000.max
|
||||
ary100000.max: ary100000.max
|
||||
|
||||
loop_count: 10000
|
||||
|
31
benchmark/array_max_int.yml
Normal file
31
benchmark/array_max_int.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
prelude: |
|
||||
ary2 = 2.times.to_a.shuffle
|
||||
ary10 = 10.times.to_a.shuffle
|
||||
ary100 = 100.times.to_a.shuffle
|
||||
ary500 = 500.times.to_a.shuffle
|
||||
ary1000 = 1000.times.to_a.shuffle
|
||||
ary2000 = 2500.times.to_a.shuffle
|
||||
ary3000 = 2500.times.to_a.shuffle
|
||||
ary5000 = 5000.times.to_a.shuffle
|
||||
ary10000 = 10000.times.to_a.shuffle
|
||||
ary20000 = 20000.times.to_a.shuffle
|
||||
ary50000 = 50000.times.to_a.shuffle
|
||||
ary100000 = 100000.times.to_a.shuffle
|
||||
ary1000000 = 1000000.times.to_a.shuffle
|
||||
|
||||
benchmark:
|
||||
ary2.max: ary2.max
|
||||
ary10.max: ary10.max
|
||||
ary100.max: ary100.max
|
||||
ary500.max: ary500.max
|
||||
ary1000.max: ary1000.max
|
||||
ary2000.max: ary2000.max
|
||||
ary3000.max: ary3000.max
|
||||
ary5000.max: ary5000.max
|
||||
ary10000.max: ary10000.max
|
||||
ary20000.max: ary20000.max
|
||||
ary50000.max: ary50000.max
|
||||
ary100000.max: ary100000.max
|
||||
ary1000000.max: ary1000000.max
|
||||
|
||||
loop_count: 10000
|
30
benchmark/array_max_str.yml
Normal file
30
benchmark/array_max_str.yml
Normal file
|
@ -0,0 +1,30 @@
|
|||
prelude: |
|
||||
ary2 = 2.times.map(&:to_s).shuffle
|
||||
ary10 = 10.times.map(&:to_s).shuffle
|
||||
ary100 = 100.times.map(&:to_s).shuffle
|
||||
ary500 = 500.times.map(&:to_s).shuffle
|
||||
ary1000 = 1000.times.map(&:to_s).shuffle
|
||||
ary2000 = 2500.times.map(&:to_s).shuffle
|
||||
ary3000 = 2500.times.map(&:to_s).shuffle
|
||||
ary5000 = 5000.times.map(&:to_s).shuffle
|
||||
ary10000 = 10000.times.map(&:to_s).shuffle
|
||||
ary20000 = 20000.times.map(&:to_s).shuffle
|
||||
ary50000 = 50000.times.map(&:to_s).shuffle
|
||||
ary100000 = 100000.times.map(&:to_s).shuffle
|
||||
|
||||
benchmark:
|
||||
ary2.max: ary2.max
|
||||
ary10.max: ary10.max
|
||||
ary100.max: ary100.max
|
||||
ary500.max: ary500.max
|
||||
ary1000.max: ary1000.max
|
||||
ary2000.max: ary2000.max
|
||||
ary3000.max: ary3000.max
|
||||
ary5000.max: ary5000.max
|
||||
ary10000.max: ary10000.max
|
||||
ary20000.max: ary20000.max
|
||||
ary50000.max: ary50000.max
|
||||
ary100000.max: ary100000.max
|
||||
|
||||
loop_count: 10000
|
||||
|
|
@ -1756,10 +1756,12 @@ class TestArray < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_max
|
||||
assert_equal(1, [1].max)
|
||||
assert_equal(3, [1, 2, 3, 1, 2].max)
|
||||
assert_equal(1, [1, 2, 3, 1, 2].max {|a,b| b <=> a })
|
||||
cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
|
||||
assert_equal([1, 3], [1, 2, 3, 1, 2].each_with_index.max(&cond))
|
||||
assert_equal(3.0, [1.0, 3.0, 2.0].max)
|
||||
ary = %w(albatross dog horse)
|
||||
assert_equal("horse", ary.max)
|
||||
assert_equal("albatross", ary.max {|a,b| a.length <=> b.length })
|
||||
|
@ -1777,6 +1779,7 @@ class TestArray < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_minmax
|
||||
assert_equal([3, 3], [3].minmax)
|
||||
assert_equal([1, 3], [1, 2, 3, 1, 2].minmax)
|
||||
assert_equal([3, 1], [1, 2, 3, 1, 2].minmax {|a,b| b <=> a })
|
||||
cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
|
||||
|
|
Loading…
Reference in a new issue