DNA.
wyrm-sieve
Version.
1.0.9
Namespace.
::wyrm
Command.
::wyrm::sieve
Language.
c
Manpage.
sieve (1WY)
Testbase.
Test Script
Test Report
Import.
Interface.
wyrm-io
wyrmwif
Package.
wyrmwif
Export.
Implementation.
wyrm-sieve.c
Interface.
wyrm-sieve.h
Package.
wyrmsieve.dylib

Modified Sieve of Eratosthenes

Sections.
Sieve of Eratosthenes
Test Base
Make.
Package.
compile -cc -ld -o [export package] [export implementation] -- -list [
  import interface] [export interface
]
Script.
rule clean :: {} "
  -rm $test/wyrm-sieve.TESTING
"
rule clobber :: {} "
  -rm $include/wyrm-sieve.h
  -rm $so/wyrmsieve[info sharedlibextension]
"
   
top

1 :: A variation of the sieve of Eratosthenes.

Copyright (C) 2004 SM Ryan

Wyrmwif Tcl extensions. For non-profit uses only, provided this copyright is preserved on all copies, this work may be freely copied, modified, redistributed, compiled, and incorporated in other works. This work is distributed with no warranty of any kind; no author or distributor accepts any responsibility for the consequences of using it, or for whether it serves any particular purpose or works at all, unless he or she says so in writing.

   
   

Sieve of Eratosthenes

   
top
2. sieve (1WY) ::

NAME

sieve — Compute successive prime numbers.

synopsis

wyrm::sieve [ number-of-primes ] [ -tmp folder ] [ -o channel ]

description

This computes prime numbers with a modified form of the Sieve of Eratosthenes: rather than a bit array of numbers and then skipping through every nth entry, it keeps a list of prime numbers up to the rth entry of the sieve and and how far r is from the last multiple of each seen prime.

The arithmetic requires just increment and decrement; it is computed on ASCII strings in decimal radix, limitted by the maximum string size rather than machine integer sizes. Also the sieve arrays are stored as files; the maximum number of primes is then determined by the file system capacity rather than memory size.

number-of-primes
Stop after computing this many primes and return the last one. If the temporary files are deleted, successive calls for larger number of primes restart from the previous computation.
-tmp folder
Store the temporary files in this folder. Default is the current folder. There are one or two files, A.sve and B.sve.
-o channel
Output primes, one per line, to this channel. Default is stdout. If channel is "none" the output is suppressed.
 
section    top

#ifndef WYRM_SIEVE_H
#define WYRM_SIEVE_H

	//	wyrm-sieve.dna - Copyright (C) 2004 wyrmwif@bigfoot.com.  All rights reserved.

	#include "wyrmwif.h"
	int Wyrmsieve_Init(Intr intr);
	int Wyrmsieve_SafeInit(Intr intr);

#endif

		
 
section    top

static const char COPYRIGHT[] = "wyrm-sieve.dna - Copyright (C) 2004 SM Ryan.  All rights reserved.";

#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "wyrm-sieve.h"
#include "wyrm-io.h"

static char *number(int n) {
	char b[50],*c;
	sprintf(b,"%d",n);
	c = nheap(strlen(b)+1,char);
	strcpy(c,b);
	return c;
}

static char *increment(char *n) {
	char *digit = n+strlen(n); int carry = 1;
	while (carry) {
		if (digit==n) {
			char *n1 = nheap(1+strlen(n)+1,char);
			*n1 = '1'; strcpy(n1+1,n);
			carry = 0;
			dispose(n); n = n1;
		}else if (*--digit=='9') {
			*digit = '0';
			carry = 1;
		}else {
			*digit += 1;
			carry = 0;
		}
	}
	return n;
}

static int decrement(Intr intr,char *n) {
	char *digit = n+strlen(n); int borrow = 1;
	int zero = 1;
	while (borrow) {
		if (digit==n) {
			rprintf(intr,"Attempted to decrement zero."); return TCL_ERROR;
		}else if (*--digit=='0') {
			*digit = '9';
			borrow = 1;
		}else {
			*digit -= 1;
			borrow = 0;
		}
	}
	while (*n && zero) zero = *n++=='0';
	return zero ? TCL_BREAK : TCL_CONTINUE;
}

static char *readline(Tcl_Channel A) {
	char *buffer = 0; int n = 0,m = 0,ch;
	for (;;) {
		int ch = cgetc(A);
		switch (ch) {
			case EOF: case ERR: if (buffer==0) return 0;
			case '\n': ch = 0;
		}
		if (n+1>=m) {m = 2*(n+1); buffer = reheap(m,char,buffer);}
		buffer[n++] = ch;
		if (!ch) break;
	}
	return buffer;
}

static void writeline(Tcl_Channel B,char *n) {
	cputs(B,n); cputc(B,'\n');
}

static int sieveStep(Intr intr,Tcl_Channel A,Tcl_Channel B) {
	int isprime = 1;
	while (1) {
		char *prime = readline(A);
		char *counter = readline(A);
		if (!prime) break;
		if (prime && !counter) return -1;
		writeline(B,prime);
		switch (decrement(intr,counter)) {
			case TCL_BREAK:
				writeline(B,prime);
				isprime = 0;
				break;
			case TCL_CONTINUE:
				writeline(B,counter);
				break;
			default:
				dispose(prime); dispose(counter);
				return TCL_ERROR;
		}
		dispose(prime); dispose(counter);
	}
	return isprime ? TCL_BREAK : TCL_CONTINUE;
}

static void addPrime(char *current,Tcl_Channel PR,Tcl_Channel B) {
	if (PR) writeline(PR,current);
	writeline(B,current);
	writeline(B,current);
}

