Skip to content

Instantly share code, notes, and snippets.

@EricBurnett
Created March 3, 2010 03:21
Show Gist options
  • Save EricBurnett/320271 to your computer and use it in GitHub Desktop.
Save EricBurnett/320271 to your computer and use it in GitHub Desktop.
Evolution of an implementation of the Sieve of Eratosthenes
import math
from time import clock
# Calculates all the primes from 0 to stop_at using a sieve on an array.
def primes(stop_at):
if stop_at is None:
print("This algorithm doesn't support unbounded ranges")
return []
if stop_at <= 2: return []
# Candidates from 3 to stop_at-1, except only odd values.
length = (stop_at-1) // 2
s = [True] * length
root = int(math.sqrt(stop_at))
i = 0
p = 3
while p <= root:
if s[i]: # is p prime?
j = (p*p-3) // 2 # index of (p^2)
while j < length:
s[j]=False
j += p
i = i + 1
p = 2*i + 3
return [2]+[x*2+3 for x in range(length) if s[x]]
# Runs the function described by the string s, then prints out how long
# it took to run.
def time(s):
t = clock()
eval(s)
print(s + " took " + str(clock() - t))
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace PrimeGen
{
using NumType = Int64;
class PrimeGen {
static void Main(string[] args) {
NumType limit = 0;
if (args.Length < 1 || !NumType.TryParse(args[0], out limit)) {
Console.Error.WriteLine(
"Usage: " + System.AppDomain.CurrentDomain.FriendlyName +
" {limit}");
return;
}
Console.Out.WriteLine("Using limit of " + limit + ":");
Stopwatch sw = new Stopwatch();
sw.Start();
NumType sum = 0;
foreach (var i in GeneratePrimesArray(limit)) {
sum += i;
}
sw.Stop();
Console.Out.WriteLine("Array: ");
Console.Out.WriteLine("\tSum: " + sum);
Console.Out.WriteLine("\tTime elapsed: " + sw.Elapsed.ToString());
}
public static IEnumerable<NumType> GeneratePrimesArray(NumType limit) {
if (limit <= 2) yield break;
NumType length = (limit - 1) / 2;
BitArray s = new BitArray((int)length, true);
int root = (int)Math.Sqrt(limit);
int i = 0;
int p = 3;
yield return 2;
while (p <= root) {
if (s.Get(i)) {
yield return p;
int j = (p * p - 3) / 2;
while (j < length) {
s.Set(j, false);
j += p;
}
}
i += 1;
p = 2 * i + 3;
}
while (i < length) {
if (s.Get(i)) {
yield return p;
}
i += 1;
p = 2 * i + 3;
}
}
}
}
// Go implementation of a segmented Sieve of Eratosthenes. Much faster than the lazy
// evaluation variants above. Sieves first 10^12 primes in 1 hour (4 cores); 10^9
// candidates in the region of 10^18 takes about 2 minutes.
package main
import "flag"
import "fmt"
import "log"
import "math"
import "math/big"
import "time"
import "runtime"
var min_prime = flag.Int64("min", 0,
"Generate primes starting at this number.")
var max_prime = flag.Int64("max", 1000000,
"Generate primes up to and including this number.")
var processes = flag.Int("processes", 2, "Number of processes to use. "+
"Best depends on the processor itself and the other flags set.")
var sum_only = flag.Bool("sum_only", false, "Output only the sum to the main "+
"thread, not every individual prime.")
var vanilla = flag.Bool("vanilla", false,
"Skip the segmenting entirely and use one large array.")
// Fine tuning nobs; probably don't need to change these.
var segment_size = flag.Int64("segment_size", 0,
"Number of values in each segment to check.")
var segment_buffer = flag.Int("buffer", 0,
"Optional override for the size of channel buffers to use.")
var DEBUG = false
func main() {
flag.Parse()
if *max_prime < *min_prime {
log.Fatal("Max must be >= min.")
}
segment_min := int64(math.Sqrt(float64(*max_prime)))
if *segment_size == 0 {
*segment_size = segment_min * 2
} else if segment_min > *segment_size {
fmt.Printf("WARNING: Low segment size detected. Recommend setting "+
"--segment_size to at least %v (currently %v)\n",
segment_min, *segment_size)
}
if *sum_only {
size := big.NewInt(*segment_size)
max := big.NewInt(*max_prime)
size.Mul(size, max)
if size.Cmp(big.NewInt((1<<62)-1)) > 0 {
log.Fatalln("ERROR: Numbers too large for --sum_only to be safe.")
}
}
if *segment_buffer == 0 {
*segment_buffer = int(*segment_size / 20)
}
runtime.GOMAXPROCS(*processes)
t := time.Now()
Run(*min_prime, *max_prime)
fmt.Println("Took", time.Since(t))
}
func Run(min int64, max int64) {
// Schedule worker that fills a channel with segments
// Each segment does its work then fills a channel with the results
// Main thread then consumes segments; consumes primes from segment
primes := make(chan int64, *segment_buffer**processes)
go GenPrimes(min, max, primes)
sum := new(big.Int)
accumulator := int64(0)
for v := range primes {
if v > (1<<62)-1 {
AddInt(sum, v)
continue
}
if accumulator > (1<<62)-1 {
AddInt(sum, accumulator)
accumulator = 0
}
accumulator += v
}
AddInt(sum, accumulator)
fmt.Printf("Sum of primes from %v up to %v is %v\n", min, max, sum)
}
// Returns a slice of all primes in [3, max]. Uses a linear array, no segmenting.
func ArrayPrimes(max int64) []int64 {
if Even(max) {
max -= 1
}
primes := make([]int64, 0)
bits := NewBitArray(3, max)
for i := int64(3); i <= max; i += 2 {
if bits.Bit(i) == false {
// Prime!
primes = append(primes, i)
for next := i * i; next <= max; next += i * 2 {
bits.SetBit(next)
}
}
}
return primes
}
func GenPrimes(min int64, max int64, out chan<- int64) {
// Pre-calculate first sqrt(n) primes, for all the segments to reference.
var pre int64
if *vanilla {
pre = max
} else {
pre = int64(math.Sqrt(float64(max))) + 1
}
pre_primes := ArrayPrimes(pre)
if min <= 2 {
out <- 2
}
for _, v := range pre_primes {
if v >= min {
out <- v
}
}
segments := make(chan chan int64, *processes-1)
// Copy primes from the individual segments to 'out', closing it when every
// prime is in.
go func() {
start_time := time.Now()
last_time := start_time
num_segments := (max - min) / *segment_size
if num_segments == 0 {
num_segments = 1
}
done_segments := int64(0)
for s := range segments {
for v := range s {
out <- v
}
done_segments += 1
if time.Since(last_time) > time.Second*5 {
fmt.Printf("Elapsed %v Done segments %v/%v (%v%%)\n", time.Since(start_time),
done_segments, num_segments, 100.0*float64(done_segments)/float64(num_segments))
last_time = time.Now()
}
}
close(out)
}()
// Now setup the segments themselves for calculating the batches.
// Each outputs to its own channel, to keep ordering intact, although they may
// be processed in parallel.
next := pre + 1
if min > next {
next = min
}
for next <= max {
next_end := next + *segment_size
if max < next_end {
next_end = max
}
var c chan int64
if *sum_only {
c = make(chan int64, 1)
} else {
c = make(chan int64, *segment_buffer)
}
go GenSegment(next, next_end, pre_primes, c)
segments <- c
next = next_end + 1
}
close(segments)
}
// Generates primes in [min, max] and outputs them to out.
// 'primes' must contain all primes <= sqrt(max) (except 2).
func GenSegment(min int64, max int64, primes []int64, out chan<- int64) {
if Even(min) {
min += 1
}
if Even(max) {
max -= 1
}
bits := NewBitArray(min, max)
for _, p := range primes {
start := p * p
if start > max {
break
}
// Find first value that is a multiple of p, >= min, and odd.
if start < min {
start = min - (min % p)
if start < min {
start += p
}
if Even(start) {
start += p
}
}
for start <= max {
bits.SetBit(start)
start += 2 * p
}
}
// Output the primes remaining.
sum := int64(0)
sum_only := *sum_only
for i := min; i <= max; i += 2 {
if bits.Bit(i) == false {
sum += i
if !sum_only {
out <- i
}
}
}
if sum_only {
out <- sum
}
close(out)
}
func Even(num int64) bool {
return num&1 == 0
}
func AddInt(z *big.Int, x int64) {
x_big := big.NewInt(x)
z.Add(z, x_big)
}
// A structure for efficiently addressing odd bits. Similar performance to a
// bool array, except requires much less space.
type BitArray struct {
Min int64
Max int64
data []byte
}
func NewBitArray(min int64, max int64) *BitArray {
if Even(min) || Even(max) {
log.Fatalf("min and max must be odd; got (%v, %v)\n", min, max)
}
elements := ((max - min) / 2) + 1
data := make([]byte, (elements+7)>>3)
return &BitArray{min, max, data}
}
func (b *BitArray) Bit(index int64) bool {
if DEBUG && (index < b.Min || index > b.Max) {
log.Fatalf("Index out of bounds! %v outside [%v, %v]\n", index, b.Min, b.Max)
}
offset := (index - b.Min) / 2
offset_byte := offset >> 3
offset_bit := uint(offset & 0x7)
return b.data[offset_byte]&(1<<offset_bit) > 0
}
func (b *BitArray) SetBit(index int64) {
if DEBUG && (index < b.Min || index > b.Max) {
log.Fatalf("Index out of bounds! %v outside [%v, %v]\n", index, b.Min, b.Max)
}
offset := (index - b.Min) / 2
offset_byte := offset >> 3
offset_bit := uint(offset & 0x7)
b.data[offset_byte] |= 1 << offset_bit
}
import heapq
import itertools
from time import clock
# Returns an iterator for generating all primes < stop
def primes(stop=None):
class primeIterObject:
def __init__(self, p, it):
self.car = p*p
self.cdr = map(lambda x:x*p, it)
def next(self):
self.car = next(self.cdr)
def __eq__(self, other):
return self.car == other.car
def __ne__(self, other):
return self.car != other.car
def __lt__(self, other):
return self.car < other.car
def __gt__(self, other):
return self.car > other.car
def __le__(self, other):
return self.car <= other.car
def __ge__(self, other):
return self.car >= other.car
# Find all primes by iterating though the candidates and checking
# if each is a known composite (multiple of some prime). If not, build
# a composite iterator based on it and add it to the heap of iterators
# to check against.
# Based on http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf
heap = [] # Set of composite iterators, one for each prime
def incHeap(heap):
front = heap[0]
front.next()
heapq.heapreplace(heap, front)
def betterIterator(n):
cur = n
cycle = itertools.cycle([2, 4])
if (n+1) % 3 != 0:
next(cycle)
while True:
yield cur
cur += next(cycle)
itmaker = betterIterator
it = itmaker(5)
cur = next(it)
yield 2
heap.append(primeIterObject(2, itmaker(5)))
yield 3
heap.append(primeIterObject(3, itmaker(5)))
while stop is None or cur < stop:
while heap[0].car < cur:
incHeap(heap)
if heap[0].car == cur:
while heap[0].car == cur:
incHeap(heap)
else:
yield cur
if stop is None or cur*cur <= stop:
it2 = itmaker(cur)
next(it2)
heapq.heappush(heap, primeIterObject(cur, it2))
cur = next(it)
# Runs the function described by the string s, then prints out how long
# it took to run.
def time(s):
t = clock()
eval(s)
print(s + " took " + str(clock() - t))
import heapq
import itertools
from time import clock
# Returns an iterator for generating all primes < stop.
def primes(stop):
if stop is None:
print("This algorithm doesn't support unbounded ranges")
raise StopIteration
# Find all primes by iterating though the candidates and checking
# if each is a known composite (multiple of some prime). If not, build
# a composite iterator based on it and add it to the heap of iterators
# to check against.
# Based loosely on http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf.
md = {}
def addToMultiDict(d, key, value):
if key in d:
d[key].append(value)
else:
d[key] = [value]
# This iterator skips all multiples of 2 and 3
# Can apply an optional multiplier
def betterIterator(n, mult = 1):
cycle = itertools.cycle([2, 4])
if (n+1) % 3 != 0:
next(cycle)
while True:
yield n * mult
n += next(cycle)
itmaker = betterIterator
it = itmaker(5)
cur = next(it)
yield 2
yield 3
while cur < stop:
if cur in md:
allIters = md[cur]
del md[cur]
for i in allIters:
n = next(i)
addToMultiDict(md, n, i)
else:
yield cur
if stop is None or cur*cur < stop:
it2 = itmaker(cur, cur)
n = next(it2)
addToMultiDict(md, n, it2)
cur = next(it)
# Runs the function described by the string s, then prints out how long
# it took to run.
def time(s):
t = clock()
eval(s)
print(s + " took " + str(clock() - t))
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace PrimeGen
{
using NumType = Int64;
public class MultiDictionary<TKey, TVal> : Dictionary<TKey, List<TVal>> {
public void Add(TKey key, TVal val) {
List<TVal> container;
if (!this.TryGetValue(key, out container)) {
container = new List<TVal>();
base.Add(key, container);
}
container.Add(val);
}
}
class PrimeGen
{
static void Main(string[] args) {
NumType limit = 0;
if (args.Length < 1 || !NumType.TryParse(args[0], out limit)) {
Console.Error.WriteLine(
"Usage: " + System.AppDomain.CurrentDomain.FriendlyName +
" {limit}");
return;
}
Console.Out.WriteLine("Using limit of " + limit + ":");
Stopwatch sw = new Stopwatch();
sw.Start();
NumType sum = 0;
foreach (var i in GeneratePrimes(limit)) {
sum += i;
}
sw.Stop();
Console.Out.WriteLine("Sum: " + sum);
Console.Out.WriteLine("Time elapsed: " + sw.Elapsed.ToString());
}
// Returns candidate composites starting at first. If 'multiplier' is
// specified, all returned candidates are multiplied by 'multiplier'
// before being returned.
public static IEnumerator<NumType> Candidates(NumType first,
NumType multiplier = 1) {
NumType[] steps = {2, 4};
int nextStepIndex = 0;
if ((first + 1) % 3 != 0) {
nextStepIndex = 1;
}
while (true) {
yield return first * multiplier;
first += steps[nextStepIndex];
nextStepIndex = 1 - nextStepIndex;
}
}
// Returns a generator for prime numbers < limit
public static IEnumerable<NumType> GeneratePrimes(NumType limit) {
if (limit <= 2) yield break;
yield return 2;
if (limit == 3) yield break;
yield return 3;
var generators = new MultiDictionary<NumType, IEnumerator<NumType>>();
var it = Candidates(5);
it.MoveNext();
NumType cur = it.Current;
while (cur < limit) {
if (generators.ContainsKey(cur)) {
var all = generators[cur];
generators.Remove(cur);
foreach (var i in all) {
i.MoveNext();
var n = i.Current;
generators.Add(n, i);
}
} else {
yield return cur;
if (cur * cur < limit) {
var it2 = Candidates(cur, cur);
it2.MoveNext();
var n = it2.Current;
generators.Add(n, it2);
}
}
it.MoveNext();
cur = it.Current;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace PrimeGen
{
using NumType = Int64;
public class MultiDictionary<TKey, TVal> : Dictionary<TKey, SimpleContainer<TVal>> {
public void Add(TKey key, TVal val) {
SimpleContainer<TVal> container;
if (!this.TryGetValue(key, out container)) {
container = new SimpleContainer<TVal>();
base.Add(key, container);
}
container.Add(val);
}
}
public class SimpleContainer<T> {
T[] array;
int count;
public void Clear() {
count = 0;
}
public void Add(T value) {
if (array == null) {
array = new T[6];
}
if (count >= array.Length) {
Array.Resize(ref array, array.Length * 2);
}
array[count] = value;
count++;
}
public int Count {
get {
return count;
}
}
public T this[int index] {
get {
if (index < count) {
return array[index];
} else {
throw new ArgumentOutOfRangeException("index");
}
}
}
}
class PrimeGen
{
static void Main(string[] args) {
NumType limit = 0;
if (args.Length < 1 || !NumType.TryParse(args[0], out limit)) {
Console.Error.WriteLine(
"Usage: " + System.AppDomain.CurrentDomain.FriendlyName +
" {limit}");
return;
}
Console.Out.WriteLine("Using limit of " + limit + ":");
Stopwatch sw = new Stopwatch();
sw.Start();
NumType sum = 0;
foreach (var i in GeneratePrimes(limit)) {
sum += i;
}
sw.Stop();
Console.Out.WriteLine("Sum: " + sum);
Console.Out.WriteLine("Time elapsed: " + sw.Elapsed.ToString());
}
// Returns candidate composites starting at first. If 'multiplier' is
// specified, all returned candidates are multiplied by 'multiplier'
// before being returned.
public static IEnumerator<NumType> Candidates(NumType first,
NumType multiplier = 1) {
NumType[] steps = {2, 4};
int nextStepIndex = 0;
if ((first + 1) % 3 != 0) {
nextStepIndex = 1;
}
while (true) {
yield return first * multiplier;
first += steps[nextStepIndex];
nextStepIndex = 1 - nextStepIndex;
}
}
// Returns a generator for prime numbers < limit
public static IEnumerable<NumType> GeneratePrimes(NumType limit) {
if (limit <= 2) yield break;
yield return 2;
if (limit == 3) yield break;
yield return 3;
var generators = new MultiDictionary<NumType, IEnumerator<NumType>>();
var it = Candidates(5);
it.MoveNext();
NumType cur = it.Current;
while (cur < limit) {
if (generators.ContainsKey(cur)) {
var all = generators[cur];
generators.Remove(cur);
for (int i = 0; i < all.Count; ++i) {
all[i].MoveNext();
var n = all[i].Current;
generators.Add(n, all[i]);
}
} else {
yield return cur;
if (cur * cur < limit) {
var it2 = Candidates(cur, cur);
it2.MoveNext();
var n = it2.Current;
generators.Add(n, it2);
}
}
it.MoveNext();
cur = it.Current;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace PrimeGen
{
using NumType = Int64;
public struct SimpleContainer<T> {
T[] array;
int count;
public void Clear() {
count = 0;
}
public void Add(T value) {
if (array == null) {
array = new T[6];
}
if (count >= array.Length) {
Array.Resize(ref array, array.Length * 2);
}
array[count] = value;
count++;
}
public int Count {
get {
return count;
}
}
public T this[int index] {
get {
if (index < count) {
return array[index];
} else {
throw new ArgumentOutOfRangeException("index");
}
}
}
}
// This class represents a list of elements [firstIndex, firstIndex + size).
// When Increment is called, the available window shifts forward by one.
// Each element in the set can hold multiple values, and every element is
// initially guaranteed to be empty.
// It is tailored to only allow values not divisible by 2 or 3
public class MultiCyclicArray<T> {
private SimpleContainer<T>[] array;
private NumType firstIndex;
private NumType firstIndexCount;
private int offset;
public MultiCyclicArray(int arraySize, NumType firstIndex) {
// Approximate the number of elements in a window not
// divisible by 2 or 3.
arraySize = arraySize / 3 + 2;
this.array = new SimpleContainer<T>[arraySize];
for (int i = 0; i < arraySize; ++i) {
array[i] = new SimpleContainer<T>();
}
this.firstIndex = firstIndex;
firstIndexCount = firstIndex / 3 + 1;
this.offset = 0;
}
public SimpleContainer<T> this[NumType index] {
get {
return Get(index);
}
}
public SimpleContainer<T> Get(NumType index) {
return array[TranslateIndex(index)];
}
public void Add(NumType index, T value) {
array[TranslateIndex(index)].Add(value);
}
public void Clear(NumType index) {
array[TranslateIndex(index)].Clear();
}
// Takes an index from the user's perspective, and returns the raw array
// index it represents.
private int TranslateIndex(NumType emulatedIndex) {
Debug.Assert(emulatedIndex % 6 == 1 || emulatedIndex % 6 == 5);
NumType emulatedIndexCount = emulatedIndex / 3 + 1;
if (emulatedIndexCount < firstIndexCount ||
emulatedIndexCount >= firstIndexCount + array.Length) {
throw new ArgumentException("index outside of current window!");
}
return GetRawIndex((int) (emulatedIndexCount - firstIndexCount));
}
// Takes an index into the current window, and applies the offsetting
// to get an index into the base array.
private int GetRawIndex(int unoffsettedIndex) {
var index = unoffsettedIndex + offset;
if (index >= array.Length) {
index -= array.Length;
}
return index;
}
// Shifts the window right by num elements.
public void Increment(int num) {
if (num != 2 && num != 4) {
throw new ArgumentException("Only supports incrementing to next number not divisible by 2 or 3!",
"num");
}
array[offset].Clear();
firstIndex += num;
firstIndexCount += 1;
offset = offset + 1;
if (offset >= array.Length) {
offset -= array.Length;
}
}
}
class PrimeGen
{
static void Main(string[] args) {
NumType limit = 0;
if (args.Length < 1 || !NumType.TryParse(args[0], out limit)) {
Console.Error.WriteLine(
"Usage: " + System.AppDomain.CurrentDomain.FriendlyName +
" {limit}");
return;
}
Console.Out.WriteLine("Using limit of " + limit + ":");
Stopwatch sw = new Stopwatch();
sw.Start();
NumType sum = 0;
foreach (var i in GeneratePrimes(limit)) {
sum += i;
}
sw.Stop();
Console.Out.WriteLine("Sum: " + sum);
Console.Out.WriteLine("Time elapsed: " + sw.Elapsed.ToString());
}
// Returns candidate composites starting at first. If 'multiplier' is
// specified, all returned candidates are multiplied by 'multiplier'
// before being returned.
public static int MaxStep = 4;
public static IEnumerator<NumType> Candidates(NumType first,
NumType multiplier = 1) {
NumType[] steps = {2, 4};
int nextStepIndex = 0;
if ((first + 1) % 3 != 0) {
nextStepIndex = 1;
}
while (true) {
yield return first * multiplier;
first += steps[nextStepIndex];
nextStepIndex = 1 - nextStepIndex;
}
}
// Returns a generator for prime numbers < limit
public static IEnumerable<NumType> GeneratePrimes(NumType limit) {
if (limit <= 2) yield break;
yield return 2;
if (limit == 3) yield break;
yield return 3;
// Needs to support values up to the maximum prime (<= sqrt(limit)),
// which can be incremented MaxStep times to the next potential
// composite.
var generators = new MultiCyclicArray<IEnumerator<NumType>>(((int) Math.Sqrt(limit))*MaxStep + 1, 5);
var queuedGenerators = new Queue<IEnumerator<NumType>>();
var it = Candidates(5);
it.MoveNext();
NumType cur = it.Current;
while (cur < limit) {
var all = generators[cur];
var count = all.Count;
if (count > 0) {
for (int i = 0; i < count; ++i) {
var it2 = all[i];
it2.MoveNext();
var n = it2.Current;
generators.Add(n, it2);
}
} else {
yield return cur;
if (cur * cur < limit) {
var it2 = Candidates(cur, cur);
it2.MoveNext();
queuedGenerators.Enqueue(it2);
}
}
NumType old = cur;
it.MoveNext();
cur = it.Current;
generators.Increment((int) (cur - old));
if (queuedGenerators.Count > 0 &&
queuedGenerators.Peek().Current == cur) {
var it2 = queuedGenerators.Dequeue();
generators.Add(it2.Current, it2);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment