speedup help
Damien R. Sullivan
dasulliv@cs.indiana.edu
Tue, 4 Mar 2003 15:45:51 -0500
On Mon, Mar 03, 2003 at 08:46:22PM -0800, Mark P Jones wrote:
> pascal :: [[Integer]]
> pascal = iterate (\row -> zipWith (+) ([0] ++ row) (row ++ [0])) [1]
>
> comb :: Int -> Int -> Integer
> comb n m = pascal !! n !! m
> In that case, you can take further advantage of using Pascal's triangle
> by recognizing that numbers of the form (comb (n+1) i) are just the
> entries in the (n+1)th row. (All but the last two, for reasons I
> don't understand ... did you possibly want [0..n+1]?) So we get the
No, the sum for a Bernoulli number is a combination times another Bernoulli
number from 0 to n-1. Hard to have B_n depend on B_n. At least in a nice
recurrence...
> sumbn n = sum [ bernoulli i * fromIntegral c
> | (i,c) <- zip [0..n-1] (pascal!!(n+1)) ]
This code as is takes about 23 seconds, comparable to the 22 seconds of
factorial with array (hardcoded, since I can't get it dynamically in a pretty
fashion.) If I turned pascal into arrays it might be even faster. I'd have
to change something though, right, zipWith wouldn't work with arrays?
> Actually, I prefer the following version that introduces an explicit
> dot product operator:
>
> sumbn n = take n (map bernoulli [0..]) `dot` (pascal!!(n+1))
> dot xs ys = sum (zipWith (*) xs ys)
This needed some modification, since bernoulli returns Rationals, so I had
zipWith use a special mult function. It just took 25 seconds.
> slower, I thought these definitions were interesting and different
> enough to justify sharing ...
Hey, you're even faster too! At least for messing with comb.
Aaron Denney, to his credit, had a pretty similar idea a week ago, but I
didn't get what he was talking about then. Newbies like code they can paste
in. :)
Thanks!
-xx- Damien X-)