Prime number module

D

Dag

Is there a python module that includes functions for working with prime
numbers? I mainly need A function that returns the Nth prime number and
that returns how many prime numbers are less than N, but a prime number
tester would also be nice. I'm dealing with numbers in the 10^6-10^8 range
so it would have to fairly efficient

Dag
 
A

Alex Martelli

Dag said:
Is there a python module that includes functions for working with prime
numbers? I mainly need A function that returns the Nth prime number and
that returns how many prime numbers are less than N, but a prime number
tester would also be nice. I'm dealing with numbers in the 10^6-10^8
range so it would have to fairly efficient

gmpy is pretty good for this sort of thing, but the primitives it gives
you are quite different -- is_prime to check if a number is prime, and
next_prime to get the smallest prime number larger than a given number.

You'd have to build your own caching on top of this to avoid repeating
computation if you need, e.g., "how many primes are < N" for several
different values of N; and I'm not even sure that gmpy's primitives are
optimal for this (compared with, for example, some kind of sieving).


Anyway, with all of these caveats, here's an example function:

import gmpy

def primes_upto(N):
count = 0
prime = gmpy.mpz(1)
while prime < N:
prime = prime.next_prime()
count += 1
return count

and having saved it in pri.py, here's what I measure in terms of time:

[alex@lancelot python2.3]$ python timeit.py -s 'import pri' -s 'M=1000*1000'
\
'pri.primes_upto(M)'
10 loops, best of 3: 2.76e+06 usec per loop
[alex@lancelot python2.3]$ python timeit.py -s 'import pri' -s
'M=2*1000*1000' 'pri.primes_upto(M)'
10 loops, best of 3: 4.03e+06 usec per loop

i.e., 2.76 seconds for primes up to 1,000,000 -- about 4 seconds
for primes up to 2,000,000. (This is on my good old trusty Athlon
Linux machine, about 30 months old now and not top-speed even when
new -- I'm sure one of today's typical PC's might take 2 or 3
times less than this, of course). If I was to use this kind of
computation "in production", I'd pre-compute the counts for some
typical N of interest and only generate and count primes in a
narrow band, I think; but it's hard to suggest anything without a
better idea of your application.


Alex
 
S

Stephen Horne

Is there a python module that includes functions for working with prime
numbers? I mainly need A function that returns the Nth prime number and
that returns how many prime numbers are less than N, but a prime number
tester would also be nice. I'm dealing with numbers in the 10^6-10^8 range
so it would have to fairly efficient

Dag

I just wrote a fairly simple sieve, which gave primes up to 1,000,000
in a few seconds (1.8GHz P4, Python code). There were 78498 primes in
that range (unless I screwed the code up, but it looked OK for smaller
ranges).

Going for 10^7 took too long for my patience, let alone 10^8, but at
least in theory there should be less than 100 times as many primes in
the range up to 10^8.

So here's the thought - a binary file containing a complete list of
primes up to 10^8 would require roughly 30MB (using 32 bit integers,
which should comfortably handle your requirement). Open in random
access and do a binary search to find a particular prime and the
position in the file should tell you how many primes are smaller than
that one.

30MB shouldn't be too prohibitive on todays machines, though if this
is to be distributed to other people there would of course be issues.
 
L

Lulu of the Lotus-Eaters

|I just wrote a fairly simple sieve, which gave primes up to 1,000,000
|in a few seconds (1.8GHz P4, Python code). There were 78498 primes in
|that range...at least in theory there should be less than 100 times as
|many primes in the range up to 10^8.

Quite a few less, actually. Under Gauss' Prime Number Theorem, an
approximation for the number of primes less than N is N/ln(N). I know
there have been some slight refinements in this estimate since 1792, but
in the ranges we're talking about, it's plenty good enough.

So I only expect around 5,428,681 primes less than 10^8 to occur. Well,
that's not SO much less than 7.8M.

|So here's the thought - a binary file containing a complete list of
|primes up to 10^8 would require roughly 30MB (using 32 bit integers,
|which should comfortably handle your requirement).

I wonder if such a data structure is really necessary. Certainly it
produces a class of answers quite quickly. I.e. search for a prime, and
its offset immediately gives you the number of primes less than it.
Heck, searching for any number, even a composite occurring between
primes, works pretty much the same way. Of course, the above
approximation gives you a close answer even quicker.

But if you are worried about disk storage, one easy shortcut is to store
a collection of 16-bit differences between successive primes. That's
half the size, and still lets you answer the desired question *pretty*
quickly (extra addition is required)... or at least generate a local
copy of Horne's data structure in one pass.

Moving farther, even this gap structure is quite compressible. Most
gaps are quite a bit smaller than 65536, so the highbits are zeros. In
fact, I am pretty sure that almost all the gaps are less than 256. So
an immediate compression strategy (saving disk space, costing time to
recreate the transparent structure) is to store gaps as 8-bit values,
with a x00 byte escaping into a larger value (I guess in the next two
bytes).

Maybe I'll try it, and see how small I can make the data... unless I do
my real work :).

Yours, Lulu...
 
E

Emile van Sebille

Lulu of the Lotus-Eaters said:
Moving farther, even this gap structure is quite compressible. Most
gaps are quite a bit smaller than 65536, so the highbits are zeros. In
fact, I am pretty sure that almost all the gaps are less than 256. So
an immediate compression strategy (saving disk space, costing time to
recreate the transparent structure) is to store gaps as 8-bit values,
with a x00 byte escaping into a larger value (I guess in the next two
bytes).

You can take this to 512 knowing that the gaps will always be an even
interval.

Emile
 
T

Tim Hochberg

Lulu said:
|I just wrote a fairly simple sieve, which gave primes up to 1,000,000
|in a few seconds (1.8GHz P4, Python code). There were 78498 primes in
|that range...at least in theory there should be less than 100 times as
|many primes in the range up to 10^8.

Quite a few less, actually. Under Gauss' Prime Number Theorem, an
approximation for the number of primes less than N is N/ln(N). I know
there have been some slight refinements in this estimate since 1792, but
in the ranges we're talking about, it's plenty good enough.

So I only expect around 5,428,681 primes less than 10^8 to occur. Well,
that's not SO much less than 7.8M.

|So here's the thought - a binary file containing a complete list of
|primes up to 10^8 would require roughly 30MB (using 32 bit integers,
|which should comfortably handle your requirement).

I wonder if such a data structure is really necessary. Certainly it
produces a class of answers quite quickly. I.e. search for a prime, and
its offset immediately gives you the number of primes less than it.
Heck, searching for any number, even a composite occurring between
primes, works pretty much the same way. Of course, the above
approximation gives you a close answer even quicker.

But if you are worried about disk storage, one easy shortcut is to store
a collection of 16-bit differences between successive primes. That's
half the size, and still lets you answer the desired question *pretty*
quickly (extra addition is required)... or at least generate a local
copy of Horne's data structure in one pass.

Moving farther, even this gap structure is quite compressible. Most
gaps are quite a bit smaller than 65536, so the highbits are zeros. In
fact, I am pretty sure that almost all the gaps are less than 256. So
an immediate compression strategy (saving disk space, costing time to
recreate the transparent structure) is to store gaps as 8-bit values,
with a x00 byte escaping into a larger value (I guess in the next two
bytes).

Maybe I'll try it, and see how small I can make the data... unless I do
my real work :).

I believe you could implement a hybrid scheme that would be quite fast
and still maintain nearly the same level of compression that you
describe above. In addition to the above compressed data, also store,
uncompressed, every Nth prime. A binary search will get you within N
primes of your answer, to find the exact value, recreate those N-primes.
For a N of, for instance, 64 the level of compression would be minimally
affected but should make finding the number of primes less than a given
number number much faster than the basic compressed scheme.

In fact I wouldn't be suprised if this was faster than the uncompressed
scheme since you're less likely to thrash your memory.

-tim
 
K

Klaus Alexander Seistrup

Lulu said:
So I only expect around 5,428,681 primes less than 10^8 to occur.
Well, that's not SO much less than 7.8M.

I found 5,761,455 primes < 1E8.


// Klaus

--
 
M

Miki Tebeka

