2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,16 +1,19 @@
|
|||
The task is to write a generator of prime numbers, in order, that will automatically adjust to accommodate the generation of any reasonably high prime.
|
||||
;Task:
|
||||
Write a generator of prime numbers, in order, that will automatically adjust to accommodate the generation of any reasonably high prime.
|
||||
|
||||
The routine should demonstrably rely on either:
|
||||
# Being based on an open-ended counter set to count without upper limit other than system or programming language limits. In this case, explain where this counter is in the code.
|
||||
# Being based on a limit that is extended automatically. In this case, choose a small limit that ensures the limit will be passed when generating some of the values to be asked for below.
|
||||
# If other methods of creating an extensible prime generator are used, the algorithm's means of extensibility/lack of limits should be stated.
|
||||
|
||||
|
||||
The routine should be used to:
|
||||
* Show the first twenty primes.
|
||||
* Show the primes between 100 and 150.
|
||||
* Show the ''number'' of primes between 7,700 and 8,000.
|
||||
* Show the 10,000th prime.
|
||||
|
||||
<br>
|
||||
Show output on this page.
|
||||
|
||||
'''Note:''' You may reference code already on this site if it is written to be imported/included, then only the code necessary for import and the performance of this task need be shown. (It is also important to leave a forward link on the referenced tasks entry so that later editors know that the code is used for multiple tasks).
|
||||
|
|
@ -19,3 +22,4 @@ Show output on this page.
|
|||
|
||||
;See also:
|
||||
* The task is written so it may be useful in solving task [[Emirp primes]] as well as others (depending on its efficiency).
|
||||
<br><br>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
ns test-project-intellij.core
|
||||
(:gen-class)
|
||||
(:require [clojure.string :as string]))
|
||||
|
||||
(def primes
|
||||
" The following routine produces a infinite sequence of primes
|
||||
(i.e. can be infinite since the evaluation is lazy in that it
|
||||
only produces values as needed). The method is from clojure primes.clj library
|
||||
which produces primes based upon O'Neill's paper:
|
||||
'The Genuine Sieve of Eratosthenes'.
|
||||
|
||||
Produces primes based upon trial division on previously found primes up to
|
||||
(sqrt number), and uses 'wheel' to avoid
|
||||
testing numbers which are divisors of 2, 3, 5, or 7.
|
||||
A full explanation of the method is available at:
|
||||
[https://github.com/stuarthalloway/programming-clojure/pull/12] "
|
||||
|
||||
(concat
|
||||
[2 3 5 7]
|
||||
(lazy-seq
|
||||
(let [primes-from ; generates primes by only checking if primes
|
||||
; numbers which are not divisible by 2, 3, 5, or 7
|
||||
(fn primes-from [n [f & r]]
|
||||
(if (some #(zero? (rem n %))
|
||||
(take-while #(<= (* % %) n) primes))
|
||||
(recur (+ n f) r)
|
||||
(lazy-seq (cons n (primes-from (+ n f) r)))))
|
||||
|
||||
; wheel provides offsets from previous number to insure we are not landing on a divisor of 2, 3, 5, 7
|
||||
wheel (cycle [2 4 2 4 6 2 6 4 2 4 6 6 2 6 4 2
|
||||
6 4 6 8 4 2 4 2 4 8 6 4 6 2 4 6
|
||||
2 6 6 4 2 4 6 2 6 4 2 4 2 10 2 10])]
|
||||
(primes-from 11 wheel)))))
|
||||
|
||||
(defn between [lo hi]
|
||||
"Primes between lo and hi value "
|
||||
(->> (take-while #(<= % hi) primes)
|
||||
(filter #(>= % lo))
|
||||
))
|
||||
|
||||
(println "First twenty:" (take 20 primes))
|
||||
|
||||
(println "Between 100 and 150:" (between 100 150))
|
||||
|
||||
(println "Number between 7,7700 and 8,000:" (count (between 7700 8000)))
|
||||
|
||||
(println "10,000th prime:" (nth primes (dec 10000))) ; decrement by one since nth starts counting from 0
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
DO WHILE(F*F <= LST) !But, F*F might overflow the integer limit so instead,
|
||||
DO WHILE(F <= LST/F) !Except, LST might also overflow the integer limit, so
|
||||
DO WHILE(F <= (IST + 2*(SBITS - 1))/F) !Which becomes...
|
||||
DO WHILE(F <= IST/F + (MOD(IST,F) + 2*(SBITS - 1))/F) !Preserving the remainder from IST/F.
|
||||
|
|
@ -0,0 +1,382 @@
|
|||
MODULE PRIMEBAG !Need prime numbers? Plenty are available.
|
||||
C Creates and expands a disc file for a sieve of Eratoshenes, representing odd numbers only and starting with three.
|
||||
C Storage requirements: an array of N prime numbers in 16/32/64 bits vs. a bit array up to the 16/32/64 bit limit.
|
||||
C Word size N Prime N words in bits Bit array in bits.
|
||||
C 8 bit P(31) = 127 248 128
|
||||
C P(54) = 251 432 256
|
||||
C 16 bit P(3,512) = 32,749 56,192 32,768
|
||||
C P(6,542) = 65,521 104,672 65,536
|
||||
C 32 bit P(105,097,565) = 2,147,483,647 3,363,122,080 2,147,483,648
|
||||
C P(203,280,221) = 4,294,967,291 6,504,967,072 4,294,967,296
|
||||
C 64 bit 2.112E17 ? 1.352E19 9,223,372,036,854,775,808 ~ 9.22E18
|
||||
C from n/Ln(n) 4.158E17 ? 2.661E19 18,446,744,073,709,551,616 ~ 1.84E19
|
||||
INTEGER MSG !I/O unit number.
|
||||
INTEGER SSTASH !For attachment to my stash file.
|
||||
INTEGER SRECLEN,SCHARS,SBITS !Sizes.
|
||||
INTEGER SORG !Where the sieve starts. This must be three.
|
||||
INTEGER SLAST !Last record in my stash file.
|
||||
DATA SSTASH,SREC,SLAST/0,0,0/ !Prepared by PRIMEBAG.
|
||||
PARAMETER (SRECLEN = 1024) !4K disc bloc size, but RECL (in OPEN) is in terms of four-byte integers.
|
||||
PARAMETER (SCHARS = (SRECLEN - 1)*4) !Reserving space for one number at the start.
|
||||
PARAMETER (SBITS = SCHARS*8) !Known size of a character.
|
||||
PARAMETER (SORG = 3) !First odd number past two, which is not odd.
|
||||
CHARACTER*(*) SFILE !A name is needed.
|
||||
PARAMETER (SFILE = "C:/Nicky/RosettaCode/Primes/PrimeSieve.bit") !I don't have to count the characters.
|
||||
Components of a buffered record for the stash.
|
||||
INTEGER SREC !The record number.
|
||||
CHARACTER*1 C4(4) !The start of the record - a counter.
|
||||
CHARACTER*1 SCHAR(0:SCHARS - 1) !The majority of the record - a bit array, packed in 8-bit blobs...
|
||||
Collect some bit twiddling assistants for AND and OR, rather than bit shifting.
|
||||
CHARACTER*1 BITON(0:7),BITOFF(0:7) !Functions IBSET and IBCLR may not be available, and are little-endian anyway.
|
||||
PARAMETER (BITON =(/CHAR(2#10000000),CHAR(2#01000000), !128, 64, Reading strictly left-to-right.
|
||||
1 CHAR(2#00100000),CHAR(2#00010000), ! 32, 16, Uncompromising bigendery.
|
||||
1 CHAR(2#00001000),CHAR(2#00000100), ! 8, 4, Not just for bytes in words,
|
||||
3 CHAR(2#00000010),CHAR(2#00000001)/)) ! 2, 1. But also bits in bytes.
|
||||
PARAMETER (BITOFF=(/CHAR(2#01111111),CHAR(2#10111111), !127, 191, BITON + BITOFF = 255.
|
||||
2 CHAR(2#11011111),CHAR(2#11101111), !223, 239,
|
||||
1 CHAR(2#11110111),CHAR(2#11111011), !247, 251,
|
||||
3 CHAR(2#11111101),CHAR(2#11111110)/)) !253, 254.
|
||||
CONTAINS
|
||||
INTEGER FUNCTION I4UNPACK(C4) !Convert four successive characters into an integer.
|
||||
CHARACTER*1 C4(4) !The characters.
|
||||
I4UNPACK = ((ICHAR(C4(1))*256 + ICHAR(C4(2)))*256 !Convert the first four bytes
|
||||
1 + ICHAR(C4(3)))*256 + ICHAR(C4(4)) !To a four-byte integer.
|
||||
END FUNCTION I4UNPACK !Big-endian style, irrespective of cpu endianness.
|
||||
SUBROUTINE C4PACK(I4) !Convert an integer into successive bytes.
|
||||
Could return the result via a fancy function, but for now a global variable will do.
|
||||
INTEGER I4,N !The integer, and a copy to damage.
|
||||
INTEGER I !A stepper.
|
||||
N = I4 !Keep the original safe.
|
||||
DO I = 4,1,-1 !Know that four characters will do. Fixed format makes this easy.
|
||||
C4(I) = CHAR(MOD(N,256)) !Grab the low-order eight bits.
|
||||
N = N/256 !And shift right eight.
|
||||
END DO !Do it again.
|
||||
END SUBROUTINE C4PACK !Stored big-endianly, irrespective of cpu endianness.
|
||||
|
||||
LOGICAL FUNCTION GRASPPRIMEBAG(F)
|
||||
INTEGER F !The I/O unit number to use.
|
||||
LOGICAL EXIST !Use the keyword as a name
|
||||
INTEGER IOSTAT !And don't worry over assignment direction.
|
||||
CHARACTER*3 STYLE !One way or another.
|
||||
SSTASH = F !I shall use it.
|
||||
INQUIRE (FILE = SFILE,EXIST = EXIST) !Trouble with a missing "path" may arise.
|
||||
IF (EXIST) THEN !If the file exists,
|
||||
STYLE = "OLD" !I shall read it.
|
||||
ELSE !But if it doesn't,
|
||||
STYLE = "NEW" !I shall create it.
|
||||
END IF !Enough prevarication.
|
||||
OPEN(SSTASH,FILE = SFILE, STATUS = STYLE, !Go for the file.
|
||||
& ACCESS = "DIRECT", RECL = SRECLEN, FORM = "UNFORMATTED", !I have plans.
|
||||
& ERR = 666, IOSTAT = IOSTAT) !Which may be thwarted.
|
||||
IF (EXIST) THEN !If there is one...
|
||||
CALL READSCHAR(1) !The first record is also a header.
|
||||
SLAST = I4UNPACK(C4) !The number of records stored.
|
||||
ELSE !Otherwise, start from scratch.
|
||||
SLAST = 0 !No saved records.
|
||||
CALL PSURGE(SCHAR) !During preparation of the first batch of bits.
|
||||
END IF !All should now be in readiness.
|
||||
GRASPPRIMEBAG = .TRUE.!So, feel confidence.
|
||||
RETURN !And escape.
|
||||
666 WRITE (*,667) IOSTAT,SFILE !But, something may have gone wrong.
|
||||
667 FORMAT ("Pox! Error code ",I0, !A "hole" in the directory path?
|
||||
1 " when attempting to open file ",A) !Read-only access allowed when I want "update"?
|
||||
GRASPPRIMEBAG = .FALSE. !Whatever, it didn't work.
|
||||
END FUNCTION GRASPPRIMEBAG !So much for that.
|
||||
|
||||
SUBROUTINE READSCHAR(R) !Get record R into SCHAR, which may already hold it.
|
||||
INTEGER R !The record number desired.
|
||||
IF (R.EQ.SREC) RETURN !Perhaps it is already to hand.
|
||||
SREC = R !If not, move attention to it.
|
||||
READ (SSTASH,REC = SREC) C4,SCHAR !And read the record.
|
||||
END SUBROUTINE READSCHAR!Thus, I have a buffer too.
|
||||
|
||||
LOGICAL FUNCTION PSURGE(BIT8) !Add another record to the stash.
|
||||
C Surges forward into the next batch of primes, to be stored via a bit array in the file.
|
||||
C Each record starts with a count of the number of primes that have gone before.
|
||||
C Except that for the first record, this is the record counter for the stash file.
|
||||
C Except that when starting the second record, one is also the number of primes before SORG.
|
||||
CHARACTER*1 BIT8(0:SCHARS - 1) !Watch out! This may be SCHAR itself!
|
||||
INTEGER IST,LST !The numbers spanned by the surge.
|
||||
INTEGER F !A factor.
|
||||
INTEGER I !Another factor and a stepper.
|
||||
INTEGER C !Index for array BIT8.
|
||||
INTEGER NP !Number of primes.
|
||||
Carry forward the count of previous primes to start the following record..
|
||||
10 IF (SLAST.GT.0) THEN !Is there a previous record?
|
||||
CALL READSCHAR(SLAST) !Yes. Grab it. A good chance this is already in C4,SCHAR.
|
||||
NP = I4UNPACK(C4) !Its count of the primes accumulated before it.
|
||||
DO I = 0,SCHARS - 1 !Find out how namy primes it fingered by scanning its bits.
|
||||
NP = NP + COUNT(IAND(ICHAR(SCHAR(I)),ICHAR(BITON)).NE.0) !Whee! Eight at a go!
|
||||
END DO !On to the next byte.
|
||||
END IF !When creating a new record, its follower may not be sought in this run.
|
||||
Concoct the next batch of bits. Contorted calculations avoid integer overflow.
|
||||
20 BIT8 = CHAR(255) !All bits are aligned with numbers that might prove to be prime.
|
||||
IST = SORG + SLAST*(2*SBITS) !Bit(0) of BIT8(0) corresponds to IST.
|
||||
LST = IST + 2*(SBITS - 1) !Bit(last) to this number. Remember, only odd numbers have bits.
|
||||
IF (IST.LE.0) THEN !Humm. I'd better check.
|
||||
WRITE (MSG,21) SLAST,IST,LST !This works only with two's complement integers.
|
||||
21 FORMAT (/,"Integer overflow in the sieve of Eratosthenes!", !Oh dear.
|
||||
1 /,"Advancing from surge ",I0," to span ",I0," to ",I0) !These numbers will look odd.
|
||||
PSURGE = .FALSE. !But it is better than no indication of what went wrong.
|
||||
RETURN !Give in.
|
||||
END IF !Enough worrying.
|
||||
F = 3 !The first possible factor. Zapping will start at F²
|
||||
c DO WHILE(F.LE.LST/F) !If F² is past the end, so will be still larger F: enough.
|
||||
DO WHILE(F.LE.IST/F + (MOD(IST,F) + 2*(SBITS - 1))/F) !"Synthetic division" avoiding overflow.
|
||||
I = (IST - 1)/F + 1 !I want the first multiple of F in IST:LST. F may be a factor of IST.
|
||||
IF (MOD(I,2).EQ.0) I = I + 1!If even, advance to the next odd multiple. Even numbers are omitted by design.
|
||||
IF (I.LT.F) I = F !Less than F is superfluous: the position was zapped by earlier action.
|
||||
c I = (I*F - IST)/2 !Current bit positions are for IST, IST+2, IST+4, etc.
|
||||
I = ((I - IST/F)*F - MOD(IST,F))/2 !Avoids overflow when calculating the start value, I*F.
|
||||
DO I = I,SBITS - 1,F !Zap every F'th bit along. This is the sieve of Eratosthenes.
|
||||
C = I/8 !Eight bits per character.
|
||||
BIT8(C) = CHAR(IAND(ICHAR(BIT8(C)), !For F = 3 and 5, characters will be hit more than once.
|
||||
1 ICHAR(BITOFF(MOD(I,8))))) !Whack a bit. All the above just for this!
|
||||
END DO !On to the next bit.
|
||||
22 F = NEXTPRIME(F) !So much for F. Next, please.
|
||||
END DO !Are we there yet?
|
||||
Correct the count in the header, if this is an added record.
|
||||
30 IF (SLAST.GT.0) THEN !So, was there a pre-existing header record?
|
||||
CALL READSCHAR(1) !Yes. Get the header record into C4,SCHAR.
|
||||
CALL C4PACK(SLAST + 1) !This is the new record count.
|
||||
WRITE (SSTASH,REC = 1) C4,SCHAR !Write it all back.
|
||||
SCHAR = BIT8 !Ensure that SCHAR and SREC will be agreed.
|
||||
END IF !So much for the header's count.
|
||||
Cast the bits into the stash by writing record SLAST + 1..
|
||||
40 IF (SLAST.EQ.0) THEN !If we're writing the first record,
|
||||
CALL C4PACK(1) !Then this is the record count.
|
||||
ELSE !Otherwise,
|
||||
CALL C4PACK(NP) !Place the previous primes count.
|
||||
END IF !All this to help PRIME(i).
|
||||
SLAST = SLAST + 1 !This is now the last stashed record.
|
||||
WRITE (SSTASH,REC = SLAST) C4,BIT8 !I/O directly from the work area?
|
||||
SREC = SLAST !This is where BIT8 was written.
|
||||
PSURGE = .TRUE. !That assumes BIT8 is not SCHAR for SLAST > 1.
|
||||
END FUNCTION PSURGE !That was fun!
|
||||
|
||||
RECURSIVE SUBROUTINE GETSREC(R) !Make present the bit array belonging to record R.
|
||||
INTEGER R !The record number..
|
||||
CHARACTER*1 BIT8(0:SCHARS - 1) !A scratchpad. Others may be relying on SCHAR.
|
||||
IF (SLAST.LE.0) RETURN!DANGER! The first record is being initialised!
|
||||
DO WHILE(SLAST.LT.R) !If we haven't reached so far,
|
||||
IF (.NOT.PSURGE(BIT8)) THEN !Slog forwards one record's worth.
|
||||
WRITE (MSG,1) R !Or maybe not.
|
||||
1 FORMAT ("Cannot prepare surge ",I0) !Explain.
|
||||
STOP "No bits, no go." !And quit.
|
||||
END IF !And having prepared the next block of bits,
|
||||
END DO !Check afresh.
|
||||
CALL READSCHAR(R) !Read the desired record's bits.
|
||||
END SUBROUTINE GETSREC !Done.
|
||||
|
||||
INTEGER FUNCTION PRIME(N) !P(1) = 2, P(2) = 3, etc.
|
||||
C Calculate P(n) ~ n.ln(n)
|
||||
C ~ n{ln(n) + ln(ln(n)) - 1 + (ln(ln(n)) - 2)/ln(n) - [ln(ln(n))**2 - 6*log(log(n)) + 11]/[2*(ln(n))**2] + ....}
|
||||
C J.B.Rosser's 1938 Theorem: n[ln(n) + ln(ln(n)) - 1] < P(n) < n[ln(n) + ln(ln(n))]
|
||||
C or, with E = ln(n) + ln(ln(n)), n[E - 1] < P(n) < n[E]
|
||||
C Experimentation shows that the undershoot of the first two terms involves many records worth of bits.
|
||||
C Including additional terms does much better, but can overshoot.
|
||||
INTEGER N !The desired one.
|
||||
INTEGER R,NP !Counts.
|
||||
INTEGER B,C !Bit and character indices.
|
||||
DOUBLE PRECISION EST,LN,LLN !Hope, if not actuality.
|
||||
IF (N.LE.0) STOP "Primes are counted positively!" !Something must be wrong!
|
||||
IF (N.LE.1) THEN !The start of the bit array being preempted.
|
||||
PRIME = 2 !So, no array access.
|
||||
ELSE !Otherwise, the fun begins.
|
||||
LN = LOG(DFLOAT(N)) !Here we go.
|
||||
LLN = LOG(LN) !A popular term.
|
||||
EST = N*(LN !Estimate the value of the N'th prime.
|
||||
1 + LLN - 1 !Second term
|
||||
2 + (LLN - 2)/LN !Third term.
|
||||
3 - (LLN**2 - 6*LLN + 11)/(2*LN**2)) !Fourth term.
|
||||
R = (EST - SORG)/(2*SBITS) + 1 !Thereby selecting a record to scan.
|
||||
IF (R.LE.0) R = 1 !And not making a mess with N < 6 or so.
|
||||
9 CALL GETSREC(R) !Go for the record.
|
||||
IF (R.LE.1) THEN !The first record starts with the record count.
|
||||
NP = 1 !And I know how many primes precede its start point
|
||||
ELSE !While for all subsequent records,
|
||||
NP = I4UNPACK(C4) !This counts the number of primes that precede record R's start number.
|
||||
END IF !So now I'm ready to count onwards.
|
||||
IF (N.LE.NP) THEN !Maybe not.
|
||||
R = R - 1 !The estimate took me too far ahead.
|
||||
GO TO 9 !Try again.
|
||||
END IF !Could escalate to a binary search or even an interpolating search.
|
||||
Commence scanning the bits.
|
||||
C = 0 !Start with the first character of SREC..
|
||||
B = -1 !Syncopation. The formula is known to always under-estimate.
|
||||
10 IF (NP.LT.N) THEN !Are we there yet?
|
||||
11 B = B + 1 !No. Advance to the next bit.
|
||||
IF (B.GE.8) THEN !Overflowed a character yet?
|
||||
B = 0 !Yes. Start afresh at the first bit.
|
||||
C = C + 1 !And advance one character.
|
||||
IF (C.GE.SCHARS) THEN !Overflowed the record yet?
|
||||
C = 0 !Yes. Start afresh at its first character.
|
||||
R = R + 1 !And advance to the next record.
|
||||
CALL GETSREC(R) !Possibly, create it.
|
||||
END IF !So much for records.
|
||||
END IF !We're now ready to test bit B of character C of record R.
|
||||
IF (IAND(ICHAR(SCHAR(C)),ICHAR(BITON(B))).EQ.0) GO TO 11 !Not a prime. Search on.
|
||||
NP = NP + 1 !Count another prime.
|
||||
GO TO 10 !Pehaps this will be the one.
|
||||
END IF !So much for the search.
|
||||
PRIME = SORG + (R - 1)*(2*SBITS) + (C*8 + B)*2 !The corresponding number.
|
||||
IF (PRIME.LE.0) WRITE (MSG,666) N,PRIME !Or, possibly not.
|
||||
666 FORMAT ("Integer overflow! Prime(",I0,") gives ",I0,"!") !Let us hope the caller notices.
|
||||
END IF !So, all going well,
|
||||
END FUNCTION PRIME !It is found.
|
||||
|
||||
RECURSIVE INTEGER FUNCTION NEXTPRIME(N) !Keep right on to the end of the road.
|
||||
Can invoke GETSREC, which can invoke PSURGE, which ... invokes NEXTPRIME. Oh dear.
|
||||
INTEGER N !Not necessarily itself a prime number.
|
||||
INTEGER NN !A value to work with.
|
||||
INTEGER R !A record number into the stash.
|
||||
INTEGER I,IST !Number offsets.
|
||||
INTEGER C,B !Character and bit index.
|
||||
IF (N.LE.1) THEN !Suspicion prevails.
|
||||
NN = 2 !This is not represented in my bit array.
|
||||
ELSE !Otherwise, the fun begins.
|
||||
NN = N + 1 !Advance, with a copy I can mess with.
|
||||
IF (MOD(NN,2).EQ.0) NN = NN + 1 !Thus, NN is now odd.
|
||||
IF (NN.LE.0) GO TO 666 !But perhaps not proper, due to overflow.
|
||||
R = (NN - SORG)/(2*SBITS) !SORG is odd, so (NN - SORG) is even.
|
||||
CALL GETSREC(R + 1) !The first record is numbered one, not zero.
|
||||
IST = SORG + R*(2*SBITS) !The number for its first bit: even numbers are omitted..
|
||||
I = (NN - IST)/2 !Offset into the record. NN - IST is even.
|
||||
C = I/8 !Which character in SCHAR(0:SCHARS - 1)?
|
||||
B = MOD(I,8) !Which bit in SCHAR(C)?
|
||||
10 IF (IAND(ICHAR(SCHAR(C)),ICHAR(BITON(B))).EQ.0) THEN !On for a prime.
|
||||
NN = NN + 2 !Alas, it is off, so NN is not a prime. Perhaps this will be.
|
||||
B = B + 1 !Advance one bit. Each bit steps two.
|
||||
IF (B.GE.8) THEN !Past the end of the character?
|
||||
B = 0 !Yes. Back to bit zero.
|
||||
C = C + 1 !And advance one chracter.
|
||||
IF (C.GE.SCHARS) THEN !Past the end of the record?
|
||||
IF (NN.LE.0) GO TO 666!Yes. If NN has overflowed, the end of the rope is reached.
|
||||
C = 0 !Back to the start of a record.
|
||||
R = R + 1 !Advance one record.
|
||||
CALL GETSREC(R + 1) !And read it. (Count is from 1, not 0).
|
||||
END IF !So much for overflowing a record.
|
||||
END IF !So much for overflowing a character.
|
||||
GO TO 10 !Try again.
|
||||
END IF !So much for the bit array.
|
||||
END IF !If there had been a scan.
|
||||
NEXTPRIME = NN !The number for which the scan stopped.
|
||||
IF (NN.GT.0) RETURN !All is well.
|
||||
666 WRITE (MSG,667) N,NN !Or, maybe not. Careful: this won't appear if NEXTPRIME is invoked in a WRITE list.
|
||||
667 FORMAT ("Integer overflow! NextPrime(",I0,") gives ",I0,"!") !The recipient could do a two's complement.
|
||||
NEXTPRIME = NN !Prefer to return the bad value rather than fail to return anything.
|
||||
END FUNCTION NEXTPRIME !No divisions, no sieving. Here, anyway
|
||||
|
||||
INTEGER FUNCTION PREVIOUSPRIME(N) !If N is good, this can't overflow.
|
||||
INTEGER N !The number, not necessarily a prime.
|
||||
INTEGER NN !A value to mess with.
|
||||
INTEGER R !A record number.
|
||||
INTEGER I !Offset.
|
||||
INTEGER C,B !Character and bit fingers.
|
||||
IF (N.LE.3) THEN !Suppress annoyances.
|
||||
NN = 2 !This is now called the first prime, not one.
|
||||
ELSE !Otherwise, some work is to be done.
|
||||
NN = N - 1 !Step back one to ensure previousness.
|
||||
IF (MOD(NN,2).EQ.0) NN = NN - 1 !And here, oddness is a minimal requirement.
|
||||
R = (NN - SORG)/(2*SBITS) !Finger the record containing the bit for NN.
|
||||
CALL GETSREC(R + 1) !Record counting starts with one.
|
||||
I = (NN - (SORG + R*(2*SBITS)))/2 !Offset into that record.
|
||||
C = I/8 !Finger the character in SCHAR.
|
||||
B = MOD(I,8) !And the bit within the character.
|
||||
10 IF (IAND(ICHAR(SCHAR(C)),ICHAR(BITON(B))).EQ.0) THEN !On for a prime.
|
||||
NN = NN - 2 !Alas, it is off, so NN is not a prime. Perhaps this will be.
|
||||
B = B - 1 !Retreat one bit. Each bit steps two.
|
||||
IF (B.LT.0) THEN !Past the start of the character?
|
||||
B = 7 !Yes. Back to the last bit.
|
||||
C = C - 1 !And retreat one chracter.
|
||||
IF (C.LT.0) THEN !Past the start of the record?
|
||||
C = SCHARS - 1 !Yes. Back to the end of a record.
|
||||
R = R - 1 !Retreat one record.
|
||||
CALL GETSREC(R + 1) !And read it. (Count is from 1, not 0).
|
||||
END IF !So much for overflowing a record.
|
||||
END IF !So much for overflowing a character.
|
||||
GO TO 10 !Try again.
|
||||
END IF !So much for the bit array.
|
||||
END IF !Possibly, it was not needed.
|
||||
PREVIOUSPRIME = NN !There.
|
||||
END FUNCTION PREVIOUSPRIME !Doesn't overflow, either.
|
||||
|
||||
LOGICAL FUNCTION ISPRIME(N) !Could fool around explicity testing 2 and 3 and say 5,
|
||||
INTEGER N !But that means also checking that N > 2, N > 3, and N > 5.
|
||||
ISPRIME = N .EQ. NEXTPRIME(N - 1) !This is so much easier.
|
||||
END FUNCTION ISPRIME !No divisions up to SQRT(N) or the like either.
|
||||
END MODULE PRIMEBAG !Functions updating a disc file as a side effect...
|
||||
|
||||
PROGRAM POKE
|
||||
USE PRIMEBAG
|
||||
INTEGER I,P,N,N1,N2 !Assorted assistants.
|
||||
INTEGER ORDER !A collection of special values.
|
||||
PARAMETER (ORDER = 6) !For one, two, and four byte integers.
|
||||
INTEGER EDGE(ORDER) !Considered as two's complement and unsigned.
|
||||
PARAMETER (EDGE = (/31,54,3512,6542,105097565,203280221/)) !These primes are of interest.
|
||||
MSG = 6 !Standard output.
|
||||
|
||||
IF (.NOT.GRASPPRIMEBAG(66)) STOP "Gan't grab my file!" !Attempt in hope.
|
||||
|
||||
Case 1.
|
||||
C FORALL(I = 1:20) LIST(I) = PRIME(I) is rejected because function Prime(i) is rather impure.
|
||||
10 WRITE (MSG,11)
|
||||
11 FORMAT (19X,"First twenty primes: ", $)
|
||||
DO I = 1,20
|
||||
P = PRIME(I)
|
||||
WRITE (MSG,12) P
|
||||
12 FORMAT (I0,",",$)
|
||||
END DO
|
||||
|
||||
Case 2.
|
||||
20 WRITE (MSG,21)
|
||||
21 FORMAT (/,12X,"Primes between 100 and 150: ",$)
|
||||
P = 100
|
||||
22 P = NEXTPRIME(P) !While (P:=NextPrime(P)) <= 150 do Print P;
|
||||
IF (P.LE.150) THEN !But alas, no assignment within an expression.
|
||||
WRITE (MSG,23) P
|
||||
23 FORMAT (I0,",",$)
|
||||
GO TO 22
|
||||
END IF
|
||||
|
||||
Case 3.
|
||||
30 N1 = 7700 !Might as well parameterise this.
|
||||
N2 = 8000 !Rather than litter the source with explicit integers.
|
||||
N = 0
|
||||
P = N1
|
||||
31 P = NEXTPRIME(P)
|
||||
IF (P.LE.N2) THEN
|
||||
N = N + 1
|
||||
GO TO 31
|
||||
END IF
|
||||
WRITE (MSG,32) N1,N2,N
|
||||
32 FORMAT (/"Number of primes between ",I0," and ",I0,": ",I0)
|
||||
|
||||
Case 4.
|
||||
40 WRITE (MSG,41)
|
||||
41 FORMAT (/,"Tenfold steps...")
|
||||
N = 1
|
||||
DO I = 1,9 !This goes about as far as it can go.
|
||||
P = PRIME(N)
|
||||
WRITE (MSG,42) N,P
|
||||
42 FORMAT ("Prime(",I0,") = ",I0)
|
||||
N = N*10
|
||||
END DO
|
||||
|
||||
Cast forth some interesting values.
|
||||
100 WRITE (MSG,101)
|
||||
101 FORMAT (/,"Primes close to number sizes")
|
||||
DO N = 1,ORDER !Step through the list.
|
||||
N1 = EDGE(N) - 1 !Syncopation for the special value.
|
||||
DO I = 1,2 !I want the prime on either side.
|
||||
N1 = N1 + 1 !So, there are two successive primes to finger.
|
||||
WRITE (MSG,102) N1 !Identify the index.
|
||||
102 FORMAT ("Prime(",I0,") = ",$) !Piecemeal writing to the output,
|
||||
P = PRIME(N1) !As this may fling forth a complaint.
|
||||
WRITE (MSG,103) P !Show the value returned.
|
||||
103 FORMAT (I0,", ",$) !Which may be unexpected.
|
||||
END DO !On to the second.
|
||||
WRITE (MSG,*) !End the line after the second result.
|
||||
END DO !On to the next in the list.
|
||||
|
||||
END !Whee!
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
P = NEXTPRIME(100)
|
||||
DO WHILE (P.LE.150)
|
||||
...stuff...
|
||||
P = NEXTPRIME(P)
|
||||
END DO
|
||||
|
|
@ -0,0 +1 @@
|
|||
P:=100; WHILE (P:=NextPrime(P)) <= 150 DO stuff;
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
function primeGenerator(num, showPrimes) {
|
||||
var i,
|
||||
arr = [];
|
||||
|
||||
function isPrime(num) {
|
||||
// try primes <= 16
|
||||
if (num <= 16) return (
|
||||
num == 2 || num == 3 || num == 5 || num == 7 || num == 11 || num == 13
|
||||
);
|
||||
// cull multiples of 2, 3, 5 or 7
|
||||
if (num % 2 == 0 || num % 3 == 0 || num % 5 == 0 || num % 7 == 0)
|
||||
return false;
|
||||
// cull square numbers ending in 1, 3, 7 or 9
|
||||
for (var i = 10; i * i <= num; i += 10) {
|
||||
if (num % (i + 1) == 0) return false;
|
||||
if (num % (i + 3) == 0) return false;
|
||||
if (num % (i + 7) == 0) return false;
|
||||
if (num % (i + 9) == 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof num == "number") {
|
||||
for (i = 0; arr.length < num; i++) if (isPrime(i)) arr.push(i);
|
||||
// first x primes
|
||||
if (showPrimes) return arr;
|
||||
// xth prime
|
||||
else return arr.pop();
|
||||
}
|
||||
|
||||
if (Array.isArray(num)) {
|
||||
for (i = num[0]; i <= num[1]; i++) if (isPrime(i)) arr.push(i);
|
||||
// primes between x .. y
|
||||
if (showPrimes) return arr;
|
||||
// number of primes between x .. y
|
||||
else return arr.length;
|
||||
}
|
||||
// throw a default error if nothing returned yet
|
||||
// (surrogate for a quite long and detailed try-catch-block anywhere before)
|
||||
throw("Invalid arguments for primeGenerator()");
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// first 20 primes
|
||||
console.log(primeGenerator(20, true));
|
||||
|
||||
// primes between 100 and 150
|
||||
console.log(primeGenerator([100, 150], true));
|
||||
|
||||
// numbers of primes between 7700 and 8000
|
||||
console.log(primeGenerator([7700, 8000], false));
|
||||
|
||||
// the 10,000th prime
|
||||
console.log(primeGenerator(10000, false));
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Array [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 51, 59, 61, 67, 71 ]
|
||||
|
||||
Array [ 101, 103, 107, 109, 113, 127, 131, 137, 139, 149 ]
|
||||
|
||||
30
|
||||
|
||||
104729
|
||||
|
|
@ -1,46 +1,46 @@
|
|||
/*REXX program finds primes using an extendible prime number generator.*/
|
||||
parse arg f .; if f=='' then f=20 /*allow specifying # for 1 ──► F.*/
|
||||
call primes f; do j=1 for f; $=$ @.j; end
|
||||
say 'first' f 'primes are:' $
|
||||
/*REXX program calculates and displays primes using an extendible prime number generator*/
|
||||
parse arg f .; if f=='' then f=20 /*allow specifying number for 1 ──► F.*/
|
||||
call primes f; do j=1 for f; $=$ @.j; end /*j*/
|
||||
say 'first' f 'primes are:' $
|
||||
say
|
||||
call primes -150; do j=100 to 150; if !.j==0 then iterate; $=$ j; end
|
||||
say 'the primes between 100 to 150 (inclusive) are:' $
|
||||
call primes -150; do j=100 to 150; if !.j==0 then iterate; $=$ j; end /*j*/
|
||||
say 'the primes between 100 to 150 (inclusive) are:' $
|
||||
say
|
||||
call primes -8000; do j=7700 to 8000; if !.j==0 then iterate; $=$ j; end
|
||||
call primes -8000; do j=7700 to 8000; if !.j==0 then iterate; $=$ j; end /*j*/
|
||||
say 'the number of primes between 7700 and 8000 (inclusive) is:' words($)
|
||||
say
|
||||
call primes 10000
|
||||
say 'the 10000th prime is:' @.10000
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────PRIMES subroutine───────────────────*/
|
||||
primes: procedure expose !. s. @. $ #; parse arg H . 1 m .,,$; H=abs(H)
|
||||
if symbol('!.0')=='LIT' then /*1st time here? Initialize stuff*/
|
||||
do; !.=0; @.=0; s.=0 /*!.x=some prime; @.n=Nth prime.*/
|
||||
_=2 3 5 7 11 13 17 19 23 /*generate a bunch of low primes.*/
|
||||
do #=1 for words(_); p=word(_,#); @.#=p; !.p=1; end
|
||||
#=#-1; !.0=#; s.#=@.#**2 /*set # to be number of primes.*/
|
||||
end /* [↑] done with building low Ps*/
|
||||
neg= m<0 /*Neg? Request is for a P value.*/
|
||||
if neg then if H<=@.# then return /*Have a high enough P already?*/
|
||||
else nop /*used to match the above THEN. */
|
||||
else if H<=# then return /*Have a enough primes already ? */
|
||||
/*─────────────────────────────────────── [↓] gen more P's within range*/
|
||||
do j=@.#+2 by 2 /*find primes until have H Primes*/
|
||||
if j//3 ==0 then iterate /*is J divisible by three? */
|
||||
if right(j,1)==5 then iterate /*is the right-most digit a "5" ?*/
|
||||
if j//7 ==0 then iterate /*is J divisible by seven? */
|
||||
if j//11 ==0 then iterate /*is J divisible by eleven? */
|
||||
if j//13 ==0 then iterate /*is J divisible by thirteen? */
|
||||
if j//17 ==0 then iterate /*is J divisible by seventeen? */
|
||||
if j//19 ==0 then iterate /*is J divisible by nineteen? */
|
||||
/*[↑] above seven lines saves time*/
|
||||
do k=!.0 while s.k<=j /*divide by the known odd primes.*/
|
||||
if j//@.k==0 then iterate j /*Is J divisible by P? Not prime.*/
|
||||
end /*k*/ /* [↑] divide by odd primes √j.*/
|
||||
#=#+1 /*bump number of primes found. */
|
||||
@.#=j; s.#=j*j; !.j=1 /*assign to sparse array; prime².*/
|
||||
if neg then if H<=@.# then leave /*do we have a high enough prime?*/
|
||||
else nop /*used to match the above THEN. */
|
||||
else if H<=# then leave /*do we have enough primes yet? */
|
||||
end /*j*/ /* [↑] keep generating 'til nuff*/
|
||||
return /*return to invoker with more Ps.*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
primes: procedure expose !. s. @. $ #; parse arg H . 1 m .,,$; H=abs(H)
|
||||
if symbol('!.0')=='LIT' then /*1st time here? Then initialize stuff*/
|
||||
do; !.=0; @.=0; s.=0 /*!.x = some prime; @.n = Nth prime. */
|
||||
_=2 3 5 7 11 13 17 19 23 /*generate a bunch of low primes. */
|
||||
do #=1 for words(_); p=word(_,#); @.#=p; !.p=1; end
|
||||
#=#-1; !.0=#; s.#=@.#**2 /*set # to be the number of primes. */
|
||||
end /* [↑] done with building low primes? */
|
||||
neg= m<0 /*Negative? Request is for a P value.*/
|
||||
if neg then if H<=@.# then return /*do we have a high enough P already?*/
|
||||
else nop /*this is used to match the above THEN.*/
|
||||
else if H<=# then return /*do we have a enough primes already ? */
|
||||
/* [↓] gen more primes within range. */
|
||||
do j=@.#+2 by 2 /*find primes until have H Primes. */
|
||||
if j//3 ==0 then iterate /*is J divisible by three? */
|
||||
parse var j '' -1 _; if _==5 then iterate /*is the right-most digit a 5?*/
|
||||
if j//7 ==0 then iterate /*is J divisible by seven? */
|
||||
if j//11==0 then iterate /*is J divisible by eleven? */
|
||||
if j//13==0 then iterate /*is J divisible by thirteen? */
|
||||
if j//17==0 then iterate /*is J divisible by seventeen? */
|
||||
if j//19==0 then iterate /*is J divisible by nineteen? */
|
||||
/*[↑] above five lines saves time. */
|
||||
do k=!.0 while s.k<=j /*divide by the known odd primes. */
|
||||
if j//@.k==0 then iterate j /*Is J ÷ by a prime? ¬prime. ___*/
|
||||
end /*k*/ /* [↑] divide by odd primes up to √ j */
|
||||
#=#+1 /*bump the number of primes found. */
|
||||
@.#=j; s.#=j*j; !.j=1 /*assign to sparse array; prime²; P#.*/
|
||||
if neg then if H<=@.# then leave /*do we have a high enough prime? */
|
||||
else nop /*used to match the above THEN. */
|
||||
else if H<=# then leave /*do we have enough primes yet? */
|
||||
end /*j*/ /* [↑] keep generating until enough. */
|
||||
return /*return to invoker with more primes. */
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@ $ include "seed7_05.s7i";
|
|||
|
||||
const func boolean: isPrime (in integer: number) is func
|
||||
result
|
||||
var boolean: result is FALSE;
|
||||
var boolean: prime is FALSE;
|
||||
local
|
||||
var integer: count is 2;
|
||||
begin
|
||||
if number = 2 then
|
||||
result := TRUE;
|
||||
prime := TRUE;
|
||||
elsif number > 2 then
|
||||
while number rem count <> 0 and count * count <= number do
|
||||
incr(count);
|
||||
end while;
|
||||
result := number rem count <> 0;
|
||||
prime := number rem count <> 0;
|
||||
end if;
|
||||
end func;
|
||||
|
||||
|
|
@ -21,12 +21,12 @@ var integer: primeNum is 0;
|
|||
|
||||
const func integer: getPrime is func
|
||||
result
|
||||
var integer: prime is 0;
|
||||
var integer: nextPrime is 0;
|
||||
begin
|
||||
repeat
|
||||
incr(currentPrime);
|
||||
until isPrime(currentPrime);
|
||||
prime := currentPrime;
|
||||
nextPrime := currentPrime;
|
||||
incr(primeNum);
|
||||
end func;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue