On Tue, Dec 1, 2015 at 4:45 PM, Sven Van Caekenberghe <[email protected]> wrote: > I am all for a cleanup, the current situation is confusing. > The basic #sum should be fast AND work for empty collections with 0 as > starting element.
> I know why the #anyOne is used, and that use case should be preserved, but it > is less common IMHO. I'm curious to be learn why? cheers -ben > >> On 01 Dec 2015, at 09:38, Thierry Goubier <[email protected]> wrote: >> >> Hi Max, >> >> Interesting results... >> >> replacing the #yourself in newSum: cuts the runtime by a factor of two. >> using an [:x | x ] block cost 10% compared to a direct version of sum. >> >> So the fastest sum is: >> >> sum >> ^ self >> inject: >> (self ifEmpty: [ ^ 0 ] ifNotEmpty: [ self anyOne ]) >> into: [ :sum :each | sum + each ] >> >> And >> >> sum >> ^ self sum: [:x | x ] >> >> is 10% slower. >> >> And >> >> sum >> ^ self sum: #yourself >> >> is 100% slower (i.e. x2) >> >> It may be wise to avoid using #yourself for a block. >> >> Thierry >> >> >> 2015-12-01 9:17 GMT+01:00 Max Leske <[email protected]>: >> Hi guys, >> >> Collection defines #sum:, #detectSum: and #sumNumbers:, all of which >> accomplish the same (in principal) but with subtle differences: >> >> #sum: >> - uses #inject:into: with #anyOne as the injected element and will thus fail >> for empty collections >> >> #detectSum: >> - uses “nextValue + sum” instead of “sum + nextValue” which makes it a lot >> slower when dealing with large numbers (primitive fails and number >> conversion is necessary) >> >> #sumNumbers: >> - same as #sum but doesn’t fail for empty collections. Only good for numbers >> though. >> >> >> Benchmarks: >> >> [ 100 timesRepeat: [ (1 to: 1000000) sum: #yourself ] ] timeToRun 18062 >> [ 100 timesRepeat: [ (1 to: 1000000) detectSum: #yourself ] ] timeToRun 42391 >> [ 100 timesRepeat: [ (1 to: 1000000) sumNumbers: #yourself ] ] timeToRun >> 18096 >> >> >> >> Can we settle for a single implementation? Such as (modified from >> #sumNumbers:): >> >> newSum: aBlock >> ^ self >> inject: (self >> ifEmpty: [ 0 ] >> ifNotEmpty: [ self anyOne ]) >> into: [ :sum :each | sum + (aBlock value: each) ] >> >> This implementation combines the best of the three implementations I think. >> Benchmark: >> >> [ 100 timesRepeat: [ (1 to: 1000000) newSum: #yourself ] ] timeToRun 17955 >> >> >> BTW, there is also the message #sum, which suffers from the same problem as >> #sum: (the implementation is basically a copy). #sum could be implemented as >> >> sum >> ^ self sum: [ :x | x ] >> >> >> As for the name for the new method, I suggest #sum:. >> >> Cheers, >> Max >> > >