Hello Dag,
Is there a python module that includes functions for working with prime
numbers? I mainly need A function that returns the Nth prime number and
that returns how many prime numbers are less than N, but a prime number
tester would also be nice. I'm dealing with numbers in the 10^6-10^8 range
so it would have to fairly efficient
Try gmpy (http://gmpy.sourceforge.net/)

HTH.
Miki
 
B

Bengt Richter

|I just wrote a fairly simple sieve, which gave primes up to 1,000,000
|in a few seconds (1.8GHz P4, Python code). There were 78498 primes in
|that range...at least in theory there should be less than 100 times as
|many primes in the range up to 10^8.

Quite a few less, actually. Under Gauss' Prime Number Theorem, an
approximation for the number of primes less than N is N/ln(N). I know
there have been some slight refinements in this estimate since 1792, but
in the ranges we're talking about, it's plenty good enough.

So I only expect around 5,428,681 primes less than 10^8 to occur. Well,
that's not SO much less than 7.8M.

|So here's the thought - a binary file containing a complete list of
|primes up to 10^8 would require roughly 30MB (using 32 bit integers,
|which should comfortably handle your requirement).
If the object is to be able to test primeness of an arbitrary candidate number
in range(10**8), I think I might just make a bit map of the 10**8 on disk,
which would only be 12.5
megabytes.

In fact, that's not that bad to hold in memory, but
you could calculate an exact sector to seek to and read and then you
can check the bit pretty fast. It might be interesting to make a timed
access map for sectors, to see what kinds of seek/read delays there are
on the average. But it would be hard/timeconsuming to reset/flush the OS
and controller cache states to get mechanical delay info. Perhaps it has
to be done at the BIOS level out of non-protected DOS or a disk mounted raw...

Anyway, getting to a known (file-relative) sector and only reading that sector
ought to be about as fast as you could get the info off the disk for an arbitrary
number, IWT.

Nth-prime and how-many-below-N would need some other representations.
I wonder if such a data structure is really necessary. Certainly it
produces a class of answers quite quickly. I.e. search for a prime, and
its offset immediately gives you the number of primes less than it.
Heck, searching for any number, even a composite occurring between
primes, works pretty much the same way. Of course, the above
approximation gives you a close answer even quicker.

But if you are worried about disk storage, one easy shortcut is to store
a collection of 16-bit differences between successive primes. That's
half the size, and still lets you answer the desired question *pretty*
quickly (extra addition is required)... or at least generate a local
copy of Horne's data structure in one pass.

Moving farther, even this gap structure is quite compressible. Most
gaps are quite a bit smaller than 65536, so the highbits are zeros. In
fact, I am pretty sure that almost all the gaps are less than 256. So
an immediate compression strategy (saving disk space, costing time to
recreate the transparent structure) is to store gaps as 8-bit values,
with a x00 byte escaping into a larger value (I guess in the next two
bytes).
I wouldn't be surprised if most of the gaps are less than 16...
I wonder what the largest gap between primes in range(10**8) is, and what
the distribution of gaps might be.
Maybe I'll try it, and see how small I can make the data... unless I do
my real work :).
Hm, the bit map stores the same information in another form, so if you
generate that, a zip compression of that ought to give an idea of how
small you are competing with.

You could translate the bit map to a sequence of prime counts for 8 or 16-bit
chunks with a simple 2*8 or 2**16 byte table mapping bytes or 16-bit chunks to
the counts of bits within them, then sum and only fiddle with one bit chunk to
make an nth-prime table...

The bit map ought to be pretty compressible, since all the bits at indices of a
multiple of 2, 3, 5, and 7 beyond the first byte should be zero, so even as bytes,
the alphabet ought to contain a lot less than 256 states.

Or you could pre-compress the bit map using a mask of redundant zeroes (beyond the
first chunk) generated from some smallish set of small primes like 2,3,5,7. Probably
hard to beat zip though.

Regards,
Bengt Richter
 
A

Alex Martelli

Tim Hochberg wrote:
...
I believe you could implement a hybrid scheme that would be quite fast
and still maintain nearly the same level of compression that you
describe above. In addition to the above compressed data, also store,
uncompressed, every Nth prime. A binary search will get you within N
primes of your answer, to find the exact value, recreate those N-primes.
For a N of, for instance, 64 the level of compression would be minimally
affected but should make finding the number of primes less than a given
number number much faster than the basic compressed scheme.

