TerseMan challenge

Travis Griggs tgriggs at keyww.com
Wed Jan 12 00:07:27 UTC 2000


Andres Valloud wrote:

> Hi Travis.
>
> > Multiply instead of using raisedTo: if you can (on my system, I can
> > make it up to about 18 before using raisedTo: is actually faster
> > than consecutive multiplies).
>
> This is very interesting... does that mean that you could do muls à la
> Egypt?... like...
>
> k1 _ b. "b"
> k2 _ b*b. "b^2"
> k4 _ k2*k2. "b^4"
> k8 _ k4*k4. "b^8"
> k16 _ k8*k8. "b^16"
> k32 _ k16*k16. "b^32"
> k64 _ k32*k32. "b^64"
> k128 _ k64*k64. "b^128, 13 muls so far"
> result _ b*k2*k3*k4*k5*k6*k7*k8. "20 muls, b^255"
>
> This is 20 multiplications, but the result is b^255... there's even a
> faster way to mul a collection of numbers, and especially for
> factorials, the result is impressive. There's a class attached to this
> mail... what it does is to try to multiply numbers similar in size
> instead of doing 3* 2^1000, which is very inefficient in terms of the
> result obtained. Or, 64! * 65...
>
> I have found this class incredibly useful for my number crunching.

Andres,

I played around with this for a while and didn't get the same results. First of all baselined
the 10 factorial send. I was getting values (for 10000 iterations) of about 578 mills. Then I
ran your code:

CollectionProduct seqCollection: #(2 3 4 5 6 7 8 9 10)

To be fair I dropped the 1. It burnt 1328. Near as I can tell, the best you can do with a
collection sized by a power of 2 is to get rid of one multiply. By doing it with a recursive
normal method, you further burden with lots of message sends. So I thot I could speed it up by
doing the following:

#(2 3 4 5 6 7 8 9 10) inject: 1 into: [:accum :each | accum * each]

But that uses 1609 mills, and once I started digging I realized its doing about as much
messaging as your example, so I wasn't surprised that its about the same, a bit slower. So I
set out to reducing normal messages to come up with the following:

obj _ #(2 3 4 5 6 7 8 9 10).
product _ obj at: 1.
2 to: obj size do: [:i | product _ product * (obj at: i)]

Now we start seeing some speed. This gets us down to 375. From a speed perspective, it would
better to implement Integer>>factorial as such a loop (instead of the current recursive send),
from a readibility point, the recursive is kind of cool.

And finally, just to bring it back around to the advantages gained from just raw variable
multiplies, I benched

2 * 3 * 4 * 5 * 6 * 7 * 8 * 9

Note that this is hardcoded for this example, it cannot be an arbirtary collection of numbers.
This burns 110. Bottom line in this case. I think you're better off to implement the
following:

Array>>seriesProduct
    | product |
    product _ self at: 1.
    2 to: self size do: [:i | product _ product * (self at: i)].
    ^product

You can implement a more abstract version in collection using do: for completeness.

--
Travis Griggs (a.k.a. Lord of the Fries)
Member, Fravenic Skreiggser Software Collective
Key Technology
P-P-P-Penguin  Power!






More information about the Squeak-dev mailing list