[Haskell-cafe] Re: Genuine Eratosthenes sieve [Was: Optimization
fun]
Melissa O'Neill
oneill at cs.hmc.edu
Mon Feb 19 21:51:54 EST 2007
apfelmus wrote:
> I think that the `mod`-algorithm counts as sieve, it just does a
> bad job at organizing the "crossing off".
I'd say that it might count as "a sieve", but *algorithmically* it is
not "The Sieve of Eratosthenes". If you abstract away the
algorithmic details to a mathematical essence, you can argue they're
the same, but I'd argue that the algorithmic details are what make
people want to use the Sieve of Eratosthenes in the first place.
Algorithmically, when you say "remove all the multiples of 17" it
really matters *how* you do it (c.f., an abstract mathematical
perspective, where we might not care). I'd argue that Eratosthenes
did say how to do it, and doing it a different way is misleading
enough that we should NOT call the resulting code "The Sieve of
Eratosthenes".
Yitzchak Gale:
> We did not cross out any number more than once. But we did consider
> each multiple of every prime, moving on if we found it already
> crossed off. My algorithm does exactly the same.
Actually it doesn't. Every composite gets handled by a stack of
deleteOrd filters, each one trying to remove multiples of one prime.
Whether you write
sieve (x:xs) = x : sieve (deleteOrd [x+x,x+x+x..] xs)
or
sieve (x:xs) = x : sieve (filter (\c -> c `mod` x > 0) xs)
you're essentially doing the same amount of work. Both ``deleteOrd [x
+x,x+x+x..]'' and ``filter (\c -> c `mod` x > 0)'' do exactly the
same job -- your version goes faster because it avoids division, but
that's all.
As I showed in my earlier post, with the worked example of removing
all the multiples of 17,
- Eratosthenes's sieve never says the equivalent of, "Hmm, I
wonder if 19 is a multiple of 17" -- but both the basic "sieve" we
began with and the deleteOrd version do
- Eratosthenes's sieve crosses-off/looks-at 459 (i.e., 17 * 27),
even though we crossed it off already when we crossed off multiples
of 3 -- whether you call that crossing it off a second time, or
merely stepping over it, it still needs to alight on 459 to get to
493 (17 * 29), which hasn't been crossed off yet
The first way of crossing off multiples of 17 is inefficient -- it
checks each composite against all the primes up to its smallest
factor. That is exactly what the classic naive primes algorithm
does. The second method is efficient -- it touches each composite
once for each unique factor it has.
Of course, the first is easy to implement as a one-liner and the
second isn't, but (sadly), that doesn't make the first way right and
the second way wrong.
Yitzchak Gale also wrote:
> It is true that I have never read Eritosthenes in the original, but
> my deleteOrd algorithm was meant to reproduce faithfully the sieve
> algorithm as I was taught it in grade school.
I don't know which version you learned in grade school. If you
learned it as a mathematical abstraction (e.g., as a way to define
what the primes are), you have faithfully reproduced that
abstraction. If you learned it as a technique for people to use to
efficiently produce lists of primes, you have *not* reproduced it,
because I'll bet in grade school you never checked 19 for
divisibility by 17.
The bait and switch occurs when people remember only the mathematical
abstraction and then look for elegant ways to recreate (only) that
abstraction. If you do that in a way that is fundamentally different
at an algorithmic level, it shouldn't come as a surprise when that
implementation doesn't run as efficiently as the original algorithm.
You also shouldn't be surprised when someone complains that you
haven't really implemented that original algorithm.
> A few days ago, I taught the sieve to my 6 year old daughter, the
> same way I learned it. She loved it!
Unless you broke out the set notation with your six year old, you
probably explained it operationally. Thus you explained the
algorithm, not a mathematical abstraction drawn from the algorithm.
As such I'm sure you taught her the real thing.
And if you want to teach her cool Haskell one-liners, the "sieve"
example that began this thread is delightfully brief. But don't
expect it to run quickly. And you'd be doing her a disservice and
propagating confusion if you tell her that it's algorithmically the
same as the genuine Sieve of Eratosthenes.
Melissa.
More information about the Haskell-Cafe
mailing list