Still thinking of gmpy's primitives, I came up with a variant of this...:

import gmpy
import array
import bisect

highest_number_of_interest = gmpy.mpz(100*1000*1000)

def make_primes(put_them_here, every=1000):
current_prime = gmpy.mpz(put_them_here[-1])
count = 0
while current_prime < highest_number_of_interest:
current_prime = current_prime.next_prime()
count += 1
if count == every:
put_them_here.append(int(current_prime))
count = 0

try:
savefile = open('primes.dat', 'rb')
except:
every_1000th_prime = array.array('l', [1])
make_primes(every_1000th_prime)
savefile = open('primes.dat', 'wb')
every_1000th_prime.tofile(savefile)
savefile.close()
else:
every_1000th_prime = array.array('l', [])
try: every_1000th_prime.fromfile(savefile, 6000)
except EOFError: pass
else:
warnings.warn("Only %d primes (?)" % len(every_1000th_prime))
warnings.warn("Highest is %d" % every_1000th_prime[-1])
# could fill out and re-save the array here, if needed
savefile.close()

print "%d primes stored (1 every 1000), highest is %d" % (
len(every_1000th_prime), every_1000th_prime[-1])

def nth_prime(N):
N_div_1000, N_mod_1000 = divmod(N, 1000)
try: prime = every_1000th_prime[N_div_1000]
except IndexError:
raise ValueError, "must be N<%d" %
(1000*len(every_1000th_prime)+999)
prime = gmpy.mpz(prime)
for x in xrange(N_mod_1000):
prime = prime.next_prime()
return int(prime)

print "55555th prime is", nth_prime(55555)

import bisect
def primes_upto(N):
if N>highest_number_of_interest:
raise ValueError, "must be N<%d" % highest_number_of_interest
x = bisect.bisect_left(every_1000th_prime, N)
if N == every_1000th_prime[x]: return x*1000+1
prime = gmpy.mpz(every_1000th_prime[x-1])
x = (x-1)*1000
while prime < N:
x += 1
prime = prime.next_prime()
if prime == N: x += 1
return x

print "Up to 555555, there are %d primes" % primes_upto(555555)


The first run, building the file primes.dat (just 23048 bytes), took
almost 7 minutes elapsed time on my machine (250 CPU seconds). But
any successive run is extremely fast:

[alex@lancelot perex]$ time python -O prio.py
5762 primes stored (1 every 1000), highest is 99991609
55555th prime is 686671
Up to 555555, there are 45741 primes
0.06user 0.00system 0:00.14elapsed 41%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (494major+297minor)pagefaults 0swaps
[alex@lancelot perex]$

I've coded this rapidly and sloppily, so I wouldn't be surprised if
there were off-by-one errors here and there (needs to be checked against
some other, independent way to generate/check primes!), but I think the
fundamental ideas are sound.


Alex
 
L

Lulu of the Lotus-Eaters

|> > So I only expect around 5,428,681 primes less than 10^8 to occur.
|> > Well, that's not SO much less than 7.8M.

|Klaus Alexander Seistrup
|> I found 5,761,455 primes < 1E8.

|http://www.utm.edu/research/primes/howmany.shtml has the same number.
|(found by googling for "5,761,455" - 3rd hit. :)

Looking at Andrew's resource, I am reminded that N/(log(N)-1) is a
better approximation for "primes up to N" than was Gauss' original. Of
course, as I wrote, both are accurate at the asymptote. But infinity is
a long way to go.
5740303.8072846411

That looks assuringly closer to the specific total than my first pass.
Obviously, enumeration of all the primes in the range is still more
accurate than any such approximation formula (some further such
approximations can be found at the above URL, and elsewhere).

Yours, Lulu...
 
L

Lulu of the Lotus-Eaters

(e-mail address removed) (Bengt Richter) wrote previously:
|just make a bit map of the 10**8 on disk, which would only be
| >>> 10**8/8000000.
| 12.5
|megabytes.