static int sieveCommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
	chars limit = 0; bool restart = false; int rc;
	Tcl_Channel A = 0,B = 0,PR = chstdout;
	Obj tmp = 0;
	Obj Apath = incr(Tcl_NewStringObj("A.sve",-1));
	Obj Bpath = incr(Tcl_NewStringObj("B.sve",-1));
	chars current = 0;
	while (++P,--N>0) {
		chars p = Tcl_GetString(*P);
		if (isdigit(p[0])) {
			limit = p;
			limit = strcpy(nheap(strlen(limit)+1,char),limit);
		}else if (strbegins("-t",p) && N>0) {
			tmp = P[1]; P++,N--;
		}else if (strbegins("-o",p) && N>0) {
			chars pr = Tcl_GetString(P[1]); P++,N--;
			if (streq(pr,"none")) {
				PR = 0;
			}else {
				int mood; PR = Tcl_GetChannel(intr,pr,&mood);
				if (!PR) {
					rprintf(intr,"not a channel: %{y}s",pr);
					goto error;
				}
				if (!(TCL_WRITABLE&mood)) {
					rprintf(intr,"not a writable channel: %{y}s",pr);
					goto error;
				}
			}
		}else {
			rprintf(intr,"unrecognised option: %s",p);
			return TCL_ERROR;
		}
	}
	if (tmp) {
		Obj L,E[2];
		E[0] = tmp; E[1] = Apath; L = incr(Tcl_NewListObj(2,E)); decr(Apath);
		Apath = incr(Tcl_FSJoinPath(L,-1)); decr(L);
		E[0] = tmp; E[1] = Bpath; L = incr(Tcl_NewListObj(2,E)); decr(Bpath);
		Bpath = incr(Tcl_FSJoinPath(L,-1)); decr(L);
	}
	
	if (Tcl_FSAccess(Apath,0)<0 ||Tcl_FSAccess(Bpath,0)==0) {
		Tcl_FSRenameFile(Bpath,Apath);
	}
	A = Tcl_FSOpenFileChannel(intr,Apath,"r",0);
	if (A) {
		current = readline(A);
		if (current && limit) {
			chars t = strcpy(nheap(strlen(limit)+1,char),limit);
			current = increment(current);
			for (restart=true; restart; ) {
				char *prime = readline(A);
				char *counter = readline(A);
				if (!prime) break;
				dispose(prime);
				if (prime && !counter) restart = false;
				dispose(counter);
				switch (decrement(intr,t)) {
					case TCL_BREAK: restart = false;
					case TCL_CONTINUE: break;
					case TCL_ERROR: dispose(t);
					goto error;
				}
			}
			if (restart) {dispose(limit); limit = t;}
			else {dispose(t);}
		}else {
			restart = true;
		}
		if (!restart) dispose(current);
		Tcl_Close(intr,A); A = 0;
	}
	if (!restart) {
		Tcl_ResetResult(intr);
		A = Tcl_FSOpenFileChannel(intr,Apath,"w",0600);
		if (!A) {
			dispose(current); dispose(limit);
			return TCL_ERROR;
		}
		current = number(2);
		writeline(A,current);
		Tcl_Close(intr,A); A = 0;
	}
	while (1) {
		A = Tcl_FSOpenFileChannel(intr,Apath,"r",0); if (!A) goto error;
		B = Tcl_FSOpenFileChannel(intr,Bpath,"w",0600); if (!B) goto error;
		dispose(readline(A)); writeline(B,current);
		switch (sieveStep(intr,A,B)) {
			case TCL_BREAK:
				Tcl_SetResult(intr,current,TCL_VOLATILE);
				addPrime(current,PR,B);
				if (limit) {
					switch (decrement(intr,limit)) {
						case TCL_BREAK: goto okay;
						case TCL_ERROR: 
						goto error;
					}
				}
				break;
			case TCL_ERROR: 
			goto error;
		}
		current = increment(current);
		Tcl_Close(intr,A); A = 0;
		Tcl_Close(intr,B); B = 0;
		if (Tcl_FSDeleteFile(Apath)<0) {
			rprintf(intr,"failed to delete %{y}s",Apath);
			goto error;
		}
		if (Tcl_FSRenameFile(Bpath,Apath)<0) {
			rprintf(intr,"failed to rename %{y}s to %{y}s",Bpath,Apath);
			goto error;
		}
	}
okay:
	rc = TCL_OK;
exit:
	if (A) Tcl_Close(intr,A);
	if (B) Tcl_Close(intr,B);
	dispose(current); dispose(limit);
	decr(Apath); decr(Bpath);
	return rc;
error:
	rc = TCL_ERROR;
	goto exit;
}

int Wyrmsieve_Init(Intr intr) {
	Tcl_PkgProvide(intr,"wyrmsieve",VERSION);
	Tcl_PkgRequire(intr,"wyrmwif","1",0);
	Tcl_CreateObjCommand(intr,"::wyrm::sieve",sieveCommand,0,0);
	return Tcl_VarEval(intr,
			"namespace eval ::wyrm {namespace export sieve}\n",
			0);
}

int Wyrmsieve_SafeInit(Intr intr) {
	return rprintf(intr,"%!package not available in a safe interpretter",TCL_ERROR);
}

		
   
   

Test Base

   
top
    SIEVE Prime number sieve.
      SIEVE00
      Start and restart sieve.
        SIEVE01
        SIEVE02
      Cannot restart sieve.
        SIEVE03
        SIEVE04
      Command syntax.
        SIEVE10
        SIEVE11
        SIEVE12