Feature #12172
Updated by mame (Yusuke Endoh) over 9 years ago
I propose to define `Array#max`. It is 10+ times faster than `Enumerable#max` since it skips a call to `#each`.
~~~~
a = [*1..10000]; 100000.times { a.max }
~~~~
* no patch: 22.424s
* Array#max defined: 1.740s
I don't think it is a good idea to copy all Enumerable methods to Array. But there are two reasons why `max` is special:
* It is one of the most basic operations for big data processing.
* We often use an idiom `[a, b].max` because of the lack of `Math.max(a, b)`.
I think the latter is particularly important. The idiom is concise but unsuitable in a hotspot since it creates a temporal array. If `Array#max` is defined, we can easily optimize the idiom by introducing a special instruction like `opt_newarray_max`.
~~~~
x, y = 1, 2; 10000000.times { [x, y].max }
~~~~
* no patch: 2.799s
* Array#max defined: 1.224s
* opt_newarray_max: 0.555s
~~~~
$ ./miniruby ./miniruby.opt2 --dump=insns -e 'x, y = 1, 2; [x, [x. y].max'
== disasm: #<ISeq:<main>@-e>============================================
local table (size: 3, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 3] x [ 2] y
0000 trace 1 ( 1)
0002 putobject_OP_INT2FIX_O_1_C_
0003 putobject 2
0005 setlocal_OP__WC__0 2
0007 setlocal_OP__WC__0 3
0009 getlocal_OP__WC__0 3
0011 getlocal_OP__WC__0 2 opt_send_without_block <callinfo!mid:y, argc:0, ARGS_SIMPLE>, <callcache>
0013 0014 opt_newarray_max 2 1
0015 0016 leave
~~~~
The patches are attached. (0001 is a preparation. 0002 introduces `Array#max`. 0003 introduces a special instruction.)
Of course, we can say the same for `Array#min`. The patches include `Array#min` too.
What do you think?