I had been thinking about this also, but Bengt beat me to posting
something. I think that we could pick up Emile van Sebille's suggestion
about gaps only needing to store even numbers here; the equivalent being
that we only store a bit array of ODD numbers, getting us down to 6.25
mB of storage space (special casing of the prime '2' needs to be
handled, seems manageable :)).

Doing this does not necessarily produce a smaller storage format than a
zip'd bitmap of all the numbers. But the in-memory image doesn't
require a decompression step (and the stored version can still be
compressed). I guess the test is something like:

prime_bits = open('bitarray.primes','rb').read() # only odd nums
def isPrime(N):
if N < 2: return False
elif N==2: return True
else:
byte, bit = divmod(N, 16)
bit = bit//2
return ord(prime_bits[byte]) & 2**bit

You could also use a memory-mapped file or the like, of course.

|Nth-prime and how-many-below-N would need some other representations.
|You could translate the bit map to a sequence of prime counts for 8 or 16-bit
|chunks with a simple 2*8 or 2**16 byte table mapping bytes or 16-bit chunks to
|the counts of bits within them, then sum and only fiddle with one bit chunk to
|make an nth-prime table...

The ancillary data structure would indeed speed the "how-many-below"
calculation enormously, while not taking too much space.

Along those lines, what's the quickest way to count bits in Python?
Maybe someone has a clever idea... something that would run a whole
bunch faster than my bit mask style above for counting all the "1"s in a
multibyte string.

Yours, Lulu...
 
T

Tim Hochberg

Alex said:
Tim Hochberg wrote:
...



Still thinking of gmpy's primitives, I came up with a variant of this...:

[Nice compact version using gmpy snipped]

Just to keep my hand in, I'm attaching a version based on the idea above
which is in turn based on Emile's and Lulu's ideas for compression.

This produces data files that total just over 6 GB for all primes up to
1E8. The initial run is quite slow, but after that it can determine the
nth prime, or the number of primes below some number in about 0.5 ms on
my box.
The first run, building the file primes.dat (just 23048 bytes), took
almost 7 minutes elapsed time on my machine (250 CPU seconds). But
any successive run is extremely fast:

[alex@lancelot perex]$ time python -O prio.py
5762 primes stored (1 every 1000), highest is 99991609
55555th prime is 686671
Up to 555555, there are 45741 primes
0.06user 0.00system 0:00.14elapsed 41%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (494major+297minor)pagefaults 0swaps
[alex@lancelot perex]$

I've coded this rapidly and sloppily, so I wouldn't be surprised if
there were off-by-one errors here and there (needs to be checked against
some other, independent way to generate/check primes!), but I think the
fundamental ideas are sound.

Well one of us is off by one as I get 45740 primes below 55555. However,
I get 686671 as the 55555th prime, so we agree there. I would not be at
all suprised if it is mine that is off by one.

-tim


import array, bisect, psyco, struct

def eratosthenes(max=None):
'''Yields the sequence of prime numbers via the Sieve of Eratosthenes.'''
# Mostly based on Alex Marteli's version from the Python Cookbook. The max
# attribute, which I addded, trims the memory usage substantially when
# computing lots of primes. Of course you need to know your max prime in
# advance.
D = {} # map composite integers to primes witnessing their compositeness
q = 2 # first integer to test for primality
while (max is None) or (q <= max):
p = D.pop(q, None)
if p:
x = p + q
while x in D:
x += p
if (x is None) or (x <= max):
D[x] = p
else:
q2 = q*q
if (max is None) or (q2 <= max):
D[q2] = q
yield q
q += 1
psyco.bind(eratosthenes)


def encode(delta):
# To encode N-bytes, preface with (N-1) leading zero-bytes
enc = []
delta /= 2
while delta:
delta, byte = divmod(delta, 128)
enc.append(byte)
enc.reverse()
result = ['\0'] * (len(enc) - 1)
for byte in enc[:-1]:
result.append(chr(byte+1))
result.append(chr(enc[-1]))
return ''.join(result)


def decode(chars):
chars = chars.lstrip('\0')
bytes = []
for c in chars[:-1]:
bytes.append(ord(c)-1)
bytes.append(ord(chars[-1]))
value = bytes[0]
for b in bytes[1:]:
value *= 128
value += b
return 2 * value

