And they chose one that wasn’t too optimized. There are much better versions of 
factorial already implemented in Smalltalk:

   
https://medium.com/concerning-pharo/speeding-up-factorial-computation-by-changing-the-order-of-multiplications-f4da3a5576da

   http://forum.world.st/Challenge-Tuning-the-large-factorial-td3588660.html

Both of these pages have optimizations that eliminate 80% or more of the 
running time where the optimized version below only eliminates ~25% of the slow 
factorial’s running time. On my machine, running the factorial for 200,000 
takes ~20 seconds using the old/slow algorithm (once I fixed it to be recursive 
on itself and not the modified factorial method), and the new factorial method 
takes ~15 seconds. Using the #productTo: method above, takes ~4 seconds, and 
using my revised version on the other page above takes ~3.5 seconds. My 
personal preference for a factorial included with Pharo would be the 
#productTo: method above. It is simple to understand and is reasonably fast.


John Brant



> On May 16, 2020, at 11:17 AM, Bernhard Höfner <[email protected]> wrote:
> 
> It seems that someone needed an optimized factorial-routine…
> The problem on the other hand is, that the machine friendly code is much less 
> „didactical" than the human friendly common implementation. To have both I 
> propose to add the human friendly clear and short version as comment. Its a 
> bit like some primitive methods were after the primitive call there is the 
> smalltalk version as well (VisualWorks).
> 
> Regards, Bernhard Höfner
> 
>> ...
>> The algos are different:
>>  
>> Pharo 8:
>> Integer>>factorial
>>                 "Answer the factorial of the receiver."
>>  
>>                 self = 0 ifTrue: [^ 1].
>>                 self > 0 ifTrue: [^ self * (self - 1) factorial].
>>                 self error: 'Not valid for negative integers'
>>  
>>  
>> Pharo 9:
>>  
>> Integer>>factorial
>> | nex nexnext acc |
>>                 "Guard for know cases (0,1,2,error)"
>>                 self < 3
>>                                 ifTrue: [ ^ self < 0
>>                                                                 ifTrue: [ 
>> self error: 'Not valid for negative integers' ]
>>                                                                 ifFalse: [ 
>> self > 0
>>                                                                              
>>                    ifTrue: [ self ]
>>                                                                              
>>                    ifFalse: [ 1 ] ] ].
>>                 acc := 2.
>>                 nex := 2.
>>                 nexnext := 10.
>>                 
>>                 self // 2 - 1
>>                                 timesRepeat: [ nex := nex + nexnext.
>>                                                 nexnext := nexnext + 8.
>>                                                 acc := acc * nex ].
>>                 self odd
>>                                 ifTrue: [ acc := acc * self ].
>>                 ^ acc
>>  
>>  ...


Reply via email to