in reply to Best way to sum an array?

List::Util (the XS version) beats them all:

Rate recursive recursive2 eval iterative list +util recursive 1244/s -- -4% -68% -97% - +100% recursive2 1297/s 4% -- -67% -97% - +100% eval 3930/s 216% 203% -- -91% +-99% iterative 42708/s 3332% 3192% 987% -- +-85% listutil 281788/s 22544% 21622% 7071% 560% + --
use warnings; use strict; use Benchmark qw/cmpthese/; use List::Util::XS; use List::Util qw/sum/; my @array = 1..1000; my $expect = sum(@array); { use feature 'current_sub'; no warnings 'recursion'; sub SumArryRcs { 1==@_?$_[0]:1>@_?die:shift(@_)+__SUB__->(@_) } sub SumArryRcs2 { @_ ? shift(@_) + __SUB__->(@_) : 0 } } cmpthese(-1, { iterative => sub { my $agg = 0; $agg += $_ for @array; $agg == $expect or die; }, recursive => sub { SumArryRcs(@array) == $expect or die }, recursive2 => sub { SumArryRcs2(@array) == $expect or die }, eval => sub { eval(join "+", @array) == $expect or die }, listutil => sub { sum(@array) == $expect or die }, });

The recursive approach is not a good solution, as I had to disable warnings on deep recursion and as the array gets longer it really blows up... only for short arrays does it outperform the eval version.

Replies are listed 'Best First'.
Re^2: Best way to sum an array?
by LanX (Saint) on May 24, 2017 at 18:14 UTC
    > as I had to disable warnings on deep recursion and as the array gets longer it really blows up...

    FWIW tailcall with goto &sub

    it's also 30% faster than normal recursion

    Rate recursive recursive2 recursive3 eval iterativ +e listutil recursive 184/s -- -4% -24% -46% -98 +% -100% recursive2 192/s 5% -- -20% -43% -98 +% -100% recursive3 240/s 31% 25% -- -29% -98 +% -100% eval 339/s 84% 76% 41% -- -97 +% -100% iterative 10240/s 5472% 5225% 4159% 2923% - +- -95% listutil 205922/s 111960% 106979% 85548% 60701% 1911 +% --

    I had a version which used $_[0] instead of aggregating in a closure, but it destroyed the aliased array and made the cmpthese() impossible.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

Re^2: Best way to sum an array?
by Anonymous Monk on May 24, 2017 at 15:55 UTC
    Nice. That module does the work in native compiled code, so of course it's fastest. I didn't know about that module. This is clearly best.
    #1053
    merci

      Then you should immediately familiarise yourself with it, and its sister module Scalar::Util. They are two of the most useful modules included in the Perl core.

      A module is almost always a good solution, if not the best, for any problem. This is especially true if you consider your own time as one of the resources you want to minimize.
      Bill
Re^2: Best way to sum an array?
by LanX (Saint) on May 25, 2017 at 14:21 UTC
    > The recursive approach is not a good solution, as I had to disable warnings on deep recursion and as the array gets longer it really blows up... only for short arrays does it outperform the eval version.

    The beauty of recursions come into play if you can split into several branches.

    Deep recursion becomes very unlikely and eval is outperformed.

    Perl Version: 5.016003 Array Length: 10000 Expected result: 50005000 Rate recursive recursive3 eval rec_split iterative + listutil recursive 7.44/s -- -19% -89% -91% -100% + -100% recursive3 9.16/s 23% -- -86% -89% -100% + -100% eval 67.6/s 808% 638% -- -19% -97% + -100% rec_split 83.8/s 1026% 815% 24% -- -96% + -100% iterative 2145/s 28722% 23322% 3073% 2461% -- + -94% listutil 36669/s 492642% 400327% 54142% 43678% 1610% + --

    Even that the total number of additions is still the same, this shows how sub-calls and copying arrays are braking in Perl.

    There is still room for more tuning:

    • don't copy arrays just indices
    • replace sub-calls with goto's/loop constructs and a result-stack
    • replace division by 2 with bit-shift

    But of course it's impossible to achieve the performance of the C version in this particular case!

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!