def pop_delta(data):
# return delta, data_without_delta
index = 0
while data[index] == '\0':
index += 1
index = 2*index + 1
return decode(data[:index]), data[index:]

def encode_primes(n, chunk, basename):
primes = eratosthenes(n)
index_file = open(basename+'.index', 'wb')
everyn_file = open(basename+'.everyn', 'wb')
encoded_file = open(basename+'.encoded', 'wb')
index_file.write(struct.pack('l', chunk))
everyn_file.write(struct.pack('l', chunk))
# We reserve some space now and come back later and fill in the length
encoded_file.write(struct.pack('l', 0))
# We write to the files a chunk at a time.
encoded_chunk = ''
primes.next() # skip 2
p0 = primes.next()
index = 0
for i, p in enumerate(primes):
delta = p - p0
if not (i % chunk):
index += len(encoded_chunk)
index_file.write(struct.pack('l', index))
everyn_file.write(struct.pack('l', p0))
encoded_file.write(encoded_chunk)
encoded_chunk = ''
encoded_chunk += encode(delta)# This is supposed to be fast under psyco
p0 = p
# write leftover data
index += len(encoded_chunk)
index_file.write(struct.pack('l', index))
encoded_file.write(encoded_chunk)
encoded_file.seek(0)
encoded_file.write(struct.pack('l', i))
psyco.bind(encode_primes)


class Primes:
def __init__(self, basename):
sizel = struct.calcsize('l')
index_file = open(basename+'.index', 'rb')
[self.chunk] = struct.unpack('l', index_file.read(sizel))
index_data = index_file.read()
self.indices = struct.unpack("%sl" % (len(index_data) // sizel), index_data)
index_file.close()
everyn_file = open(basename+'.everyn', 'rb')
[chunk] = struct.unpack('l', everyn_file.read(sizel))
assert self.chunk == chunk, "inconsistent chunk sizes (%s vs %s)" % (self.chunk, chunk)
everyn_data = everyn_file.read()
self.everyn = struct.unpack("%sl" % (len(everyn_data) // sizel), everyn_data)
everyn_file.close()
encoded_file = open(basename+'.encoded', 'rb')
[self.nprimes] = struct.unpack('l', encoded_file.read(sizel))
self.encoded = encoded_file.read()

def __len__(self):
return self.nprimes

def __getitem__(self, n):
if n < 0:
n += self.nprimes
if not isinstance(n, int) and (0 <= n < self._len):
raise IndexError()
if n == 0:
return 2
cindex, pindex = divmod((n-1), self.chunk)
return self.decode_chunk(cindex)[pindex]

def decode_chunk(self, n):
cprimes = [self.everyn[n]]
data = self.encoded[self.indices[n]:self.indices[n+1]]
while data:
delta, data = pop_delta(data)
cprimes.append(cprimes[-1] + delta)
return cprimes

def upto(self, n):
if n < 2:
return 0
elif n < 3:
return 1
else:
n0 = max(bisect.bisect_right(self.everyn, n) - 1, 0)
chunk = self.decode_chunk(n0)
return bisect.bisect_right(chunk, n) + n0*self.chunk + 1


basename = "packedprimes"
try:
primes = Primes(basename)
except: # be more specific...
encode_primes(int(1e8), 64, basename)
primes = Primes(basename)

if __name__ == "__main__":

for n in 1, 2, 2.5, 3, 3.5, 5, 13, 13.5, 555555:
print "Up to", n, ", there are %d primes" % primes.upto(n)
print primes[55555-1]

import timeit
t = timeit.Timer("packedprimes.primes.upto(555555)", "import packedprimes")
print "seconds per call to upto =", t.timeit(number=1000) / 1000
t = timeit.Timer("packedprimes.primes[99834]", "import packedprimes")
print "seconds per call to [] =", t.timeit(number=1000) / 1000

#~ eprimes = eratosthenes(int(1e5))
#~ for i, p in enumerate(eprimes):
#~ assert p == primes, "mismatch at prime[%s] (%s vs %s)" % (i, p, primes)
#~ print "OK"
 
E

Emile van Sebille

Lulu of the Lotus-Eaters said:
Along those lines, what's the quickest way to count bits in Python?
Maybe someone has a clever idea... something that would run a whole
bunch faster than my bit mask style above for counting all the "1"s in a
multibyte string.

Probably far from the fastest, but in the tradition that you'll get a better
answer by posting, here's a stab at a python method for counting bits:

import string,time

nibbles = [(w+x+y+z, w*8+x*4+y*2+z)
for w in (0,1) for x in (0,1)
for y in (0,1) for z in (0,1)]


bitcounts = [
(chr(hinibblevalue*16 + lonibblevalue),
hibitcount+lobitcount)
for hibitcount, hinibblevalue in nibbles
for lobitcount, lonibblevalue in nibbles ]

bytes = dict(bitcounts)

xlater = "".join([chr(bitcount) for byte, bitcount in bitcounts])


def bitcount1(bytestr):
return sum([bytes[ii] for ii in bytestr])

def bitcount2(bytestr):
return sum(map(ord, string.translate(bytestr,xlater)))

t=time.time()
bitcount1('a'*100000)
print time.time()-t

t=time.time()
bitcount2('a'*100000)
print time.time()-t
 
L

Lulu of the Lotus-Eaters

Taking up Bengt's suggestion, and some various others, I created a bit
array version of the primality data structure. That is, each bit of the
file 'primes.bitarray' encodes the primality of the number corresponding
to its bit position. However, only ODD numbers are mentioned in this
file, since it's rather easy to rule out evens (and special case 2).
This produces a 6.25 mB file for the first 10**8 numbers.

I was disappointed that gzip only reduces the size by 41%. I would have
guessed better, given the predominance of 0 bits. Still, no reason not
to use the [gzip] module to read the data. You can download the data
file, if you wish, at:

http://gnosis.cx/download/primes.bitarray.gz

I decided to check how quickly I can check primality using this data
structure. Pretty well, to my mind (for reference, I have a PIII
733Mhz; nothing very fast for nowadays). Here's the code:

#!/usr/bin/python
import gzip

bit_source = gzip.open('primes.bitarray.gz')
prime_bits = bit_source.read(100000)

def isPrime(N):
"Check primality on pre-generated bit field (read more as needed)"
if N < 2: return False
elif N==2: return True
elif not N % 2: return False
else:
# Check if we need to extend prime_bits
global prime_bits
if 8*len(prime_bits) < N:
needed = 1+(N//8) - len(prime_bits)
prime_bits += bit_source.read(needed)
byte, bit = divmod(N, 16)
bit = 7 - bit//2
return ord(prime_bits[byte]) & 2**bit

if __name__=='__main__':
from time import clock
from random import randint
# generate a million numbers to check
tests = []
for _ in xrange(10**6):
tests.append(randint(1,10**8))
start = clock()
primes = 0
for n in tests:
if isPrime(n): primes += 1
print "%d primes in 1e6 numbers (%.2f secs)" % (primes,clock()-start)

Here's the timing:

% test_bits.py
57546 primes in 1e6 numbers (29.57 secs)

I figured there was no need to read the whole data file in unless a
check required it--I just read in a smallish 100k at initialization. Of
course, in the course of a million tests, I am pretty sure I wind up
reading in essentially the whole file at some point.

One nice thing to do would be to make 'bit_source' a bit smarter. I.e.
it could be a class that generated more primes when needed (maybe using
gmpy as Alex suggests). In principle, 'isPrime()' could then check
unbounded primes (subject to time and resource constraints).

The next thing would probably be to store sparce accumulations as Bengt
suggested (and Alex implemented in a different fashion). That is,
another structure could store "every 1000th prime" in order to answer
questions like "how-many-less-than" and "which-is-Nth-prime".

Maybe I'll Emile's bitcounting techniques to do this.

Yours, Lulu...

--
mertz@ | The specter of free information is haunting the `Net! All the
gnosis | powers of IP- and crypto-tyranny have entered into an unholy
..cx | alliance...ideas have nothing to lose but their chains. Unite
| against "intellectual property" and anti-privacy regimes!
-------------------------------------------------------------------------
 
A

Alex Martelli

Lulu of the Lotus-Eaters wrote:
...
Along those lines, what's the quickest way to count bits in Python?

Probably gmpy's popcount function.
Maybe someone has a clever idea... something that would run a whole
bunch faster than my bit mask style above for counting all the "1"s in a
multibyte string.

I would try gmpy.mpz(multibytestring, 256).popcount(). E.g.:
163

and, on my trusty 30-months-old Athlon box...:

[alex@lancelot python2.3]$ python timeit.py -s'import gmpy' \
-s'x="gmpy IS pretty fast for many kinds of things"' \
'gmpy.mpz(x,256).popcount()'
100000 loops, best of 3: 8.13 usec per loop
[alex@lancelot python2.3]$


Alex
 
L

Lulu of the Lotus-Eaters

|Lulu of the Lotus-Eaters wrote:
|> Along those lines, what's the quickest way to count bits in Python?

|Probably gmpy's popcount function.

What about fast AND portable?

(I'm sure gmpy can be installed lots of places, but not necessarily by
receivers of Python code).

Yours, Lulu...
 
S

Stephen Horne

If the object is to be able to test primeness of an arbitrary candidate number
in range(10**8), I think I might just make a bit map of the 10**8 on disk,
which would only be
12.5
megabytes.

If the object was simply to test primeness I would agree, but the
requirement included determining the number of primes below some given
value. It should be easy enough to fix, though - keep a cached count
for every n primes and only redo the count for the last few.


I think bitsets are the way to go for compression. The idea of only
storing every nth prime until you consider how you implement the seive
for the missing primes. You can't just check the interval - you need
to know the primes in earlier intervals to do the seive checks. You
may end up recalculating a lot of the smaller primes again.


It is not too difficult to count the bits in a single integer. One of
my favorite tricks exploits the fact that a single operation on an
integer can be seen as a parallel operation processing 32 or 64 bits
in one go.

Take an integer. Each bit can be considered a count of the number of
bits in that bit position. With a little bit of masking and shifting,
you can get a value where every pair of bits contains the number of
bits that were in that pair of bits in the original. In the 32 bit
case...

x = (x & 0x55555555) + ((x & 0xAAAAAAAA) >> 1)

Next, get the totals for each group of four bits...

x = (x & 0x33333333) + ((x & 0xCCCCCCCC) >> 2)

And so on, until the value contains a single total of the number of
bits in the whole original value.

x = (x & 0x0F0F0F0F) + ((x & 0xF0F0F0F0) >> 2)
x = (x & 0x00FF00FF) + ((x & 0xFF00FF00) >> 4)
x = (x & 0x0000FFFF) + ((x & 0xFFFF0000) >> 8)

A simple looping method would need 32 shifts, 32 bitwise ands and an
average of 16 increments. This takes 5 shifts, 10 bitwise ands and 5
additions. Probably a worthwhile gain.



LuLu points out that you can compress the bitset even further by
storing bits only for odd numbers. This compression can be extended by
looking at larger repeating patterns. For example, if we look at a
each value modulo 2*3 = 6, we can exclude multiples of both two and
three from the bitset.

0 1 2 3 4 5 - value % 6
* . * . * . - multiples of two
* . . * . . - multiples of three
* . * * * . - multiples of two or three

Basically, you only need to store bits where (value % 6) is one of the
values that gets a dot in the bottom line. Then to determine which bit
you need, you set up something like...

lookup = [None, 0, None, None, None, 1]

if lookup [value % 6] is None :
if (value == 2) or (value == 3) :
value is prime
else :
value is not prime
else
lookup_bit ((value / 3) + lookup [value % 6])

So you only need to hold one bit in three (those with value % 6 equal
to either 1 or 5) with both 2 and 3 being special-cased.

Use modulo 2*3*5 == 30 and I think the bitset reduces to 8/30 == just
under 27%, which tells me that along with a rapidly increasing
pattern-checking lookup table size you get rapidly decreasing returns.
No way am I going to work out the figures for modulo 2*3*5*7 = 210!

The modulo 6 case is certainly worthwhile, and maybe the module 30 if
you really need those extra few % points (which are still worth a
couple of MB at a guess), but I doubt it's worth going further than
that.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top