Sieve of Eratosthenes: Difference between revisions
Content deleted Content added
Optimized version added |
GordonBGood (talk | contribs) m Sieve of Eratosthenes page fix highlighting... |
||
Line 33: | Line 33: | ||
{{trans|Python}} |
{{trans|Python}} |
||
< |
<syntaxhighlight lang=11l>F primes_upto(limit) |
||
V is_prime = [0B]*2 [+] [1B]*(limit - 1) |
V is_prime = [0B]*2 [+] [1B]*(limit - 1) |
||
L(n) 0 .< Int(limit ^ 0.5 + 1.5) |
L(n) 0 .< Int(limit ^ 0.5 + 1.5) |
||
Line 41: | Line 41: | ||
R enumerate(is_prime).filter((i, prime) -> prime).map((i, prime) -> i) |
R enumerate(is_prime).filter((i, prime) -> prime).map((i, prime) -> i) |
||
print(primes_upto(100))</ |
print(primes_upto(100))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 50: | Line 50: | ||
=={{header|360 Assembly}}== |
=={{header|360 Assembly}}== |
||
For maximum compatibility, this program uses only the basic instruction set. |
For maximum compatibility, this program uses only the basic instruction set. |
||
< |
<syntaxhighlight lang=360_Assembly>* Sieve of Eratosthenes |
||
ERATOST CSECT |
ERATOST CSECT |
||
USING ERATOST,R12 |
USING ERATOST,R12 |
||
Line 120: | Line 120: | ||
CRIBLE DC 100000X'01' |
CRIBLE DC 100000X'01' |
||
YREGS |
YREGS |
||
END ERATOST</ |
END ERATOST</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre style="height:20ex"> |
<pre style="height:20ex"> |
||
Line 168: | Line 168: | ||
=={{header|6502 Assembly}}== |
=={{header|6502 Assembly}}== |
||
If this subroutine is called with the value of <i>n</i> in the accumulator, it will store an array of the primes less than <i>n</i> beginning at address 1000 hex and return the number of primes it has found in the accumulator. |
If this subroutine is called with the value of <i>n</i> in the accumulator, it will store an array of the primes less than <i>n</i> beginning at address 1000 hex and return the number of primes it has found in the accumulator. |
||
< |
<syntaxhighlight lang=6502asm>ERATOS: STA $D0 ; value of n |
||
LDA #$00 |
LDA #$00 |
||
LDX #$00 |
LDX #$00 |
||
Line 206: | Line 206: | ||
JMP COPY |
JMP COPY |
||
COPIED: TYA ; how many found |
COPIED: TYA ; how many found |
||
RTS</ |
RTS</syntaxhighlight> |
||
=={{header|68000 Assembly}}== |
=={{header|68000 Assembly}}== |
||
Line 215: | Line 215: | ||
Some of the macro code is derived from the examples included with EASy68K. |
Some of the macro code is derived from the examples included with EASy68K. |
||
See 68000 "100 Doors" listing for additional information. |
See 68000 "100 Doors" listing for additional information. |
||
< |
<syntaxhighlight lang=68000devpac>*----------------------------------------------------------- |
||
* Title : BitSieve |
* Title : BitSieve |
||
* Written by : G. A. Tippery |
* Written by : G. A. Tippery |
||
Line 469: | Line 469: | ||
Summary2: DC.B ' prime numbers found.',CR,LF,$00 |
Summary2: DC.B ' prime numbers found.',CR,LF,$00 |
||
END START ; last line of source</ |
END START ; last line of source</syntaxhighlight> |
||
=={{header|8086 Assembly}}== |
=={{header|8086 Assembly}}== |
||
< |
<syntaxhighlight lang=asm>MAXPRM: equ 5000 ; Change this value for more primes |
||
cpu 8086 |
cpu 8086 |
||
bits 16 |
bits 16 |
||
Line 531: | Line 531: | ||
numbuf: db 13,10,'$' |
numbuf: db 13,10,'$' |
||
section .bss |
section .bss |
||
sieve: resb MAXPRM</ |
sieve: resb MAXPRM</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 548: | Line 548: | ||
=={{header|8th}}== |
=={{header|8th}}== |
||
< |
<syntaxhighlight lang=8th> |
||
with: n |
with: n |
||
Line 585: | Line 585: | ||
: sieve SED: n -- a |
: sieve SED: n -- a |
||
dup make-sieve swap sieve>a ; |
dup make-sieve swap sieve>a ; |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Out}} |
{{Out}} |
||
<pre> |
<pre> |
||
Line 598: | Line 598: | ||
=={{header|AArch64 Assembly}}== |
=={{header|AArch64 Assembly}}== |
||
{{works with|as|Raspberry Pi 3B version Buster 64 bits}} |
{{works with|as|Raspberry Pi 3B version Buster 64 bits}} |
||
< |
<syntaxhighlight lang=AArch64 Assembly> |
||
/* ARM assembly AARCH64 Raspberry PI 3B */ |
/* ARM assembly AARCH64 Raspberry PI 3B */ |
||
/* program cribleEras64.s */ |
/* program cribleEras64.s */ |
||
Line 688: | Line 688: | ||
/* for this file see task include a file in language AArch64 assembly */ |
/* for this file see task include a file in language AArch64 assembly */ |
||
.include "../includeARM64.inc" |
.include "../includeARM64.inc" |
||
</syntaxhighlight> |
|||
</lang> |
|||
<pre> |
<pre> |
||
Prime : 2 |
Prime : 2 |
||
Line 718: | Line 718: | ||
=={{header|ABAP}}== |
=={{header|ABAP}}== |
||
< |
<syntaxhighlight lang=Lisp> |
||
PARAMETERS: p_limit TYPE i OBLIGATORY DEFAULT 100. |
PARAMETERS: p_limit TYPE i OBLIGATORY DEFAULT 100. |
||
Line 760: | Line 760: | ||
ENDIF. |
ENDIF. |
||
ENDLOOP. |
ENDLOOP. |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|ACL2}}== |
=={{header|ACL2}}== |
||
< |
<syntaxhighlight lang=Lisp>(defun nats-to-from (n i) |
||
(declare (xargs :measure (nfix (- n i)))) |
(declare (xargs :measure (nfix (- n i)))) |
||
(if (zp (- n i)) |
(if (zp (- n i)) |
||
Line 792: | Line 792: | ||
(defun sieve (limit) |
(defun sieve (limit) |
||
(sieve-r 2 limit))</ |
(sieve-r 2 limit))</syntaxhighlight> |
||
=={{header|Action!}}== |
=={{header|Action!}}== |
||
< |
<syntaxhighlight lang=Action!>DEFINE MAX="1000" |
||
PROC Main() |
PROC Main() |
||
Line 825: | Line 825: | ||
i==+1 |
i==+1 |
||
OD |
OD |
||
RETURN</ |
RETURN</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Sieve_of_Eratosthenes.png Screenshot from Atari 8-bit computer] |
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Sieve_of_Eratosthenes.png Screenshot from Atari 8-bit computer] |
||
Line 841: | Line 841: | ||
=={{header|ActionScript}}== |
=={{header|ActionScript}}== |
||
Works with ActionScript 3.0 (this is utilizing the actions panel, not a separated class file) |
Works with ActionScript 3.0 (this is utilizing the actions panel, not a separated class file) |
||
< |
<syntaxhighlight lang=actionscript>function eratosthenes(limit:int):Array |
||
{ |
{ |
||
var primes:Array = new Array(); |
var primes:Array = new Array(); |
||
Line 864: | Line 864: | ||
} |
} |
||
var e:Array = eratosthenes(1000); |
var e:Array = eratosthenes(1000); |
||
trace(e);</ |
trace(e);</syntaxhighlight> |
||
Output: |
Output: |
||
{{out}} |
{{out}} |
||
Line 873: | Line 873: | ||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
< |
<syntaxhighlight lang=Ada>with Ada.Text_IO, Ada.Command_Line; |
||
procedure Eratos is |
procedure Eratos is |
||
Line 898: | Line 898: | ||
end if; |
end if; |
||
end loop; |
end loop; |
||
end Eratos;</ |
end Eratos;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 906: | Line 906: | ||
=={{header|Agda}}== |
=={{header|Agda}}== |
||
< |
<syntaxhighlight lang=agda> |
||
-- imports |
-- imports |
||
open import Data.Nat as ℕ using (ℕ; suc; zero; _+_; _∸_) |
open import Data.Nat as ℕ using (ℕ; suc; zero; _+_; _∸_) |
||
Line 953: | Line 953: | ||
remove _ ys zero = nothing ∷ ys i |
remove _ ys zero = nothing ∷ ys i |
||
remove y ys (suc j) = y ∷ ys j |
remove y ys (suc j) = y ∷ ys j |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Agena}}== |
=={{header|Agena}}== |
||
Tested with Agena 2.9.5 Win32 |
Tested with Agena 2.9.5 Win32 |
||
< |
<syntaxhighlight lang=agena># Sieve of Eratosthenes |
||
# generate and return a sequence containing the primes up to sieveSize |
# generate and return a sequence containing the primes up to sieveSize |
||
Line 988: | Line 988: | ||
# test the sieve proc |
# test the sieve proc |
||
for i in sieve( 100 ) do write( " ", i ) od; print();</ |
for i in sieve( 100 ) do write( " ", i ) od; print();</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,025: | Line 1,025: | ||
'''Works with:''' ALGOL 60 for OS/360 |
'''Works with:''' ALGOL 60 for OS/360 |
||
< |
<syntaxhighlight lang=algol60>'BEGIN' |
||
'INTEGER' 'ARRAY' CANDIDATES(/0..1000/); |
'INTEGER' 'ARRAY' CANDIDATES(/0..1000/); |
||
'INTEGER' I,J,K; |
'INTEGER' I,J,K; |
||
Line 1,064: | Line 1,064: | ||
'END' |
'END' |
||
'END' |
'END' |
||
'END'</ |
'END'</syntaxhighlight> |
||
=={{header|ALGOL 68}}== |
=={{header|ALGOL 68}}== |
||
< |
<syntaxhighlight lang=algol68>BOOL prime = TRUE, non prime = FALSE; |
||
PROC eratosthenes = (INT n)[]BOOL: |
PROC eratosthenes = (INT n)[]BOOL: |
||
( |
( |
||
Line 1,084: | Line 1,084: | ||
); |
); |
||
print((eratosthenes(80),new line))</ |
print((eratosthenes(80),new line))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,092: | Line 1,092: | ||
=={{header|ALGOL W}}== |
=={{header|ALGOL W}}== |
||
=== Standard, non-optimised sieve === |
=== Standard, non-optimised sieve === |
||
< |
<syntaxhighlight lang=algolw>begin |
||
% implements the sieve of Eratosthenes % |
% implements the sieve of Eratosthenes % |
||
Line 1,134: | Line 1,134: | ||
end |
end |
||
end.</ |
end.</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,143: | Line 1,143: | ||
Alternative version that only stores odd numbers greater than 1 in the sieve. |
Alternative version that only stores odd numbers greater than 1 in the sieve. |
||
< |
<syntaxhighlight lang=algolw>begin |
||
% implements the sieve of Eratosthenes % |
% implements the sieve of Eratosthenes % |
||
% only odd numbers appear in the sieve, which starts at 3 % |
% only odd numbers appear in the sieve, which starts at 3 % |
||
Line 1,175: | Line 1,175: | ||
for i := 1 until arrayMax do if s( i ) then writeon( ( i * 2 ) + 1 ); |
for i := 1 until arrayMax do if s( i ) then writeon( ( i * 2 ) + 1 ); |
||
end |
end |
||
end.</ |
end.</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Same as the standard version. |
Same as the standard version. |
||
=={{header|ALGOL-M}}== |
=={{header|ALGOL-M}}== |
||
< |
<syntaxhighlight lang=algol> |
||
BEGIN |
BEGIN |
||
Line 1,249: | Line 1,249: | ||
END |
END |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,274: | Line 1,274: | ||
=== Non-Optimized Version === |
=== Non-Optimized Version === |
||
< |
<syntaxhighlight lang=apl>sieve2←{ |
||
b←⍵⍴1 |
b←⍵⍴1 |
||
b[⍳2⌊⍵]←0 |
b[⍳2⌊⍵]←0 |
||
Line 1,283: | Line 1,283: | ||
} |
} |
||
primes2←{⍵/⍳⍴⍵}∘sieve2</ |
primes2←{⍵/⍳⍴⍵}∘sieve2</syntaxhighlight> |
||
The required list of prime divisors obtains by recursion (<tt>{⍵/⍳⍴⍵}∇⌈⍵*0.5</tt>). |
The required list of prime divisors obtains by recursion (<tt>{⍵/⍳⍴⍵}∇⌈⍵*0.5</tt>). |
||
Line 1,289: | Line 1,289: | ||
=== Optimized Version === |
=== Optimized Version === |
||
< |
<syntaxhighlight lang=apl>sieve←{ |
||
b←⍵⍴{∧⌿↑(×/⍵)⍴¨~⍵↑¨1}2 3 5 |
b←⍵⍴{∧⌿↑(×/⍵)⍴¨~⍵↑¨1}2 3 5 |
||
b[⍳6⌊⍵]←(6⌊⍵)⍴0 0 1 1 0 1 |
b[⍳6⌊⍵]←(6⌊⍵)⍴0 0 1 1 0 1 |
||
Line 1,298: | Line 1,298: | ||
} |
} |
||
primes←{⍵/⍳⍴⍵}∘sieve</ |
primes←{⍵/⍳⍴⍵}∘sieve</syntaxhighlight> |
||
The optimizations are as follows: |
The optimizations are as follows: |
||
Line 1,307: | Line 1,307: | ||
=== Examples === |
=== Examples === |
||
< |
<syntaxhighlight lang=apl> primes 100 |
||
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
||
Line 1,319: | Line 1,319: | ||
+/∘sieve¨ 10*⍳10 |
+/∘sieve¨ 10*⍳10 |
||
0 4 25 168 1229 9592 78498 664579 5761455 50847534</ |
0 4 25 168 1229 9592 78498 664579 5761455 50847534</syntaxhighlight> |
||
The last expression computes the number of primes < 1e0 1e1 ... 1e9. |
The last expression computes the number of primes < 1e0 1e1 ... 1e9. |
||
Line 1,326: | Line 1,326: | ||
=={{header|AppleScript}}== |
=={{header|AppleScript}}== |
||
< |
<syntaxhighlight lang=applescript>on sieveOfEratosthenes(limit) |
||
script o |
script o |
||
property numberList : {missing value} |
property numberList : {missing value} |
||
Line 1,345: | Line 1,345: | ||
end sieveOfEratosthenes |
end sieveOfEratosthenes |
||
sieveOfEratosthenes(1000)</ |
sieveOfEratosthenes(1000)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
< |
<syntaxhighlight lang=applescript>{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997}</syntaxhighlight> |
||
=={{header|ARM Assembly}}== |
=={{header|ARM Assembly}}== |
||
{{works with|as|Raspberry Pi}} |
{{works with|as|Raspberry Pi}} |
||
< |
<syntaxhighlight lang=ARM Assembly> |
||
/* ARM assembly Raspberry PI */ |
/* ARM assembly Raspberry PI */ |
||
Line 1,446: | Line 1,446: | ||
/***************************************************/ |
/***************************************************/ |
||
.include "../affichage.inc" |
.include "../affichage.inc" |
||
</syntaxhighlight> |
|||
</lang> |
|||
<pre> |
<pre> |
||
Prime : 2 |
Prime : 2 |
||
Line 1,477: | Line 1,477: | ||
=={{header|Arturo}}== |
=={{header|Arturo}}== |
||
< |
<syntaxhighlight lang=rebol>sieve: function [upto][ |
||
composites: array.of: inc upto false |
composites: array.of: inc upto false |
||
loop 2..to :integer sqrt upto 'x [ |
loop 2..to :integer sqrt upto 'x [ |
||
Line 1,493: | Line 1,493: | ||
] |
] |
||
print sieve 100</ |
print sieve 100</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,501: | Line 1,501: | ||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
{{AutoHotkey case}}Source: [http://www.autohotkey.com/forum/topic44657.html AutoHotkey forum] by Laszlo |
{{AutoHotkey case}}Source: [http://www.autohotkey.com/forum/topic44657.html AutoHotkey forum] by Laszlo |
||
< |
<syntaxhighlight lang=autohotkey>MsgBox % "12345678901234567890`n" Sieve(20) |
||
Sieve(n) { ; Sieve of Eratosthenes => string of 0|1 chars, 1 at position k: k is prime |
Sieve(n) { ; Sieve of Eratosthenes => string of 0|1 chars, 1 at position k: k is prime |
||
Line 1,516: | Line 1,516: | ||
} |
} |
||
Return S |
Return S |
||
}</ |
}</syntaxhighlight> |
||
===Alternative Version=== |
===Alternative Version=== |
||
< |
<syntaxhighlight lang=AutoHotkey>Sieve_of_Eratosthenes(n){ |
||
arr := [] |
arr := [] |
||
loop % n-1 |
loop % n-1 |
||
Line 1,533: | Line 1,533: | ||
} |
} |
||
return Arr |
return Arr |
||
}</ |
}</syntaxhighlight> |
||
Examples:< |
Examples:<syntaxhighlight lang=AutoHotkey>n := 101 |
||
Arr := Sieve_of_Eratosthenes(n) |
Arr := Sieve_of_Eratosthenes(n) |
||
loop, % n-1 |
loop, % n-1 |
||
output .= (Arr[A_Index] ? A_Index : ".") . (!Mod(A_Index, 10) ? "`n" : "`t") |
output .= (Arr[A_Index] ? A_Index : ".") . (!Mod(A_Index, 10) ? "`n" : "`t") |
||
MsgBox % output |
MsgBox % output |
||
return</ |
return</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>. 2 3 . 5 . 7 . . . |
<pre>. 2 3 . 5 . 7 . . . |
||
Line 1,553: | Line 1,553: | ||
=={{header|AutoIt}}== |
=={{header|AutoIt}}== |
||
< |
<syntaxhighlight lang=autoit>#include <Array.au3> |
||
$M = InputBox("Integer", "Enter biggest Integer") |
$M = InputBox("Integer", "Enter biggest Integer") |
||
Global $a[$M], $r[$M], $c = 1 |
Global $a[$M], $r[$M], $c = 1 |
||
Line 1,567: | Line 1,567: | ||
$r[0] = $c - 1 |
$r[0] = $c - 1 |
||
ReDim $r[$c] |
ReDim $r[$c] |
||
_ArrayDisplay($r)</ |
_ArrayDisplay($r)</syntaxhighlight> |
||
=={{header|AWK}}== |
=={{header|AWK}}== |
||
Line 1,592: | Line 1,592: | ||
input from commandline as well as stdin, |
input from commandline as well as stdin, |
||
and input is checked for valid numbers: |
and input is checked for valid numbers: |
||
< |
<syntaxhighlight lang=awk> |
||
# usage: gawk -v n=101 -f sieve.awk |
# usage: gawk -v n=101 -f sieve.awk |
||
Line 1,611: | Line 1,611: | ||
END { print "Bye!" } |
END { print "Bye!" } |
||
</syntaxhighlight> |
|||
</lang> |
|||
Here is an alternate version that uses an associative array to record composites with a prime dividing it. It can be considered a slow version, as it does not cross out composites until needed. This version assumes enough memory to hold all primes up to ULIMIT. It prints out noncomposites greater than 1. |
Here is an alternate version that uses an associative array to record composites with a prime dividing it. It can be considered a slow version, as it does not cross out composites until needed. This version assumes enough memory to hold all primes up to ULIMIT. It prints out noncomposites greater than 1. |
||
< |
<syntaxhighlight lang=awk> |
||
BEGIN { ULIMIT=100 |
BEGIN { ULIMIT=100 |
||
Line 1,626: | Line 1,626: | ||
else print ( S[(n+n)] = n ) |
else print ( S[(n+n)] = n ) |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
==Bash== |
==Bash== |
||
Line 1,634: | Line 1,634: | ||
{{works with|FreeBASIC}} |
{{works with|FreeBASIC}} |
||
{{works with|RapidQ}} |
{{works with|RapidQ}} |
||
< |
<syntaxhighlight lang=freebasic>DIM n AS Integer, k AS Integer, limit AS Integer |
||
INPUT "Enter number to search to: "; limit |
INPUT "Enter number to search to: "; limit |
||
Line 1,650: | Line 1,650: | ||
FOR n = 2 TO limit |
FOR n = 2 TO limit |
||
IF flags(n) = 0 THEN PRINT n; ", "; |
IF flags(n) = 0 THEN PRINT n; ", "; |
||
NEXT n</ |
NEXT n</syntaxhighlight> |
||
==={{header|Applesoft BASIC}}=== |
==={{header|Applesoft BASIC}}=== |
||
< |
<syntaxhighlight lang=basic>10 INPUT "ENTER NUMBER TO SEARCH TO: ";LIMIT |
||
20 DIM FLAGS(LIMIT) |
20 DIM FLAGS(LIMIT) |
||
30 FOR N = 2 TO SQR (LIMIT) |
30 FOR N = 2 TO SQR (LIMIT) |
||
Line 1,664: | Line 1,664: | ||
100 FOR N = 2 TO LIMIT |
100 FOR N = 2 TO LIMIT |
||
110 IF FLAGS(N) = 0 THEN PRINT N;", "; |
110 IF FLAGS(N) = 0 THEN PRINT N;", "; |
||
120 NEXT N</ |
120 NEXT N</syntaxhighlight> |
||
==={{header|Atari BASIC}}=== |
==={{header|Atari BASIC}}=== |
||
{{trans|Commodore BASIC}} |
{{trans|Commodore BASIC}} |
||
Auto-initialization of arrays is not reliable, so we have to do our own. Also, PRINTing with commas doesn't quite format as nicely as one might hope, so we do a little extra work to keep the columns lined up. |
Auto-initialization of arrays is not reliable, so we have to do our own. Also, PRINTing with commas doesn't quite format as nicely as one might hope, so we do a little extra work to keep the columns lined up. |
||
< |
<syntaxhighlight lang=basic>100 REM SIEVE OF ERATOSTHENES |
||
110 PRINT "LIMIT";:INPUT LI |
110 PRINT "LIMIT";:INPUT LI |
||
120 DIM N(LI):FOR I=0 TO LI:N(I)=1:NEXT I |
120 DIM N(LI):FOR I=0 TO LI:N(I)=1:NEXT I |
||
Line 1,686: | Line 1,686: | ||
250 IF C=3 THEN PRINT:C=0 |
250 IF C=3 THEN PRINT:C=0 |
||
260 NEXT I |
260 NEXT I |
||
270 IF C THEN PRINT</ |
270 IF C THEN PRINT</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre> Ready |
<pre> Ready |
||
Line 1,703: | Line 1,703: | ||
==={{header|Commodore BASIC}}=== |
==={{header|Commodore BASIC}}=== |
||
Since C= BASIC initializes arrays to all zeroes automatically, we avoid needing our own initialization loop by simply letting 0 mean prime and using 1 for composite. |
Since C= BASIC initializes arrays to all zeroes automatically, we avoid needing our own initialization loop by simply letting 0 mean prime and using 1 for composite. |
||
< |
<syntaxhighlight lang=basic>100 REM SIEVE OF ERATOSTHENES |
||
110 INPUT "LIMIT";LI |
110 INPUT "LIMIT";LI |
||
120 DIM N(LI) |
120 DIM N(LI) |
||
Line 1,718: | Line 1,718: | ||
230 NEXT I |
230 NEXT I |
||
240 PRINT |
240 PRINT |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Out}} |
{{Out}} |
||
<pre> |
<pre> |
||
Line 1,736: | Line 1,736: | ||
==={{header|IS-BASIC}}=== |
==={{header|IS-BASIC}}=== |
||
< |
<syntaxhighlight lang=IS-BASIC>100 PROGRAM "Sieve.bas" |
||
110 LET LIMIT=100 |
110 LET LIMIT=100 |
||
120 NUMERIC T(1 TO LIMIT) |
120 NUMERIC T(1 TO LIMIT) |
||
Line 1,751: | Line 1,751: | ||
230 FOR I=2 TO LIMIT ! Display the primes |
230 FOR I=2 TO LIMIT ! Display the primes |
||
240 IF T(I)=0 THEN PRINT I; |
240 IF T(I)=0 THEN PRINT I; |
||
250 NEXT</ |
250 NEXT</syntaxhighlight> |
||
==={{header|Locomotive Basic}}=== |
==={{header|Locomotive Basic}}=== |
||
< |
<syntaxhighlight lang=locobasic>10 DEFINT a-z |
||
20 INPUT "Limit";limit |
20 INPUT "Limit";limit |
||
30 DIM f(limit) |
30 DIM f(limit) |
||
Line 1,765: | Line 1,765: | ||
100 FOR n=2 TO limit |
100 FOR n=2 TO limit |
||
110 IF f(n)=0 THEN PRINT n;","; |
110 IF f(n)=0 THEN PRINT n;","; |
||
120 NEXT</ |
120 NEXT</syntaxhighlight> |
||
==={{header|MSX Basic}}=== |
==={{header|MSX Basic}}=== |
||
< |
<syntaxhighlight lang=MSX Basic>5 REM Tested with MSXPen web emulator |
||
6 REM Translated from Rosetta's ZX Spectrum implementation |
6 REM Translated from Rosetta's ZX Spectrum implementation |
||
10 INPUT "Enter number to search to: ";l |
10 INPUT "Enter number to search to: ";l |
||
Line 1,781: | Line 1,781: | ||
100 FOR n=2 TO l |
100 FOR n=2 TO l |
||
110 IF p(n)=0 THEN PRINT n;", "; |
110 IF p(n)=0 THEN PRINT n;", "; |
||
120 NEXT n</ |
120 NEXT n</syntaxhighlight> |
||
==={{header|Sinclair ZX81 BASIC}}=== |
==={{header|Sinclair ZX81 BASIC}}=== |
||
Line 1,787: | Line 1,787: | ||
A note on <code>FAST</code> and <code>SLOW</code>: under normal circumstances the CPU spends about 3/4 of its time driving the display and only 1/4 doing everything else. Entering <code>FAST</code> mode blanks the screen (which we do not want to update anyway), resulting in substantially improved performance; we then return to <code>SLOW</code> mode when we have something to print out. |
A note on <code>FAST</code> and <code>SLOW</code>: under normal circumstances the CPU spends about 3/4 of its time driving the display and only 1/4 doing everything else. Entering <code>FAST</code> mode blanks the screen (which we do not want to update anyway), resulting in substantially improved performance; we then return to <code>SLOW</code> mode when we have something to print out. |
||
< |
<syntaxhighlight lang=basic> 10 INPUT L |
||
20 FAST |
20 FAST |
||
30 DIM N(L) |
30 DIM N(L) |
||
Line 1,799: | Line 1,799: | ||
110 FOR I=2 TO L |
110 FOR I=2 TO L |
||
120 IF NOT N(I) THEN PRINT I;" "; |
120 IF NOT N(I) THEN PRINT I;" "; |
||
130 NEXT I</ |
130 NEXT I</syntaxhighlight> |
||
==={{header|ZX Spectrum Basic}}=== |
==={{header|ZX Spectrum Basic}}=== |
||
< |
<syntaxhighlight lang=zxbasic>10 INPUT "Enter number to search to: ";l |
||
20 DIM p(l) |
20 DIM p(l) |
||
30 FOR n=2 TO SQR l |
30 FOR n=2 TO SQR l |
||
Line 1,813: | Line 1,813: | ||
100 FOR n=2 TO l |
100 FOR n=2 TO l |
||
110 IF p(n)=0 THEN PRINT n;", "; |
110 IF p(n)=0 THEN PRINT n;", "; |
||
120 NEXT n</ |
120 NEXT n</syntaxhighlight> |
||
==={{header|QBasic}}=== |
==={{header|QBasic}}=== |
||
{{works with|QBasic|1.1}} |
{{works with|QBasic|1.1}} |
||
{{works with|QuickBasic|4.5}} |
{{works with|QuickBasic|4.5}} |
||
< |
<syntaxhighlight lang=qbasic>limit = 120 |
||
DIM flags(limit) |
DIM flags(limit) |
||
Line 1,836: | Line 1,836: | ||
FOR n = 1 TO limit |
FOR n = 1 TO limit |
||
IF flags(n) THEN PRINT USING "####"; n; |
IF flags(n) THEN PRINT USING "####"; n; |
||
NEXT n</ |
NEXT n</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Prime numbers less than or equal to 120 are: |
<pre>Prime numbers less than or equal to 120 are: |
||
Line 1,842: | Line 1,842: | ||
==={{header|BASIC256}}=== |
==={{header|BASIC256}}=== |
||
< |
<syntaxhighlight lang=BASIC256>arraybase 1 |
||
limit = 120 |
limit = 120 |
||
Line 1,861: | Line 1,861: | ||
for n = 1 to limit |
for n = 1 to limit |
||
if flags[n] then print rjust(n,4); |
if flags[n] then print rjust(n,4); |
||
next n</ |
next n</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Prime numbers less than or equal to 120 are: |
<pre>Prime numbers less than or equal to 120 are: |
||
Line 1,868: | Line 1,868: | ||
==={{header|True BASIC}}=== |
==={{header|True BASIC}}=== |
||
{{trans|QBasic}} |
{{trans|QBasic}} |
||
< |
<syntaxhighlight lang=qbasic>LET limit = 120 |
||
DIM flags(0) |
DIM flags(0) |
||
MAT redim flags(limit) |
MAT redim flags(limit) |
||
Line 1,885: | Line 1,885: | ||
IF flags(n)<>0 then PRINT using "####": n; |
IF flags(n)<>0 then PRINT using "####": n; |
||
NEXT n |
NEXT n |
||
END</ |
END</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Same as QBasic entry.</pre> |
<pre>Same as QBasic entry.</pre> |
||
Line 1,893: | Line 1,893: | ||
{{trans|ZX Spectrum Basic}} |
{{trans|ZX Spectrum Basic}} |
||
Sets h$ to 1 for higher multiples of 2 via <code>FILL$</code>, later on sets <code>STEP</code> to 2n; replaces Floating Pt array p(z) with string variable h$(z) to sieve out all primes < z=441 (<code>l</code>=21) in under 1K, so that h$ is fillable to its maximum (32766), even on a 48K ZX Spectrum if translated back. |
Sets h$ to 1 for higher multiples of 2 via <code>FILL$</code>, later on sets <code>STEP</code> to 2n; replaces Floating Pt array p(z) with string variable h$(z) to sieve out all primes < z=441 (<code>l</code>=21) in under 1K, so that h$ is fillable to its maximum (32766), even on a 48K ZX Spectrum if translated back. |
||
< |
<syntaxhighlight lang=qbasic> |
||
10 INPUT "Enter Stopping Pt for squared factors: ";z |
10 INPUT "Enter Stopping Pt for squared factors: ";z |
||
15 LET l=SQR(z) |
15 LET l=SQR(z) |
||
Line 1,903: | Line 1,903: | ||
90 REM Display the primes |
90 REM Display the primes |
||
100 FOR n=2 TO z: IF h$(n)=0: PRINT n;", "; |
100 FOR n=2 TO z: IF h$(n)=0: PRINT n;", "; |
||
</syntaxhighlight> |
|||
</lang> |
|||
====2i wheel emulation of Sinclair ZX81 BASIC==== |
====2i wheel emulation of Sinclair ZX81 BASIC==== |
||
Backward-compatible also on Spectrums, as well as 1K ZX81s for all primes < Z=441. N.B. the <code>STEP</code> of 2 in line 40 mitigates line 50's inefficiency when going to 90. < |
Backward-compatible also on Spectrums, as well as 1K ZX81s for all primes < Z=441. N.B. the <code>STEP</code> of 2 in line 40 mitigates line 50's inefficiency when going to 90. <syntaxhighlight lang=qbasic> |
||
10 INPUT Z |
10 INPUT Z |
||
15 LET L=SQR(Z) |
15 LET L=SQR(Z) |
||
Line 1,922: | Line 1,922: | ||
120 IF H$(I)="0" THEN PRINT I! |
120 IF H$(I)="0" THEN PRINT I! |
||
130 NEXT I |
130 NEXT I |
||
</syntaxhighlight> |
|||
</lang> |
|||
====2i wheel emulation of Sinclair ZX80 BASIC==== |
====2i wheel emulation of Sinclair ZX80 BASIC==== |
||
. . . with 2:1 compression (of 16-bit integer variables on ZX80s) such that it obviates having to account for any multiple of 2; one has to input odd upper limits on factors to be squared, <code>L</code> (=21 at most on 1K ZX80s for all primes till 439). |
. . . with 2:1 compression (of 16-bit integer variables on ZX80s) such that it obviates having to account for any multiple of 2; one has to input odd upper limits on factors to be squared, <code>L</code> (=21 at most on 1K ZX80s for all primes till 439). |
||
Backward-compatible on ZX80s after substituting ** for ^ in line 120.< |
Backward-compatible on ZX80s after substituting ** for ^ in line 120.<syntaxhighlight lang=qbasic> |
||
10 INPUT L |
10 INPUT L |
||
15 LET Z=(L+1)*(L- 1)/2 |
15 LET Z=(L+1)*(L- 1)/2 |
||
Line 1,939: | Line 1,939: | ||
120 IF NOT H(I) THEN PRINT 0^I+1+I*2! |
120 IF NOT H(I) THEN PRINT 0^I+1+I*2! |
||
130 NEXT I |
130 NEXT I |
||
</syntaxhighlight> |
|||
</lang> |
|||
====Sieve of Sundaram==== |
====Sieve of Sundaram==== |
||
Line 1,946: | Line 1,946: | ||
duplicate entries are omitted. Thus, a slightly transformed Sieve of Sundaram is what Eratosthenes' Sieve becomes upon applying all |
duplicate entries are omitted. Thus, a slightly transformed Sieve of Sundaram is what Eratosthenes' Sieve becomes upon applying all |
||
optimisations incorporated into the prior entries for QL SuperBASIC, except for any equivalent to line 50 in them. |
optimisations incorporated into the prior entries for QL SuperBASIC, except for any equivalent to line 50 in them. |
||
Backward-compatible on 1K ZX80s for all primes < 441 (O=10) after substituting ** for ^ in line 120.< |
Backward-compatible on 1K ZX80s for all primes < 441 (O=10) after substituting ** for ^ in line 120.<syntaxhighlight lang=qbasic> |
||
10 INPUT O |
10 INPUT O |
||
15 LET Z=2*O*O+O*2 |
15 LET Z=2*O*O+O*2 |
||
Line 1,961: | Line 1,961: | ||
120 IF NOT H(I) THEN PRINT 0^I+1+I*2! |
120 IF NOT H(I) THEN PRINT 0^I+1+I*2! |
||
130 NEXT I |
130 NEXT I |
||
</syntaxhighlight> |
|||
</lang> |
|||
====Eulerian optimisation==== |
====Eulerian optimisation==== |
||
While slower than the optimised Sieve of Eratosthenes before it, the Sieve of Sundaram above has a compatible compression scheme that's more convenient than the conventional one used beforehand. It is therefore applied below along with Euler's alternative optimisation in a reversed implementation that lacks backward-compatibility to ZX80 BASIC. This program is designed around features & limitations of the QL, yet can be rewritten more efficiently for 1K ZX80s, as they allow integer variables to be parameters of <code>FOR</code> statements (& as their 1K of static RAM is equivalent to L1 cache, even in <code>FAST</code> mode). That's left as an exercise for ZX80 enthusiasts, who for o%=14 should be able to generate all primes < 841, i.e. 3 orders of (base 2) magnitude above the limit for the program listed under Sinclair ZX81 BASIC. In QL SuperBASIC, o% may at most be 127--generating all primes < 65,025 (almost 2x the upper limit for indices & integer variables used to calculate them ~2x faster than for floating point as used in line 30, after which the integer code mimics an assembly algorithm for the QL's 68008.) |
While slower than the optimised Sieve of Eratosthenes before it, the Sieve of Sundaram above has a compatible compression scheme that's more convenient than the conventional one used beforehand. It is therefore applied below along with Euler's alternative optimisation in a reversed implementation that lacks backward-compatibility to ZX80 BASIC. This program is designed around features & limitations of the QL, yet can be rewritten more efficiently for 1K ZX80s, as they allow integer variables to be parameters of <code>FOR</code> statements (& as their 1K of static RAM is equivalent to L1 cache, even in <code>FAST</code> mode). That's left as an exercise for ZX80 enthusiasts, who for o%=14 should be able to generate all primes < 841, i.e. 3 orders of (base 2) magnitude above the limit for the program listed under Sinclair ZX81 BASIC. In QL SuperBASIC, o% may at most be 127--generating all primes < 65,025 (almost 2x the upper limit for indices & integer variables used to calculate them ~2x faster than for floating point as used in line 30, after which the integer code mimics an assembly algorithm for the QL's 68008.) |
||
< |
<syntaxhighlight lang=qbasic> |
||
10 INPUT "Enter highest value of diagonal index q%: ";o% |
10 INPUT "Enter highest value of diagonal index q%: ";o% |
||
15 LET z%=o%*(2+o%*2) : h$=FILL$(" ",z%+o%) : q%=1 : q=q% : m=z% DIV (2*q%+1) |
15 LET z%=o%*(2+o%*2) : h$=FILL$(" ",z%+o%) : q%=1 : q=q% : m=z% DIV (2*q%+1) |
||
Line 1,979: | Line 1,979: | ||
110 GOTO 100 |
110 GOTO 100 |
||
127 DEF FN N%(i)=0^i+1+i*2 |
127 DEF FN N%(i)=0^i+1+i*2 |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Batch File}}== |
=={{header|Batch File}}== |
||
< |
<syntaxhighlight lang=dos>:: Sieve of Eratosthenes for Rosetta Code - PG |
||
@echo off |
@echo off |
||
setlocal ENABLEDELAYEDEXPANSION |
setlocal ENABLEDELAYEDEXPANSION |
||
Line 2,001: | Line 2,001: | ||
if !crible.%%i! EQU 1 echo %%i |
if !crible.%%i! EQU 1 echo %%i |
||
) |
) |
||
pause</ |
pause</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre style="height:20ex">limit: 100 |
<pre style="height:20ex">limit: 100 |
||
Line 2,031: | Line 2,031: | ||
=={{header|BBC BASIC}}== |
=={{header|BBC BASIC}}== |
||
< |
<syntaxhighlight lang=bbcbasic> limit% = 100000 |
||
DIM sieve% limit% |
DIM sieve% limit% |
||
Line 2,045: | Line 2,045: | ||
FOR I% = 1 TO limit% |
FOR I% = 1 TO limit% |
||
IF sieve%?I% = 0 PRINT I%; |
IF sieve%?I% = 0 PRINT I%; |
||
NEXT</ |
NEXT</syntaxhighlight> |
||
=={{header|BCPL}}== |
=={{header|BCPL}}== |
||
< |
<syntaxhighlight lang=bcpl>get "libhdr" |
||
manifest $( LIMIT = 1000 $) |
manifest $( LIMIT = 1000 $) |
||
Line 2,080: | Line 2,080: | ||
$) |
$) |
||
wrch('*N') |
wrch('*N') |
||
$)</ |
$)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 |
<pre> 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 |
||
Line 2,093: | Line 2,093: | ||
=== Odds-only bit packed array version (64 bit) === |
=== Odds-only bit packed array version (64 bit) === |
||
This sieve also uses an iterator structure to enumerate the primes in the sieve. It's inspired by the golang bit packed sieve that returns a closure as an iterator. However, BCPL does not support closures, so the code uses an iterator object. |
This sieve also uses an iterator structure to enumerate the primes in the sieve. It's inspired by the golang bit packed sieve that returns a closure as an iterator. However, BCPL does not support closures, so the code uses an iterator object. |
||
< |
<syntaxhighlight lang=BCPL> |
||
GET "libhdr" |
GET "libhdr" |
||
Line 2,216: | Line 2,216: | ||
RESULTIS 0 |
RESULTIS 0 |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Out}} |
{{Out}} |
||
<pre> |
<pre> |
||
Line 2,253: | Line 2,253: | ||
A more efficient sieve (primes below one billion in under a minute) is provided as <code>PrimesTo</code> in bqn-libs [https://github.com/mlochbaum/bqn-libs/blob/master/primes.bqn primes.bqn]. |
A more efficient sieve (primes below one billion in under a minute) is provided as <code>PrimesTo</code> in bqn-libs [https://github.com/mlochbaum/bqn-libs/blob/master/primes.bqn primes.bqn]. |
||
< |
<syntaxhighlight lang=bqn>Primes ← { |
||
𝕩≤2 ? ↕0 ; # No primes below 2 |
𝕩≤2 ? ↕0 ; # No primes below 2 |
||
p ← 𝕊⌈√n←𝕩 # Initial primes by recursion |
p ← 𝕊⌈√n←𝕩 # Initial primes by recursion |
||
Line 2,259: | Line 2,259: | ||
E ← {↕∘⌈⌾((𝕩×𝕩+⊢)⁼)n} # Multiples of 𝕩 under n, starting at 𝕩×𝕩 |
E ← {↕∘⌈⌾((𝕩×𝕩+⊢)⁼)n} # Multiples of 𝕩 under n, starting at 𝕩×𝕩 |
||
/ b E⊸{0¨⌾(𝕨⊸⊏)𝕩}´ p # Cross them out |
/ b E⊸{0¨⌾(𝕨⊸⊏)𝕩}´ p # Cross them out |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
< |
<syntaxhighlight lang=bqn> Primes 100 |
||
⟨ 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ⟩ |
⟨ 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ⟩ |
||
≠∘Primes¨ 10⋆↕7 # Number of primes below 1e0, 1e1, ... 1e6 |
≠∘Primes¨ 10⋆↕7 # Number of primes below 1e0, 1e1, ... 1e6 |
||
⟨ 0 4 25 168 1229 9592 78498 ⟩</ |
⟨ 0 4 25 168 1229 9592 78498 ⟩</syntaxhighlight> |
||
=={{header|Bracmat}}== |
=={{header|Bracmat}}== |
||
This solution does not use an array. Instead, numbers themselves are used as variables. The numbers that are not prime are set (to the silly value "nonprime"). Finally all numbers up to the limit are tested for being initialised. The uninitialised (unset) ones must be the primes. |
This solution does not use an array. Instead, numbers themselves are used as variables. The numbers that are not prime are set (to the silly value "nonprime"). Finally all numbers up to the limit are tested for being initialised. The uninitialised (unset) ones must be the primes. |
||
< |
<syntaxhighlight lang=bracmat>( ( eratosthenes |
||
= n j i |
= n j i |
||
. !arg:?n |
. !arg:?n |
||
Line 2,290: | Line 2,290: | ||
) |
) |
||
& eratosthenes$100 |
& eratosthenes$100 |
||
)</ |
)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
||
=={{header|C}}== |
=={{header|C}}== |
||
Plain sieve, without any optimizations:< |
Plain sieve, without any optimizations:<syntaxhighlight lang=c>#include <stdlib.h> |
||
#include <math.h> |
#include <math.h> |
||
Line 2,322: | Line 2,322: | ||
} |
} |
||
return sieve; |
return sieve; |
||
}</ |
}</syntaxhighlight>Possible optimizations include sieving only odd numbers (or more complex wheels), packing the sieve into bits to improve locality (and allow larger sieves), etc. |
||
'''Another example:''' |
'''Another example:''' |
||
Line 2,329: | Line 2,329: | ||
Then, in a loop, fill zeroes into those places where i * j is less than or equal to n (number of primes requested), which means they have multiples! |
Then, in a loop, fill zeroes into those places where i * j is less than or equal to n (number of primes requested), which means they have multiples! |
||
To understand this better, look at the output of the following example. |
To understand this better, look at the output of the following example. |
||
To print this back, we look for ones in the array and only print those spots. < |
To print this back, we look for ones in the array and only print those spots. <syntaxhighlight lang=C>#include <stdio.h> |
||
#include <malloc.h> |
#include <malloc.h> |
||
void sieve(int *, int); |
void sieve(int *, int); |
||
Line 2,367: | Line 2,367: | ||
} |
} |
||
printf("\n\n"); |
printf("\n\n"); |
||
}</ |
}</syntaxhighlight>{{out}}<syntaxhighlight lang=Shell>i:2 |
||
j:2 |
j:2 |
||
Before a[2*2]: 1 |
Before a[2*2]: 1 |
||
Line 2,391: | Line 2,391: | ||
i:9 |
i:9 |
||
i:10 |
i:10 |
||
Primes numbers from 1 to 10 are : 2, 3, 5, 7, </ |
Primes numbers from 1 to 10 are : 2, 3, 5, 7, </syntaxhighlight> |
||
=={{header|C sharp|C#}}== |
=={{header|C sharp|C#}}== |
||
{{works with|C sharp|C#|2.0+}} |
{{works with|C sharp|C#|2.0+}} |
||
< |
<syntaxhighlight lang=csharp>using System; |
||
using System.Collections; |
using System.Collections; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
Line 2,438: | Line 2,438: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
===Richard Bird Sieve=== |
===Richard Bird Sieve=== |
||
Line 2,445: | Line 2,445: | ||
To show that C# code can be written in somewhat functional paradigms, the following in an implementation of the Richard Bird sieve from the Epilogue of [Melissa E. O'Neill's definitive article](http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf) in Haskell: |
To show that C# code can be written in somewhat functional paradigms, the following in an implementation of the Richard Bird sieve from the Epilogue of [Melissa E. O'Neill's definitive article](http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf) in Haskell: |
||
< |
<syntaxhighlight lang=csharp>using System; |
||
using System.Collections; |
using System.Collections; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
Line 2,485: | Line 2,485: | ||
} |
} |
||
IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } |
IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } |
||
}</ |
}</syntaxhighlight> |
||
===Tree Folding Sieve=== |
===Tree Folding Sieve=== |
||
Line 2,492: | Line 2,492: | ||
The above code can easily be converted to "'''odds-only'''" and a infinite tree-like folding scheme with the following minor changes: |
The above code can easily be converted to "'''odds-only'''" and a infinite tree-like folding scheme with the following minor changes: |
||
< |
<syntaxhighlight lang=csharp>using System; |
||
using System.Collections; |
using System.Collections; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
Line 2,540: | Line 2,540: | ||
} |
} |
||
IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } |
IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } |
||
}</ |
}</syntaxhighlight> |
||
The above code runs over ten times faster than the original Richard Bird algorithm. |
The above code runs over ten times faster than the original Richard Bird algorithm. |
||
Line 2,549: | Line 2,549: | ||
First, an implementation of a Min Heap Priority Queue is provided as extracted from the entry at [http://rosettacode.org/wiki/Priority_queue#C.23 RosettaCode], with only the necessary methods duplicated here: |
First, an implementation of a Min Heap Priority Queue is provided as extracted from the entry at [http://rosettacode.org/wiki/Priority_queue#C.23 RosettaCode], with only the necessary methods duplicated here: |
||
< |
<syntaxhighlight lang=csharp>namespace PriorityQ { |
||
using KeyT = System.UInt32; |
using KeyT = System.UInt32; |
||
using System; |
using System; |
||
Line 2,606: | Line 2,606: | ||
public static MinHeapPQ<V> replaceMin(KeyT k, V v, MinHeapPQ<V> pq) { |
public static MinHeapPQ<V> replaceMin(KeyT k, V v, MinHeapPQ<V> pq) { |
||
pq.rplcmin(k, v); return pq; } |
pq.rplcmin(k, v); return pq; } |
||
}</ |
}</syntaxhighlight> |
||
Line 2,613: | Line 2,613: | ||
The following code implements an improved version of the '''odds-only''' O'Neil algorithm, which provides the improvements of only adding base prime composite number streams to the queue when the sieved number reaches the square of the base prime (saving a huge amount of memory and considerable execution time, including not needing as wide a range of a type for the internal prime numbers) as well as minimizing stream processing using fusion: |
The following code implements an improved version of the '''odds-only''' O'Neil algorithm, which provides the improvements of only adding base prime composite number streams to the queue when the sieved number reaches the square of the base prime (saving a huge amount of memory and considerable execution time, including not needing as wide a range of a type for the internal prime numbers) as well as minimizing stream processing using fusion: |
||
< |
<syntaxhighlight lang=csharp>using System; |
||
using System.Collections; |
using System.Collections; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
Line 2,648: | Line 2,648: | ||
public IEnumerator<PrimeT> GetEnumerator() { return nmrtr(); } |
public IEnumerator<PrimeT> GetEnumerator() { return nmrtr(); } |
||
IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } |
IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } |
||
}</ |
}</syntaxhighlight> |
||
The above code is at least about 2.5 times faster than the Tree Folding version. |
The above code is at least about 2.5 times faster than the Tree Folding version. |
||
Line 2,657: | Line 2,657: | ||
The above code adds quite a bit of overhead in having to provide a version of a Priority Queue for little advantage over a Dictionary (hash table based) version as per the code below: |
The above code adds quite a bit of overhead in having to provide a version of a Priority Queue for little advantage over a Dictionary (hash table based) version as per the code below: |
||
< |
<syntaxhighlight lang=csharp>using System; |
||
using System.Collections; |
using System.Collections; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
Line 2,690: | Line 2,690: | ||
public IEnumerator<PrimeT> GetEnumerator() { return nmrtr(); } |
public IEnumerator<PrimeT> GetEnumerator() { return nmrtr(); } |
||
IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } |
IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } |
||
}</ |
}</syntaxhighlight> |
||
The above code runs in about three quarters of the time as the above Priority Queue based version for a range of a million primes which will fall even further behind for increasing ranges due to the Dictionary providing O(1) access times as compared to the O(log n) access times for the Priority Queue; the only slight advantage of the PQ based version is at very small ranges where the constant factor overhead of computing the table hashes becomes greater than the "log n" factor for small "n". |
The above code runs in about three quarters of the time as the above Priority Queue based version for a range of a million primes which will fall even further behind for increasing ranges due to the Dictionary providing O(1) access times as compared to the O(log n) access times for the Priority Queue; the only slight advantage of the PQ based version is at very small ranges where the constant factor overhead of computing the table hashes becomes greater than the "log n" factor for small "n". |
||
Line 2,697: | Line 2,697: | ||
All of the above unbounded versions are really just an intellectual exercise as with very little extra lines of code above the fastest Dictionary based version, one can have an bit-packed page-segmented array based version as follows: |
All of the above unbounded versions are really just an intellectual exercise as with very little extra lines of code above the fastest Dictionary based version, one can have an bit-packed page-segmented array based version as follows: |
||
< |
<syntaxhighlight lang=csharp>using System; |
||
using System.Collections; |
using System.Collections; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
Line 2,753: | Line 2,753: | ||
public IEnumerator<PrimeT> GetEnumerator() { return nmrtr(); } |
public IEnumerator<PrimeT> GetEnumerator() { return nmrtr(); } |
||
IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } |
IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } |
||
}</ |
}</syntaxhighlight> |
||
The above code is about 25 times faster than the Dictionary version at computing the first about 50 million primes (up to a range of one billion), with the actual enumeration of the result sequence now taking longer than the time it takes to cull the composite number representation bits from the arrays, meaning that it is over 50 times faster at actually sieving the primes. The code owes its speed as compared to a naive "one huge memory array" algorithm to using an array size that is the size of the CPU L1 or L2 caches and using bit-packing to fit more number representations into this limited capacity; in this way RAM memory access times are reduced by a factor of from about four to about 10 (depending on CPU and RAM speed) as compared to those naive implementations, and the minor computational cost of the bit manipulations is compensated by a large factor in total execution time. |
The above code is about 25 times faster than the Dictionary version at computing the first about 50 million primes (up to a range of one billion), with the actual enumeration of the result sequence now taking longer than the time it takes to cull the composite number representation bits from the arrays, meaning that it is over 50 times faster at actually sieving the primes. The code owes its speed as compared to a naive "one huge memory array" algorithm to using an array size that is the size of the CPU L1 or L2 caches and using bit-packing to fit more number representations into this limited capacity; in this way RAM memory access times are reduced by a factor of from about four to about 10 (depending on CPU and RAM speed) as compared to those naive implementations, and the minor computational cost of the bit manipulations is compensated by a large factor in total execution time. |
||
Line 2,764: | Line 2,764: | ||
All of the above unbounded code can be tested by the following "main" method (replace the name "PrimesXXX" with the name of the class to be tested): |
All of the above unbounded code can be tested by the following "main" method (replace the name "PrimesXXX" with the name of the class to be tested): |
||
< |
<syntaxhighlight lang=csharp> static void Main(string[] args) { |
||
Console.WriteLine(PrimesXXX().ElementAt(1000000 - 1)); // zero based indexing... |
Console.WriteLine(PrimesXXX().ElementAt(1000000 - 1)); // zero based indexing... |
||
}</ |
}</syntaxhighlight> |
||
To produce the following output for all tested versions (although some are considerably faster than others): |
To produce the following output for all tested versions (although some are considerably faster than others): |
||
Line 2,777: | Line 2,777: | ||
This implementation follows the standard library pattern of [http://en.cppreference.com/w/cpp/algorithm/iota std::iota]. The start and end iterators are provided for the container. The destination container is used for marking primes and then filled with the primes which are less than the container size. This method requires no memory allocation inside the function. |
This implementation follows the standard library pattern of [http://en.cppreference.com/w/cpp/algorithm/iota std::iota]. The start and end iterators are provided for the container. The destination container is used for marking primes and then filled with the primes which are less than the container size. This method requires no memory allocation inside the function. |
||
< |
<syntaxhighlight lang=cpp>#include <iostream> |
||
#include <algorithm> |
#include <algorithm> |
||
#include <vector> |
#include <vector> |
||
Line 2,824: | Line 2,824: | ||
std::cout << std::endl; |
std::cout << std::endl; |
||
return 1; |
return 1; |
||
}</ |
}</syntaxhighlight> |
||
=== Boost === |
=== Boost === |
||
< |
<syntaxhighlight lang=cpp>// yield all prime numbers less than limit. |
||
template<class UnaryFunction> |
template<class UnaryFunction> |
||
void primesupto(int limit, UnaryFunction yield) |
void primesupto(int limit, UnaryFunction yield) |
||
Line 2,847: | Line 2,847: | ||
if (is_prime[n]) |
if (is_prime[n]) |
||
yield(n); |
yield(n); |
||
}</ |
}</syntaxhighlight> |
||
Full program: |
Full program: |
||
{{works with|Boost}}< |
{{works with|Boost}}<syntaxhighlight lang=cpp>/** |
||
$ g++ -I/path/to/boost sieve.cpp -o sieve && sieve 10000000 |
$ g++ -I/path/to/boost sieve.cpp -o sieve && sieve 10000000 |
||
*/ |
*/ |
||
Line 2,891: | Line 2,891: | ||
cout << "limit sum pi(n)\n" |
cout << "limit sum pi(n)\n" |
||
<< limit << " " << sum << " " << count << endl; |
<< limit << " " << sum << " " << count << endl; |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Chapel}}== |
=={{header|Chapel}}== |
||
{{incorrect|Chapel|Doesn't compile since at least Chapel version 1.20 to 1.24.1.}} |
{{incorrect|Chapel|Doesn't compile since at least Chapel version 1.20 to 1.24.1.}} |
||
This solution uses nested iterators to create new wheels at run time: |
This solution uses nested iterators to create new wheels at run time: |
||
< |
<syntaxhighlight lang=chapel>// yield prime and remove all multiples of it from children sieves |
||
iter sieve(prime):int { |
iter sieve(prime):int { |
||
Line 2,918: | Line 2,918: | ||
yield candidate; |
yield candidate; |
||
} |
} |
||
}</ |
}</syntaxhighlight>The topmost sieve needs to be started with 2 (the smallest prime): |
||
< |
<syntaxhighlight lang=chapel>config const N = 30; |
||
for p in sieve(2) { |
for p in sieve(2) { |
||
if p > N { |
if p > N { |
||
Line 2,926: | Line 2,926: | ||
} |
} |
||
write(" ", p); |
write(" ", p); |
||
}</ |
}</syntaxhighlight> |
||
===Alternate Conventional Bit-Packed Implementation=== |
===Alternate Conventional Bit-Packed Implementation=== |
||
Line 2,934: | Line 2,934: | ||
compile with the `--fast` option |
compile with the `--fast` option |
||
< |
<syntaxhighlight lang=chapel>use Time; |
||
use BitOps; |
use BitOps; |
||
Line 2,973: | Line 2,973: | ||
for p in 2 .. n do if cmpsts[p >> 3] & (1: uint(8) << (p & 7)) == 0 then yield p; |
for p in 2 .. n do if cmpsts[p >> 3] & (1: uint(8) << (p & 7)) == 0 then yield p; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,985: | Line 2,985: | ||
===Alternate Odds-Only Bit-Packed Implementation=== |
===Alternate Odds-Only Bit-Packed Implementation=== |
||
< |
<syntaxhighlight lang=chapel>use Time; |
||
use BitOps; |
use BitOps; |
||
Line 3,028: | Line 3,028: | ||
if cmpsts[i >> 3] & (1: uint(8) << (i & 7)) == 0 then yield i + i + 3; |
if cmpsts[i >> 3] & (1: uint(8) << (i & 7)) == 0 then yield i + i + 3; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,045: | Line 3,045: | ||
{{works with|Chapel|1.25.1}} |
{{works with|Chapel|1.25.1}} |
||
< |
<syntaxhighlight lang=chapel>use Time; |
||
config const limit = 100000000; |
config const limit = 100000000; |
||
Line 3,096: | Line 3,096: | ||
write("Found ", count, " primes up to ", limit); |
write("Found ", count, " primes up to ", limit); |
||
writeln(" in ", timer.elapsed(TimeUnits.milliseconds), " milliseconds."); |
writeln(" in ", timer.elapsed(TimeUnits.milliseconds), " milliseconds."); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,112: | Line 3,112: | ||
Compile with the `--fast` compiler command line option |
Compile with the `--fast` compiler command line option |
||
< |
<syntaxhighlight lang=chapel>use Time; |
||
config const limit = 100000000; |
config const limit = 100000000; |
||
Line 3,207: | Line 3,207: | ||
write("Found ", count, " primes up to ", limit); |
write("Found ", count, " primes up to ", limit); |
||
writeln(" in ", timer.elapsed(TimeUnits.milliseconds), " milliseconds."); |
writeln(" in ", timer.elapsed(TimeUnits.milliseconds), " milliseconds."); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,221: | Line 3,221: | ||
Compile with the `--fast` compiler command line option |
Compile with the `--fast` compiler command line option |
||
< |
<syntaxhighlight lang=chapel>use Time; |
||
use Map; |
use Map; |
||
Line 3,276: | Line 3,276: | ||
write("Found ", count, " primes up to ", limit); |
write("Found ", count, " primes up to ", limit); |
||
writeln(" in ", timer.elapsed(TimeUnits.milliseconds), " milliseconds."); |
writeln(" in ", timer.elapsed(TimeUnits.milliseconds), " milliseconds."); |
||
}</ |
}</syntaxhighlight> |
||
This works in about exactly the same time as the last previous code, but doesn't require special custom adaptations of the associative array so that the standard library Map can be used. |
This works in about exactly the same time as the last previous code, but doesn't require special custom adaptations of the associative array so that the standard library Map can be used. |
||
Line 3,286: | Line 3,286: | ||
{{trans|Nim}} [https://rosettacode.org/wiki/Sieve_of_Eratosthenes#Nim_Unbounded_Versions code link] |
{{trans|Nim}} [https://rosettacode.org/wiki/Sieve_of_Eratosthenes#Nim_Unbounded_Versions code link] |
||
{{works with|Chapel|1.22|- compile with the --fast compiler command line flag for full optimization}} |
{{works with|Chapel|1.22|- compile with the --fast compiler command line flag for full optimization}} |
||
< |
<syntaxhighlight lang=chapel>use Time; |
||
type Prime = uint(32); |
type Prime = uint(32); |
||
Line 3,401: | Line 3,401: | ||
for p in primes() { if p > limit then break; cnt += 1; } |
for p in primes() { if p > limit then break; cnt += 1; } |
||
timer.stop(); write("\nFound ", cnt, " primes up to ", limit); |
timer.stop(); write("\nFound ", cnt, " primes up to ", limit); |
||
writeln(" in ", timer.elapsed(TimeUnits.milliseconds), " milliseconds.");</ |
writeln(" in ", timer.elapsed(TimeUnits.milliseconds), " milliseconds.");</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>The first 25 primes are: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
<pre>The first 25 primes are: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
||
Line 3,414: | Line 3,414: | ||
To take advantage of the features that make Chapel shine, we need to use it to do some parallel computations, and to efficiently do that for the Sieve of Eratosthenes, we need to divide the work into page segments where we can assign each largish segment to a separate thread/task; this also improves the speed due to better cache associativity with most memory accesses to values that are already in the cache(s). Once we have divided the work, Chapel offers lots of means to implement the parallelism but to be a true Sieve of Eratosthenes, we need to have the ability to output the results in order; with many of the convenience mechanisms not doing that, the best/simplest option is likely task parallelism with the output results assigned to an rotary indexed array containing the `sync` results. It turns out that, although the Chapel compiler can sometimes optimize the code so the overhead of creating tasks is not onerous, for this case where the actual tasks are somewhat complex, the compiler can't recognize that an automatically generated thread pool(s) are required so we need to generate the thread pool(s) manually. The code that implements the multi-threading of page segments using thread pools is as follows: |
To take advantage of the features that make Chapel shine, we need to use it to do some parallel computations, and to efficiently do that for the Sieve of Eratosthenes, we need to divide the work into page segments where we can assign each largish segment to a separate thread/task; this also improves the speed due to better cache associativity with most memory accesses to values that are already in the cache(s). Once we have divided the work, Chapel offers lots of means to implement the parallelism but to be a true Sieve of Eratosthenes, we need to have the ability to output the results in order; with many of the convenience mechanisms not doing that, the best/simplest option is likely task parallelism with the output results assigned to an rotary indexed array containing the `sync` results. It turns out that, although the Chapel compiler can sometimes optimize the code so the overhead of creating tasks is not onerous, for this case where the actual tasks are somewhat complex, the compiler can't recognize that an automatically generated thread pool(s) are required so we need to generate the thread pool(s) manually. The code that implements the multi-threading of page segments using thread pools is as follows: |
||
{{works with|Chapel|1.24.1|- compile with the --fast compiler command line flag for full optimization}} |
{{works with|Chapel|1.24.1|- compile with the --fast compiler command line flag for full optimization}} |
||
< |
<syntaxhighlight lang=chapel>use Time; use BitOps; use CPtr; |
||
type Prime = uint(64); |
type Prime = uint(64); |
||
Line 3,726: | Line 3,726: | ||
write("Found ", count, " primes up to ", LIMIT); |
write("Found ", count, " primes up to ", LIMIT); |
||
writeln(" in ", timer.elapsed(TimeUnits.milliseconds), " milliseconds.");</ |
writeln(" in ", timer.elapsed(TimeUnits.milliseconds), " milliseconds.");</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>The first 25 primes are: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
<pre>The first 25 primes are: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
||
Line 3,772: | Line 3,772: | ||
=={{header|Clojure}}== |
=={{header|Clojure}}== |
||
< |
<syntaxhighlight lang=clojure>(defn primes< [n] |
||
(remove (set (mapcat #(range (* % %) n %) |
(remove (set (mapcat #(range (* % %) n %) |
||
(range 2 (Math/sqrt n)))) |
(range 2 (Math/sqrt n)))) |
||
(range 2 n)))</ |
(range 2 n)))</syntaxhighlight> |
||
The above is **not strictly a Sieve of Eratosthenes** as the composite culling ranges (in the ''mapcat'') include all of the multiples of all of the numbers and not just the multiples of primes. When tested with <code clojure>(println (time (count (primes< 1000000))))</code>, it takes about 5.5 seconds just to find the number of primes up to a million, partly because of the extra work due to the use of the non-primes, and partly because of the constant enumeration using sequences with multiple levels of function calls. Although very short, this code is likely only useful up to about this range of a million. |
The above is **not strictly a Sieve of Eratosthenes** as the composite culling ranges (in the ''mapcat'') include all of the multiples of all of the numbers and not just the multiples of primes. When tested with <code clojure>(println (time (count (primes< 1000000))))</code>, it takes about 5.5 seconds just to find the number of primes up to a million, partly because of the extra work due to the use of the non-primes, and partly because of the constant enumeration using sequences with multiple levels of function calls. Although very short, this code is likely only useful up to about this range of a million. |
||
Line 3,781: | Line 3,781: | ||
It may be written using the ''into #{}'' function to run slightly faster due to the ''set'' function being concerned with only distinct elements whereas the ''into #{}'' only does the conjunction, and even at that doesn't do that much as it does the conjunction to an empty sequence, the code as follows: |
It may be written using the ''into #{}'' function to run slightly faster due to the ''set'' function being concerned with only distinct elements whereas the ''into #{}'' only does the conjunction, and even at that doesn't do that much as it does the conjunction to an empty sequence, the code as follows: |
||
< |
<syntaxhighlight lang=clojure>(defn primes< [n] |
||
(remove (into #{} |
(remove (into #{} |
||
(mapcat #(range (* % %) n %) |
(mapcat #(range (* % %) n %) |
||
(range 2 (Math/sqrt n)))) |
(range 2 (Math/sqrt n)))) |
||
(range 2 n)))</ |
(range 2 n)))</syntaxhighlight> |
||
The above code is slightly faster for the reasons given, but is still not strictly a Sieve of Eratosthenes due to sieving by all numbers and not just by the base primes. |
The above code is slightly faster for the reasons given, but is still not strictly a Sieve of Eratosthenes due to sieving by all numbers and not just by the base primes. |
||
The following code also uses the ''into #{}'' transducer but has been slightly wheel-factorized to sieve odds-only: |
The following code also uses the ''into #{}'' transducer but has been slightly wheel-factorized to sieve odds-only: |
||
< |
<syntaxhighlight lang=clojure>(defn primes< [n] |
||
(if (< n 2) () |
(if (< n 2) () |
||
(cons 2 (remove (into #{} |
(cons 2 (remove (into #{} |
||
(mapcat #(range (* % %) n %) |
(mapcat #(range (* % %) n %) |
||
(range 3 (Math/sqrt n) 2))) |
(range 3 (Math/sqrt n) 2))) |
||
(range 3 n 2)))))</ |
(range 3 n 2)))))</syntaxhighlight> |
||
The above code is a little over twice as fast as the non-odds-only due to the reduced number of operations. It still isn't strictly a Sieve of Eratosthenes as it sieves by all odd base numbers and not only by the base primes. |
The above code is a little over twice as fast as the non-odds-only due to the reduced number of operations. It still isn't strictly a Sieve of Eratosthenes as it sieves by all odd base numbers and not only by the base primes. |
||
The following code calculates primes up to and including ''n'' using a mutable boolean array but otherwise entirely functional code; it is tens (to a hundred) times faster than the purely functional codes due to the use of mutability in the boolean array: |
The following code calculates primes up to and including ''n'' using a mutable boolean array but otherwise entirely functional code; it is tens (to a hundred) times faster than the purely functional codes due to the use of mutability in the boolean array: |
||
< |
<syntaxhighlight lang=clojure>(defn primes-to |
||
"Computes lazy sequence of prime numbers up to a given number using sieve of Eratosthenes" |
"Computes lazy sequence of prime numbers up to a given number using sieve of Eratosthenes" |
||
[n] |
[n] |
||
Line 3,812: | Line 3,812: | ||
(do (dorun (map #(cullp %) (filter #(not (aget cmpsts %)) |
(do (dorun (map #(cullp %) (filter #(not (aget cmpsts %)) |
||
(range 2 (inc root))))) |
(range 2 (inc root))))) |
||
(filter #(not (aget cmpsts %)) (range 2 (inc n))))))</ |
(filter #(not (aget cmpsts %)) (range 2 (inc n))))))</syntaxhighlight> |
||
'''Alternative implementation using Clojure's side-effect oriented list comprehension.''' |
'''Alternative implementation using Clojure's side-effect oriented list comprehension.''' |
||
< |
<syntaxhighlight lang=clojure> (defn primes-to |
||
"Returns a lazy sequence of prime numbers less than lim" |
"Returns a lazy sequence of prime numbers less than lim" |
||
[lim] |
[lim] |
||
Line 3,826: | Line 3,826: | ||
(doseq [j (range (* i i) lim i)] |
(doseq [j (range (* i i) lim i)] |
||
(aset refs j false))) |
(aset refs j false))) |
||
(filter #(aget refs %) (range 2 lim)))))</ |
(filter #(aget refs %) (range 2 lim)))))</syntaxhighlight> |
||
'''Alternative implementation using Clojure's side-effect oriented list comprehension. Odds only.''' |
'''Alternative implementation using Clojure's side-effect oriented list comprehension. Odds only.''' |
||
< |
<syntaxhighlight lang=clojure>(defn primes-to |
||
"Returns a lazy sequence of prime numbers less than lim" |
"Returns a lazy sequence of prime numbers less than lim" |
||
[lim] |
[lim] |
||
Line 3,839: | Line 3,839: | ||
(doseq [j (range (* (+ i i) (inc i)) max-i (+ i i 1))] |
(doseq [j (range (* (+ i i) (inc i)) max-i (+ i i 1))] |
||
(aset refs j false))) |
(aset refs j false))) |
||
(cons 2 (map #(+ % % 1) (filter #(aget refs %) (range 1 max-i)))))))</ |
(cons 2 (map #(+ % % 1) (filter #(aget refs %) (range 1 max-i)))))))</syntaxhighlight> |
||
This implemantation is about twice as fast as the previous one and uses only half the memory. |
This implemantation is about twice as fast as the previous one and uses only half the memory. |
||
Line 3,848: | Line 3,848: | ||
'''Alternative very slow entirely functional implementation using lazy sequences''' |
'''Alternative very slow entirely functional implementation using lazy sequences''' |
||
< |
<syntaxhighlight lang=clojure>(defn primes-to |
||
"Computes lazy sequence of prime numbers up to a given number using sieve of Eratosthenes" |
"Computes lazy sequence of prime numbers up to a given number using sieve of Eratosthenes" |
||
[n] |
[n] |
||
Line 3,856: | Line 3,856: | ||
(cons p (lazy-seq (nxtprm (-> (range (* p p) (inc n) p) |
(cons p (lazy-seq (nxtprm (-> (range (* p p) (inc n) p) |
||
set (remove cs) rest)))))))] |
set (remove cs) rest)))))))] |
||
(nxtprm (range 2 (inc n)))))</ |
(nxtprm (range 2 (inc n)))))</syntaxhighlight> |
||
The reason that the above code is so slow is that it has has a high constant factor overhead due to using a (hash) set to remove the composites from the future composites stream, each prime composite stream removal requires a scan across all remaining composites (compared to using an array or vector where only the culled values are referenced, and due to the slowness of Clojure sequence operations as compared to iterator/sequence operations in other languages. |
The reason that the above code is so slow is that it has has a high constant factor overhead due to using a (hash) set to remove the composites from the future composites stream, each prime composite stream removal requires a scan across all remaining composites (compared to using an array or vector where only the culled values are referenced, and due to the slowness of Clojure sequence operations as compared to iterator/sequence operations in other languages. |
||
Line 3,863: | Line 3,863: | ||
Here is an immutable boolean vector based non-lazy sequence version other than for the lazy sequence operations to output the result: |
Here is an immutable boolean vector based non-lazy sequence version other than for the lazy sequence operations to output the result: |
||
< |
<syntaxhighlight lang=clojure>(defn primes-to |
||
"Computes lazy sequence of prime numbers up to a given number using sieve of Eratosthenes" |
"Computes lazy sequence of prime numbers up to a given number using sieve of Eratosthenes" |
||
[max-prime] |
[max-prime] |
||
Line 3,877: | Line 3,877: | ||
(assoc 1 false) |
(assoc 1 false) |
||
(sieve 2)) |
(sieve 2)) |
||
(map-indexed #(vector %2 %1)) (filter first) (map second))))</ |
(map-indexed #(vector %2 %1)) (filter first) (map second))))</syntaxhighlight> |
||
The above code is still quite slow due to the cost of the immutable copy-on-modify operations. |
The above code is still quite slow due to the cost of the immutable copy-on-modify operations. |
||
Line 3,884: | Line 3,884: | ||
The following code implements an odds-only sieve using a mutable bit packed long array, only using a lazy sequence for the output of the resulting primes: |
The following code implements an odds-only sieve using a mutable bit packed long array, only using a lazy sequence for the output of the resulting primes: |
||
< |
<syntaxhighlight lang=clojure>(set! *unchecked-math* true) |
||
(defn primes-to |
(defn primes-to |
||
Line 3,910: | Line 3,910: | ||
(recur (inc i)))))))))] |
(recur (inc i)))))))))] |
||
(if (< n 2) nil |
(if (< n 2) nil |
||
(cons 3 (if (< n 3) nil (do (cull) (lazy-seq (nxtprm 0)))))))))</ |
(cons 3 (if (< n 3) nil (do (cull) (lazy-seq (nxtprm 0)))))))))</syntaxhighlight> |
||
The above code is about as fast as any "one large sieving array" type of program in any computer language with this level of wheel factorization other than the lazy sequence operations are quite slow: it takes about ten times as long to enumerate the results as it does to do the actual sieving work of culling the composites from the sieving buffer array. The slowness of sequence operations is due to nested function calls, but primarily due to the way Clojure implements closures by "boxing" all arguments (and perhaps return values) as objects in the heap space, which then need to be "un-boxed" as primitives as necessary for integer operations. Some of the facilities provided by lazy sequences are not needed for this algorithm, such as the automatic memoization which means that each element of the sequence is calculated only once; it is not necessary for the sequence values to be retraced for this algorithm. |
The above code is about as fast as any "one large sieving array" type of program in any computer language with this level of wheel factorization other than the lazy sequence operations are quite slow: it takes about ten times as long to enumerate the results as it does to do the actual sieving work of culling the composites from the sieving buffer array. The slowness of sequence operations is due to nested function calls, but primarily due to the way Clojure implements closures by "boxing" all arguments (and perhaps return values) as objects in the heap space, which then need to be "un-boxed" as primitives as necessary for integer operations. Some of the facilities provided by lazy sequences are not needed for this algorithm, such as the automatic memoization which means that each element of the sequence is calculated only once; it is not necessary for the sequence values to be retraced for this algorithm. |
||
Line 3,917: | Line 3,917: | ||
The following code overcomes many of those limitations by using an internal (OPSeq) "deftype" which implements the ISeq interface as well as the Counted interface to provide immediate count returns (based on a pre-computed total), as well as the IReduce interface which can greatly speed come computations based on the primes sequence (eased greatly using facilities provided by Clojure 1.7.0 and up): |
The following code overcomes many of those limitations by using an internal (OPSeq) "deftype" which implements the ISeq interface as well as the Counted interface to provide immediate count returns (based on a pre-computed total), as well as the IReduce interface which can greatly speed come computations based on the primes sequence (eased greatly using facilities provided by Clojure 1.7.0 and up): |
||
< |
<syntaxhighlight lang=clojure>(defn primes-tox |
||
"Computes lazy sequence of prime numbers up to a given number using sieve of Eratosthenes" |
"Computes lazy sequence of prime numbers up to a given number using sieve of Eratosthenes" |
||
[n] |
[n] |
||
Line 3,989: | Line 3,989: | ||
(toString [this] (if (= cnt tcnt) "()" |
(toString [this] (if (= cnt tcnt) "()" |
||
(.toString (seq (map identity this)))))) |
(.toString (seq (map identity this)))))) |
||
(->OPSeq 0 cmpsts 0 (numprms))))))))</ |
(->OPSeq 0 cmpsts 0 (numprms))))))))</syntaxhighlight> |
||
'(time (count (primes-tox 10000000)))' takes about 40 milliseconds (compiled) to produce 664579. |
'(time (count (primes-tox 10000000)))' takes about 40 milliseconds (compiled) to produce 664579. |
||
Line 4,007: | Line 4,007: | ||
'''A Clojure version of Richard Bird's Sieve using Lazy Sequences (sieves odds only)''' |
'''A Clojure version of Richard Bird's Sieve using Lazy Sequences (sieves odds only)''' |
||
< |
<syntaxhighlight lang=clojure>(defn primes-Bird |
||
"Computes the unbounded sequence of primes using a Sieve of Eratosthenes algorithm by Richard Bird." |
"Computes the unbounded sequence of primes using a Sieve of Eratosthenes algorithm by Richard Bird." |
||
[] |
[] |
||
Line 4,028: | Line 4,028: | ||
(do (def oddprms (cons 3 (lazy-seq (let [cmpsts (-> oddprms (allmtpls) (mrgmltpls))] |
(do (def oddprms (cons 3 (lazy-seq (let [cmpsts (-> oddprms (allmtpls) (mrgmltpls))] |
||
(minusStrtAt 5 cmpsts))))) |
(minusStrtAt 5 cmpsts))))) |
||
(cons 2 (lazy-seq oddprms)))))</ |
(cons 2 (lazy-seq oddprms)))))</syntaxhighlight> |
||
The above code is quite slow due to both that the data structure is a linear merging of prime multiples and due to the slowness of the Clojure sequence operations. |
The above code is quite slow due to both that the data structure is a linear merging of prime multiples and due to the slowness of the Clojure sequence operations. |
||
Line 4,035: | Line 4,035: | ||
The following code speeds up the above code by merging the linear sequence of sequences as above by pairs into a right-leaning tree structure: |
The following code speeds up the above code by merging the linear sequence of sequences as above by pairs into a right-leaning tree structure: |
||
< |
<syntaxhighlight lang=clojure>(defn primes-treeFolding |
||
"Computes the unbounded sequence of primes using a Sieve of Eratosthenes algorithm modified from Bird." |
"Computes the unbounded sequence of primes using a Sieve of Eratosthenes algorithm modified from Bird." |
||
[] |
[] |
||
Line 4,059: | Line 4,059: | ||
(do (def oddprms (cons 3 (lazy-seq (let [cmpsts (-> oddprms (allmtpls) (mrgmltpls))] |
(do (def oddprms (cons 3 (lazy-seq (let [cmpsts (-> oddprms (allmtpls) (mrgmltpls))] |
||
(minusStrtAt 5 cmpsts))))) |
(minusStrtAt 5 cmpsts))))) |
||
(cons 2 (lazy-seq oddprms)))))</ |
(cons 2 (lazy-seq oddprms)))))</syntaxhighlight> |
||
The above code is still slower than it should be due to the slowness of Clojure's sequence operations. |
The above code is still slower than it should be due to the slowness of Clojure's sequence operations. |
||
Line 4,066: | Line 4,066: | ||
The following code uses a custom "deftype" non-memoizing Co Inductive Stream/Sequence (CIS) implementing the ISeq interface to make the sequence operations more efficient and is about four times faster than the above code: |
The following code uses a custom "deftype" non-memoizing Co Inductive Stream/Sequence (CIS) implementing the ISeq interface to make the sequence operations more efficient and is about four times faster than the above code: |
||
< |
<syntaxhighlight lang=clojure>(deftype CIS [v cont] |
||
clojure.lang.ISeq |
clojure.lang.ISeq |
||
(first [_] v) |
(first [_] v) |
||
Line 4,114: | Line 4,114: | ||
(do (def oddprms (->CIS 3 (fn [] (let [cmpsts (-> oddprms (allmtpls) (mrgmltpls))] |
(do (def oddprms (->CIS 3 (fn [] (let [cmpsts (-> oddprms (allmtpls) (mrgmltpls))] |
||
(minusStrtAt 5 cmpsts))))) |
(minusStrtAt 5 cmpsts))))) |
||
(->CIS 2 (fn [] oddprms)))))</ |
(->CIS 2 (fn [] oddprms)))))</syntaxhighlight> |
||
'(time (count (take-while #(<= (long %) 10000000) (primes-treeFoldingx))))' takes about 3.4 seconds for a range of 10 million. |
'(time (count (take-while #(<= (long %) 10000000) (primes-treeFoldingx))))' takes about 3.4 seconds for a range of 10 million. |
||
Line 4,124: | Line 4,124: | ||
The following code is a version of the O'Neill Haskell code but does not use wheel factorization other than for sieving odds only (although it could be easily added) and uses a Hash Map (constant amortized access time) rather than a Priority Queue (log n access time for combined remove-and-insert-anew operations, which are the majority used for this algorithm) with a lazy sequence for output of the resulting primes; the code has the added feature that it uses a secondary base primes sequence generator and only adds prime culling sequences to the composites map when they are necessary, thus saving time and limiting storage to only that required for the map entries for primes up to the square root of the currently sieved number: |
The following code is a version of the O'Neill Haskell code but does not use wheel factorization other than for sieving odds only (although it could be easily added) and uses a Hash Map (constant amortized access time) rather than a Priority Queue (log n access time for combined remove-and-insert-anew operations, which are the majority used for this algorithm) with a lazy sequence for output of the resulting primes; the code has the added feature that it uses a secondary base primes sequence generator and only adds prime culling sequences to the composites map when they are necessary, thus saving time and limiting storage to only that required for the map entries for primes up to the square root of the currently sieved number: |
||
< |
<syntaxhighlight lang=clojure>(defn primes-hashmap |
||
"Infinite sequence of primes using an incremental Sieve or Eratosthenes with a Hashmap" |
"Infinite sequence of primes using an incremental Sieve or Eratosthenes with a Hashmap" |
||
[] |
[] |
||
Line 4,140: | Line 4,140: | ||
(cons c (lazy-seq (nxtoddprm (+ c 2) q bsprms cmpsts))))))] |
(cons c (lazy-seq (nxtoddprm (+ c 2) q bsprms cmpsts))))))] |
||
(do (def baseoddprms (cons 3 (lazy-seq (nxtoddprm 5 9 baseoddprms {})))) |
(do (def baseoddprms (cons 3 (lazy-seq (nxtoddprm 5 9 baseoddprms {})))) |
||
(cons 2 (lazy-seq (nxtoddprm 3 9 baseoddprms {}))))))</ |
(cons 2 (lazy-seq (nxtoddprm 3 9 baseoddprms {}))))))</syntaxhighlight> |
||
The above code is slower than the best tree folding version due to the added constant factor overhead of computing the hash functions for every hash map operation even though it has computational complexity of (n log log n) rather than the worse (n log n log log n) for the previous incremental tree folding sieve. It is still about 100 times slower than the sieve based on the bit-packed mutable array due to these constant factor hashing overheads. |
The above code is slower than the best tree folding version due to the added constant factor overhead of computing the hash functions for every hash map operation even though it has computational complexity of (n log log n) rather than the worse (n log n log log n) for the previous incremental tree folding sieve. It is still about 100 times slower than the sieve based on the bit-packed mutable array due to these constant factor hashing overheads. |
||
Line 4,150: | Line 4,150: | ||
In order to implement the O'Neill Priority Queue incremental Sieve of Eratosthenes algorithm, one requires an efficient implementation of a Priority Queue, which is not part of standard Clojure. For this purpose, the most suitable Priority Queue is a binary tree heap based MinHeap algorithm. The following code implements a purely functional (using entirely immutable state) MinHeap Priority Queue providing the required functions of (emtpy-pq) initialization, (getMin-pq pq) to examinte the minimum key/value pair in the queue, (insert-pq pq k v) to add entries to the queue, and (replaceMinAs-pq pq k v) to replaace the minimum entry with a key/value pair as given (it is more efficient that if functions were provided to delete and then re-insert entries in the queue; there is therefore no "delete" or other queue functions supplied as the algorithm does not requrie them: |
In order to implement the O'Neill Priority Queue incremental Sieve of Eratosthenes algorithm, one requires an efficient implementation of a Priority Queue, which is not part of standard Clojure. For this purpose, the most suitable Priority Queue is a binary tree heap based MinHeap algorithm. The following code implements a purely functional (using entirely immutable state) MinHeap Priority Queue providing the required functions of (emtpy-pq) initialization, (getMin-pq pq) to examinte the minimum key/value pair in the queue, (insert-pq pq k v) to add entries to the queue, and (replaceMinAs-pq pq k v) to replaace the minimum entry with a key/value pair as given (it is more efficient that if functions were provided to delete and then re-insert entries in the queue; there is therefore no "delete" or other queue functions supplied as the algorithm does not requrie them: |
||
< |
<syntaxhighlight lang=clojure>(deftype PQEntry [k, v] |
||
Object |
Object |
||
(toString [_] (str "<" k "," v ">"))) |
(toString [_] (str "<" k "," v ">"))) |
||
Line 4,195: | Line 4,195: | ||
(if (<= kl kr) |
(if (<= kl kr) |
||
(recur l #(cont (->PQNode kvl % r))) |
(recur l #(cont (->PQNode kvl % r))) |
||
(recur r #(cont (->PQNode kvr l %))))))))))))</ |
(recur r #(cont (->PQNode kvr l %))))))))))))</syntaxhighlight> |
||
Note that the above code is written partially using continuation passing style so as to leave the "recur" calls in tail call position as required for efficient looping in Clojure; for practical sieving ranges, the algorithm could likely use just raw function recursion as recursion depth is unlikely to be used beyond a depth of about ten or so, but raw recursion is said to be less code efficient. |
Note that the above code is written partially using continuation passing style so as to leave the "recur" calls in tail call position as required for efficient looping in Clojure; for practical sieving ranges, the algorithm could likely use just raw function recursion as recursion depth is unlikely to be used beyond a depth of about ten or so, but raw recursion is said to be less code efficient. |
||
Line 4,201: | Line 4,201: | ||
The actual incremental sieve using the Priority Queue is as follows, which code uses the same optimizations of postponing the addition of prime composite streams to the queue until the square root of the currently sieved number is reached and using a secondary base primes stream to generate the primes composite stream markers in the queue as was used for the Hash Map version: |
The actual incremental sieve using the Priority Queue is as follows, which code uses the same optimizations of postponing the addition of prime composite streams to the queue until the square root of the currently sieved number is reached and using a secondary base primes stream to generate the primes composite stream markers in the queue as was used for the Hash Map version: |
||
< |
<syntaxhighlight lang=clojure>(defn primes-pq |
||
"Infinite sequence of primes using an incremental Sieve or Eratosthenes with a Priority Queue" |
"Infinite sequence of primes using an incremental Sieve or Eratosthenes with a Priority Queue" |
||
[] |
[] |
||
Line 4,219: | Line 4,219: | ||
(cons c (lazy-seq (nxtoddprm (+ c 2) q bsprms cmpsts)))))))] |
(cons c (lazy-seq (nxtoddprm (+ c 2) q bsprms cmpsts)))))))] |
||
(do (def baseoddprms (cons 3 (lazy-seq (nxtoddprm 5 9 baseoddprms (empty-pq))))) |
(do (def baseoddprms (cons 3 (lazy-seq (nxtoddprm 5 9 baseoddprms (empty-pq))))) |
||
(cons 2 (lazy-seq (nxtoddprm 3 9 baseoddprms (empty-pq)))))))</ |
(cons 2 (lazy-seq (nxtoddprm 3 9 baseoddprms (empty-pq)))))))</syntaxhighlight> |
||
The above code is faster than the Hash Map version up to about a sieving range of fifteen million or so, but gets progressively slower for larger ranges due to having (n log n log log n) computational complexity rather than the (n log log n) for the Hash Map version, which has a higher constant factor overhead that is overtaken by the extra "log n" factor. |
The above code is faster than the Hash Map version up to about a sieving range of fifteen million or so, but gets progressively slower for larger ranges due to having (n log n log log n) computational complexity rather than the (n log log n) for the Hash Map version, which has a higher constant factor overhead that is overtaken by the extra "log n" factor. |
||
Line 4,235: | Line 4,235: | ||
To show that Clojure does not need to be particularly slow, the following version runs about twice as fast as the non-segmented unbounded array based version above (extremely fast compared to the non-array based versions) and only a little slower than other equivalent versions running on virtual machines: C# or F# on DotNet or Java and Scala on the JVM: |
To show that Clojure does not need to be particularly slow, the following version runs about twice as fast as the non-segmented unbounded array based version above (extremely fast compared to the non-array based versions) and only a little slower than other equivalent versions running on virtual machines: C# or F# on DotNet or Java and Scala on the JVM: |
||
< |
<syntaxhighlight lang=clojure>(set! *unchecked-math* true) |
||
(def PGSZ (bit-shift-left 1 14)) ;; size of CPU cache |
(def PGSZ (bit-shift-left 1 14)) ;; size of CPU cache |
||
Line 4,382: | Line 4,382: | ||
(next pgseq) |
(next pgseq) |
||
(+ cnt (count-pg PGBTS pg))))))] |
(+ cnt (count-pg PGBTS pg))))))] |
||
(nxt-pg 0 (primes-pages) 1))))</ |
(nxt-pg 0 (primes-pages) 1))))</syntaxhighlight> |
||
The above code runs just as fast as other virtual machine languages when run on a 64-bit JVM; however, when run on a 32-bit JVM it runs almost five times slower. This is likely due to Clojure only using 64-bit integers for integer operations and these operations getting JIT compiled to use library functions to simulate those operations using combined 32-bit operations under a 32-bit JVM whereas direct CPU operations can be used on a 64-bit JVM |
The above code runs just as fast as other virtual machine languages when run on a 64-bit JVM; however, when run on a 32-bit JVM it runs almost five times slower. This is likely due to Clojure only using 64-bit integers for integer operations and these operations getting JIT compiled to use library functions to simulate those operations using combined 32-bit operations under a 32-bit JVM whereas direct CPU operations can be used on a 64-bit JVM |
||
Line 4,395: | Line 4,395: | ||
=={{header|CLU}}== |
=={{header|CLU}}== |
||
< |
<syntaxhighlight lang=clu>% Sieve of Eratosthenes |
||
eratosthenes = proc (n: int) returns (array[bool]) |
eratosthenes = proc (n: int) returns (array[bool]) |
||
prime: array[bool] := array[bool]$fill(1, n, true) |
prime: array[bool] := array[bool]$fill(1, n, true) |
||
Line 4,426: | Line 4,426: | ||
end |
end |
||
end |
end |
||
end start_up</ |
end start_up</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 2 3 5 7 11 13 17 19 23 29 |
<pre> 2 3 5 7 11 13 17 19 23 29 |
||
Line 4,447: | Line 4,447: | ||
=={{header|CMake}}== |
=={{header|CMake}}== |
||
< |
<syntaxhighlight lang=cmake>function(eratosthenes var limit) |
||
# Check for integer overflow. With CMake using 32-bit signed integer, |
# Check for integer overflow. With CMake using 32-bit signed integer, |
||
# this check fails when limit > 46340. |
# this check fails when limit > 46340. |
||
Line 4,481: | Line 4,481: | ||
endforeach(i) |
endforeach(i) |
||
set(${var} ${list} PARENT_SCOPE) |
set(${var} ${list} PARENT_SCOPE) |
||
endfunction(eratosthenes)</ |
endfunction(eratosthenes)</syntaxhighlight> |
||
# Print all prime numbers through 100. |
# Print all prime numbers through 100. |
||
eratosthenes(primes 100) |
eratosthenes(primes 100) |
||
Line 4,487: | Line 4,487: | ||
=={{header|COBOL}}== |
=={{header|COBOL}}== |
||
< |
<syntaxhighlight lang=cobol>*> Please ignore the asterisks in the first column of the next comments, |
||
*> which are kludges to get syntax highlighting to work. |
*> which are kludges to get syntax highlighting to work. |
||
IDENTIFICATION DIVISION. |
IDENTIFICATION DIVISION. |
||
Line 4,541: | Line 4,541: | ||
GOBACK |
GOBACK |
||
.</ |
.</syntaxhighlight> |
||
=={{header|Comal}}== |
=={{header|Comal}}== |
||
{{trans|BASIC}} |
{{trans|BASIC}} |
||
< |
<syntaxhighlight lang=comal>// Sieve of Eratosthenes |
||
input "Limit? ": limit |
input "Limit? ": limit |
||
dim sieve(1:limit) |
dim sieve(1:limit) |
||
Line 4,568: | Line 4,568: | ||
endif |
endif |
||
endfor i |
endfor i |
||
print</ |
print</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
Line 4,580: | Line 4,580: | ||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
< |
<syntaxhighlight lang=lisp>(defun sieve-of-eratosthenes (maximum) |
||
(loop |
(loop |
||
with sieve = (make-array (1+ maximum) |
with sieve = (make-array (1+ maximum) |
||
Line 4,590: | Line 4,590: | ||
and do (loop for composite from (expt candidate 2) |
and do (loop for composite from (expt candidate 2) |
||
to maximum by candidate |
to maximum by candidate |
||
do (setf (bit sieve composite) 1))))</ |
do (setf (bit sieve composite) 1))))</syntaxhighlight> |
||
Working with odds only (above twice speedup), and marking composites only for primes up to the square root of the maximum: |
Working with odds only (above twice speedup), and marking composites only for primes up to the square root of the maximum: |
||
< |
<syntaxhighlight lang=lisp>(defun sieve-odds (maximum) |
||
"Prime numbers sieve for odd numbers. |
"Prime numbers sieve for odd numbers. |
||
Returns a list with all the primes that are less than or equal to maximum." |
Returns a list with all the primes that are less than or equal to maximum." |
||
Line 4,607: | Line 4,607: | ||
:do (loop :for j :from (* i (1+ i) 2) :to maxi :by odd-number |
:do (loop :for j :from (* i (1+ i) 2) :to maxi :by odd-number |
||
:do (setf (sbit sieve j) 1)) |
:do (setf (sbit sieve j) 1)) |
||
:finally (return (cons 2 values))))</ |
:finally (return (cons 2 values))))</syntaxhighlight> |
||
The indexation scheme used here interprets each index <code>i</code> as standing for the value <code>2i+1</code>. Bit <code>0</code> is unused, a small price to pay for the simpler index calculations compared with the <code>2i+3</code> indexation scheme. The multiples of a given odd prime <code>p</code> are enumerated in increments of <code>2p</code>, which corresponds to the index increment of <code>p</code> on the sieve array. The starting point <code>p*p = (2i+1)(2i+1) = 4i(i+1)+1</code> corresponds to the index <code>2i(i+1)</code>. |
The indexation scheme used here interprets each index <code>i</code> as standing for the value <code>2i+1</code>. Bit <code>0</code> is unused, a small price to pay for the simpler index calculations compared with the <code>2i+3</code> indexation scheme. The multiples of a given odd prime <code>p</code> are enumerated in increments of <code>2p</code>, which corresponds to the index increment of <code>p</code> on the sieve array. The starting point <code>p*p = (2i+1)(2i+1) = 4i(i+1)+1</code> corresponds to the index <code>2i(i+1)</code>. |
||
Line 4,614: | Line 4,614: | ||
=={{header|Cowgol}}== |
=={{header|Cowgol}}== |
||
< |
<syntaxhighlight lang=cowgol>include "cowgol.coh"; |
||
# To change the maximum prime, change the size of this array |
# To change the maximum prime, change the size of this array |
||
Line 4,644: | Line 4,644: | ||
end if; |
end if; |
||
cand := cand + 1; |
cand := cand + 1; |
||
end loop;</ |
end loop;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 4,665: | Line 4,665: | ||
This implementation uses a `BitArray` so it is automatically bit-packed to use just one bit per number representation: |
This implementation uses a `BitArray` so it is automatically bit-packed to use just one bit per number representation: |
||
< |
<syntaxhighlight lang=ruby># compile with `--release --no-debug` for speed... |
||
require "bit_array" |
require "bit_array" |
||
Line 4,714: | Line 4,714: | ||
print SoE.new(1_000_000_000).each.size |
print SoE.new(1_000_000_000).each.size |
||
elpsd = (Time.monotonic - start_time).total_milliseconds |
elpsd = (Time.monotonic - start_time).total_milliseconds |
||
puts " in #{elpsd} milliseconds."</ |
puts " in #{elpsd} milliseconds."</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 4,727: | Line 4,727: | ||
the non-odds-only version as per the above should never be used because in not using odds-only, it uses twice the memory and over two and a half times the CPU operations as the following odds-only code, which is very little more complex: |
the non-odds-only version as per the above should never be used because in not using odds-only, it uses twice the memory and over two and a half times the CPU operations as the following odds-only code, which is very little more complex: |
||
< |
<syntaxhighlight lang=ruby># compile with `--release --no-debug` for speed... |
||
require "bit_array" |
require "bit_array" |
||
Line 4,779: | Line 4,779: | ||
print SoE_Odds.new(1_000_000_000).each.size |
print SoE_Odds.new(1_000_000_000).each.size |
||
elpsd = (Time.monotonic - start_time).total_milliseconds |
elpsd = (Time.monotonic - start_time).total_milliseconds |
||
puts " in #{elpsd} milliseconds."</ |
puts " in #{elpsd} milliseconds."</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 4,792: | Line 4,792: | ||
For sieving of ranges larger than a few million efficiently, a page-segmented sieve should always be used to preserve CPU cache associativity by making the page size to be about that of the CPU L1 data cache. The following code implements a page-segmented version that is an extensible sieve (no upper limit needs be specified) using a secondary memoized feed of base prime value arrays which use a smaller page-segment size for efficiency. When the count of the number of primes is desired, the sieve is polymorphic in output and counts the unmarked composite bits by using fast `popcount` instructions taken 64-bits at a time. The code is as follows: |
For sieving of ranges larger than a few million efficiently, a page-segmented sieve should always be used to preserve CPU cache associativity by making the page size to be about that of the CPU L1 data cache. The following code implements a page-segmented version that is an extensible sieve (no upper limit needs be specified) using a secondary memoized feed of base prime value arrays which use a smaller page-segment size for efficiency. When the count of the number of primes is desired, the sieve is polymorphic in output and counts the unmarked composite bits by using fast `popcount` instructions taken 64-bits at a time. The code is as follows: |
||
< |
<syntaxhighlight lang=ruby># compile with `--release --no-debug` for speed... |
||
alias Prime = UInt64 |
alias Prime = UInt64 |
||
Line 4,994: | Line 4,994: | ||
answr = primes_count_to(1_000_000_000) # fast way |
answr = primes_count_to(1_000_000_000) # fast way |
||
elpsd = (Time.monotonic - start_time).total_milliseconds |
elpsd = (Time.monotonic - start_time).total_milliseconds |
||
print "#{answr} in #{elpsd} milliseconds.\r\n"</ |
print "#{answr} in #{elpsd} milliseconds.\r\n"</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 5,007: | Line 5,007: | ||
=={{header|D}}== |
=={{header|D}}== |
||
===Simpler Version=== |
===Simpler Version=== |
||
Prints all numbers less than the limit.< |
Prints all numbers less than the limit.<syntaxhighlight lang=d>import std.stdio, std.algorithm, std.range, std.functional; |
||
uint[] sieve(in uint limit) nothrow @safe { |
uint[] sieve(in uint limit) nothrow @safe { |
||
Line 5,025: | Line 5,025: | ||
void main() { |
void main() { |
||
50.sieve.writeln; |
50.sieve.writeln; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]</pre> |
<pre>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]</pre> |
||
Line 5,031: | Line 5,031: | ||
===Faster Version=== |
===Faster Version=== |
||
This version uses an array of bits (instead of booleans, that are represented with one byte), and skips even numbers. The output is the same. |
This version uses an array of bits (instead of booleans, that are represented with one byte), and skips even numbers. The output is the same. |
||
< |
<syntaxhighlight lang=d>import std.stdio, std.math, std.array; |
||
size_t[] sieve(in size_t m) pure nothrow @safe { |
size_t[] sieve(in size_t m) pure nothrow @safe { |
||
Line 5,069: | Line 5,069: | ||
void main() { |
void main() { |
||
50.sieve.writeln; |
50.sieve.writeln; |
||
}</ |
}</syntaxhighlight> |
||
===Extensible Version=== |
===Extensible Version=== |
||
(This version is used in the task [[Extensible prime generator#D|Extensible prime generator]].) |
(This version is used in the task [[Extensible prime generator#D|Extensible prime generator]].) |
||
< |
<syntaxhighlight lang=d>/// Extensible Sieve of Eratosthenes. |
||
struct Prime { |
struct Prime { |
||
uint[] a = [2]; |
uint[] a = [2]; |
||
Line 5,107: | Line 5,107: | ||
uint.max.iota.map!prime.until!q{a > 50}.writeln; |
uint.max.iota.map!prime.until!q{a > 50}.writeln; |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
To see the output (that is the same), compile with <code>-version=sieve_of_eratosthenes3_main</code>. |
To see the output (that is the same), compile with <code>-version=sieve_of_eratosthenes3_main</code>. |
||
=={{header|Dart}}== |
=={{header|Dart}}== |
||
< |
<syntaxhighlight lang=dart>// helper function to pretty print an Iterable |
||
String iterableToString(Iterable seq) { |
String iterableToString(Iterable seq) { |
||
String str = "["; |
String str = "["; |
||
Line 5,143: | Line 5,143: | ||
print(iterableToString(sortedValues)); // expect sieve.length to be 168 up to 1000... |
print(iterableToString(sortedValues)); // expect sieve.length to be 168 up to 1000... |
||
// Expect.equals(168, sieve.length); |
// Expect.equals(168, sieve.length); |
||
}</ |
}</syntaxhighlight> |
||
{{out}}<pre> |
{{out}}<pre> |
||
Found 168 primes up to 1000 in 9 milliseconds. |
Found 168 primes up to 1000 in 9 milliseconds. |
||
Line 5,151: | Line 5,151: | ||
===faster bit-packed array odds-only solution=== |
===faster bit-packed array odds-only solution=== |
||
< |
<syntaxhighlight lang=dart>import 'dart:typed_data'; |
||
import 'dart:math'; |
import 'dart:math'; |
||
Line 5,183: | Line 5,183: | ||
print("There were $answer primes found up to $range."); |
print("There were $answer primes found up to $range."); |
||
print("This test bench took $elapsed milliseconds."); |
print("This test bench took $elapsed milliseconds."); |
||
}</ |
}</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>( 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ) |
<pre>( 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ) |
||
Line 5,198: | Line 5,198: | ||
The following code will have about O(n log (log n)) performance due to a hash table having O(1) average performance and is only somewhat slow due to the constant overhead of processing hashes: |
The following code will have about O(n log (log n)) performance due to a hash table having O(1) average performance and is only somewhat slow due to the constant overhead of processing hashes: |
||
< |
<syntaxhighlight lang=dart>Iterable<int> primesMap() { |
||
Iterable<int> oddprms() sync* { |
Iterable<int> oddprms() sync* { |
||
yield(3); yield(5); // need at least 2 for initialization |
yield(3); yield(5); // need at least 2 for initialization |
||
Line 5,240: | Line 5,240: | ||
print("There were $answer primes found up to $range."); |
print("There were $answer primes found up to $range."); |
||
print("This test bench took $elapsed milliseconds."); |
print("This test bench took $elapsed milliseconds."); |
||
}</ |
}</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>( 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ) |
<pre>( 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ) |
||
Line 5,256: | Line 5,256: | ||
{{trans|Kotlin}} |
{{trans|Kotlin}} |
||
< |
<syntaxhighlight lang=dart>import 'dart:typed_data'; |
||
import 'dart:math'; |
import 'dart:math'; |
||
import 'dart:collection'; |
import 'dart:collection'; |
||
Line 5,464: | Line 5,464: | ||
print("There were $answer primes found up to $range."); |
print("There were $answer primes found up to $range."); |
||
print("This test bench took $elapsed milliseconds."); |
print("This test bench took $elapsed milliseconds."); |
||
}</ |
}</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>( 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ) |
<pre>( 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ) |
||
Line 5,478: | Line 5,478: | ||
=={{header|Delphi}}== |
=={{header|Delphi}}== |
||
< |
<syntaxhighlight lang=delphi>program erathostenes; |
||
{$APPTYPE CONSOLE} |
{$APPTYPE CONSOLE} |
||
Line 5,562: | Line 5,562: | ||
Sieve.Free; |
Sieve.Free; |
||
readln; |
readln; |
||
end.</ |
end.</syntaxhighlight> |
||
Output: |
Output: |
||
<pre>2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 </pre> |
<pre>2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 </pre> |
||
=={{header|Draco}}== |
=={{header|Draco}}== |
||
< |
<syntaxhighlight lang=draco>/* Sieve of Eratosthenes - fill a given boolean array */ |
||
proc nonrec sieve([*] bool prime) void: |
proc nonrec sieve([*] bool prime) void: |
||
word p, c, max; |
word p, c, max; |
||
Line 5,599: | Line 5,599: | ||
fi |
fi |
||
od |
od |
||
corp</ |
corp</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 2 3 5 7 11 13 17 19 23 29 |
<pre> 2 3 5 7 11 13 17 19 23 29 |
||
Line 5,621: | Line 5,621: | ||
=={{header|DWScript}}== |
=={{header|DWScript}}== |
||
< |
<syntaxhighlight lang=delphi>function Primes(limit : Integer) : array of Integer; |
||
var |
var |
||
n, k : Integer; |
n, k : Integer; |
||
Line 5,641: | Line 5,641: | ||
var i : Integer; |
var i : Integer; |
||
for i:=0 to r.High do |
for i:=0 to r.High do |
||
PrintLn(r[i]);</ |
PrintLn(r[i]);</syntaxhighlight> |
||
=={{header|Dylan}}== |
=={{header|Dylan}}== |
||
With outer to sqrt and inner to p^2 optimizations: |
With outer to sqrt and inner to p^2 optimizations: |
||
< |
<syntaxhighlight lang=dylan>define method primes(n) |
||
let limit = floor(n ^ 0.5) + 1; |
let limit = floor(n ^ 0.5) + 1; |
||
let sieve = make(limited(<simple-vector>, of: <boolean>), size: n + 1, fill: #t); |
let sieve = make(limited(<simple-vector>, of: <boolean>), size: n + 1, fill: #t); |
||
Line 5,668: | Line 5,668: | ||
if (sieve[x]) format-out("Prime: %d\n", x); end; |
if (sieve[x]) format-out("Prime: %d\n", x); end; |
||
end; |
end; |
||
end;</ |
end;</syntaxhighlight> |
||
=={{header|E}}== |
=={{header|E}}== |
||
Line 5,725: | Line 5,725: | ||
. |
. |
||
i += 1 |
i += 1 |
||
.</ |
.</syntaxhighlight> |
||
=={{header|eC}}== |
=={{header|eC}}== |
||
{{incorrect|eC|It uses rem testing and so is a trial division algorithm, not a sieve of Eratosthenes.}} |
{{incorrect|eC|It uses rem testing and so is a trial division algorithm, not a sieve of Eratosthenes.}} |
||
Note: this is not a Sieve of Eratosthenes; it is just trial division. |
Note: this is not a Sieve of Eratosthenes; it is just trial division. |
||
< |
<syntaxhighlight lang=cpp> |
||
public class FindPrime |
public class FindPrime |
||
{ |
{ |
||
Line 5,774: | Line 5,774: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|EchoLisp}}== |
=={{header|EchoLisp}}== |
||
===Sieve=== |
===Sieve=== |
||
< |
<syntaxhighlight lang=lisp>(require 'types) ;; bit-vector |
||
;; converts sieve->list for integers in [nmin .. nmax[ |
;; converts sieve->list for integers in [nmin .. nmax[ |
||
Line 5,807: | Line 5,807: | ||
→ (1000003 1000033 1000037 1000039 1000081 1000099) |
→ (1000003 1000033 1000037 1000039 1000081 1000099) |
||
(s-next-prime s-primes 9_000_000) |
(s-next-prime s-primes 9_000_000) |
||
→ 9000011</ |
→ 9000011</syntaxhighlight> |
||
===Segmented sieve=== |
===Segmented sieve=== |
||
Allow to extend the basis sieve (n) up to n^2. Memory requirement is O(√n) |
Allow to extend the basis sieve (n) up to n^2. Memory requirement is O(√n) |
||
< |
<syntaxhighlight lang=scheme>;; ref : http://research.cs.wisc.edu/techreports/1990/TR909.pdf |
||
;; delta multiple of sqrt(n) |
;; delta multiple of sqrt(n) |
||
;; segment is [left .. left+delta-1] |
;; segment is [left .. left+delta-1] |
||
Line 5,844: | Line 5,844: | ||
;; 8 msec using the native (prime?) function |
;; 8 msec using the native (prime?) function |
||
(for/list ((p (in-range 1_000_000_000 1_000_001_000))) #:when (prime? p) p)</ |
(for/list ((p (in-range 1_000_000_000 1_000_001_000))) #:when (prime? p) p)</syntaxhighlight> |
||
===Wheel=== |
===Wheel=== |
||
A 2x3 wheel gives a 50% performance gain. |
A 2x3 wheel gives a 50% performance gain. |
||
< |
<syntaxhighlight lang=scheme>;; 2x3 wheel |
||
(define (weratosthenes n) |
(define (weratosthenes n) |
||
(define primes (make-bit-vector n )) ;; everybody to #f (false) |
(define primes (make-bit-vector n )) ;; everybody to #f (false) |
||
Line 5,864: | Line 5,864: | ||
(for ([j (in-range (* p p) n p)]) |
(for ([j (in-range (* p p) n p)]) |
||
(bit-vector-set! primes j #f))) |
(bit-vector-set! primes j #f))) |
||
primes)</ |
primes)</syntaxhighlight> |
||
=={{header|EDSAC order code}}== |
=={{header|EDSAC order code}}== |
||
Line 5,872: | Line 5,872: | ||
On the EdsacPC simulator (see link above) the printout starts off very slowly, and gradually gets faster. |
On the EdsacPC simulator (see link above) the printout starts off very slowly, and gradually gets faster. |
||
< |
<syntaxhighlight lang=edsac> |
||
[Sieve of Eratosthenes] |
[Sieve of Eratosthenes] |
||
[EDSAC program. Initial Orders 2] |
[EDSAC program. Initial Orders 2] |
||
Line 6,093: | Line 6,093: | ||
E 19 Z [address to start execution] |
E 19 Z [address to start execution] |
||
P F [acc = 0 at start] |
P F [acc = 0 at start] |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,117: | Line 6,117: | ||
=={{header|Eiffel}}== |
=={{header|Eiffel}}== |
||
{{works with|EiffelStudio|6.6 beta (with provisional loop syntax)}} |
{{works with|EiffelStudio|6.6 beta (with provisional loop syntax)}} |
||
< |
<syntaxhighlight lang=eiffel>class |
||
APPLICATION |
APPLICATION |
||
Line 6,151: | Line 6,151: | ||
end |
end |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
Output: |
Output: |
||
Line 6,159: | Line 6,159: | ||
=={{header|Elixir}}== |
=={{header|Elixir}}== |
||
< |
<syntaxhighlight lang=elixir>defmodule Prime do |
||
def eratosthenes(limit \\ 1000) do |
def eratosthenes(limit \\ 1000) do |
||
sieve = [false, false | Enum.to_list(2..limit)] |> List.to_tuple |
sieve = [false, false | Enum.to_list(2..limit)] |> List.to_tuple |
||
Line 6,183: | Line 6,183: | ||
if x=elem(sieve, n), do: :io.format("~3w", [x]), else: :io.format(" .") |
if x=elem(sieve, n), do: :io.format("~3w", [x]), else: :io.format(" .") |
||
if rem(n+1, 20)==0, do: IO.puts "" |
if rem(n+1, 20)==0, do: IO.puts "" |
||
end)</ |
end)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 6,201: | Line 6,201: | ||
Shorter version (but slow): |
Shorter version (but slow): |
||
< |
<syntaxhighlight lang=elixir> |
||
defmodule Sieve do |
defmodule Sieve do |
||
def primes_to(limit), do: sieve(Enum.to_list(2..limit)) |
def primes_to(limit), do: sieve(Enum.to_list(2..limit)) |
||
Line 6,208: | Line 6,208: | ||
defp sieve([]), do: [] |
defp sieve([]), do: [] |
||
end |
end |
||
</syntaxhighlight> |
|||
</lang> |
|||
'''Alternate much faster odds-only version more suitable for immutable data structures using a (hash) Map''' |
'''Alternate much faster odds-only version more suitable for immutable data structures using a (hash) Map''' |
||
The above code has a very limited useful range due to being very slow: for example, to sieve to a million, even changing the algorithm to odds-only, requires over 800 thousand "copy-on-update" operations of the entire saved immutable tuple ("array") of 500 thousand bytes in size, making it very much a "toy" application. The following code overcomes that problem by using a (immutable/hashed) Map to store the record of the current state of the composite number chains resulting from each of the secondary streams of base primes, which are only 167 in number up to this range; it is a functional "incremental" Sieve of Eratosthenes implementation: |
The above code has a very limited useful range due to being very slow: for example, to sieve to a million, even changing the algorithm to odds-only, requires over 800 thousand "copy-on-update" operations of the entire saved immutable tuple ("array") of 500 thousand bytes in size, making it very much a "toy" application. The following code overcomes that problem by using a (immutable/hashed) Map to store the record of the current state of the composite number chains resulting from each of the secondary streams of base primes, which are only 167 in number up to this range; it is a functional "incremental" Sieve of Eratosthenes implementation: |
||
< |
<syntaxhighlight lang=elixir>defmodule PrimesSoEMap do |
||
@typep stt :: {integer, integer, integer, Enumerable.integer, %{integer => integer}} |
@typep stt :: {integer, integer, integer, Enumerable.integer, %{integer => integer}} |
||
Line 6,265: | Line 6,265: | ||
|> (fn {t,ans} -> |
|> (fn {t,ans} -> |
||
IO.puts "There are #{ans} primes up to #{range}." |
IO.puts "There are #{ans} primes up to #{range}." |
||
IO.puts "This test bench took #{t} microseconds." end).()</ |
IO.puts "This test bench took #{t} microseconds." end).()</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>The first 25 primes are: |
<pre>The first 25 primes are: |
||
Line 6,279: | Line 6,279: | ||
In order to save the computation time of computing the hashes, the following version uses a deferred execution Co-Inductive Stream type (constructed using Tuple's) in an infinite tree folding structure (by the `pairs` function): |
In order to save the computation time of computing the hashes, the following version uses a deferred execution Co-Inductive Stream type (constructed using Tuple's) in an infinite tree folding structure (by the `pairs` function): |
||
< |
<syntaxhighlight lang=elixir>defmodule PrimesSoETreeFolding do |
||
@typep cis :: {integer, (() -> cis)} |
@typep cis :: {integer, (() -> cis)} |
||
@typep ciss :: {cis, (() -> ciss)} |
@typep ciss :: {cis, (() -> ciss)} |
||
Line 6,359: | Line 6,359: | ||
|> (fn {t,ans} -> |
|> (fn {t,ans} -> |
||
IO.puts "There are #{ans} primes up to #{range}." |
IO.puts "There are #{ans} primes up to #{range}." |
||
IO.puts "This test bench took #{t} microseconds." end).()</ |
IO.puts "This test bench took #{t} microseconds." end).()</syntaxhighlight> |
||
It's output is identical to the previous version other than the time required is less than half; however, it has a O(n (log n) (log (log n))) asymptotic computation complexity meaning that it gets slower with range faster than the above version. That said, it would take sieving to billions taking hours before the two would take about the same time. |
It's output is identical to the previous version other than the time required is less than half; however, it has a O(n (log n) (log (log n))) asymptotic computation complexity meaning that it gets slower with range faster than the above version. That said, it would take sieving to billions taking hours before the two would take about the same time. |
||
Line 6,367: | Line 6,367: | ||
The Elm language doesn't handle efficiently doing the Sieve of Eratosthenes (SoE) algorithm efficiently because it doesn't have directly accessible linear arrays and also does Copy On Write (COW) for every write to every location as well as a logarithmic process of updating as a "tree" to minimize the COW operations. Thus, there is better performance implementing the Richard Bird Tree Folding functional algorithm, as follows: |
The Elm language doesn't handle efficiently doing the Sieve of Eratosthenes (SoE) algorithm efficiently because it doesn't have directly accessible linear arrays and also does Copy On Write (COW) for every write to every location as well as a logarithmic process of updating as a "tree" to minimize the COW operations. Thus, there is better performance implementing the Richard Bird Tree Folding functional algorithm, as follows: |
||
{{trans|Haskell}} |
{{trans|Haskell}} |
||
< |
<syntaxhighlight lang=elm>module Main exposing (main) |
||
import Browser exposing (element) |
import Browser exposing (element) |
||
Line 6,456: | Line 6,456: | ||
, update = myupdate |
, update = myupdate |
||
, subscriptions = \ _ -> Sub.none |
, subscriptions = \ _ -> Sub.none |
||
, view = myview }</ |
, view = myview }</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>The primes up to 100 are: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97. |
<pre>The primes up to 100 are: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97. |
||
Line 6,465: | Line 6,465: | ||
Using a Binary Minimum Heap Priority Queue is a constant factor faster than the above code as the data structure is balanced rather than "heavy to the right" in the following code, which implements enough of the Priority Queue for the purpose: |
Using a Binary Minimum Heap Priority Queue is a constant factor faster than the above code as the data structure is balanced rather than "heavy to the right" in the following code, which implements enough of the Priority Queue for the purpose: |
||
< |
<syntaxhighlight lang=elm>module Main exposing ( main ) |
||
import Task exposing ( Task, succeed, perform, andThen ) |
import Task exposing ( Task, succeed, perform, andThen ) |
||
Line 6,589: | Line 6,589: | ||
, update = myupdate |
, update = myupdate |
||
, subscriptions = \ _ -> Sub.none |
, subscriptions = \ _ -> Sub.none |
||
, view = myview }</ |
, view = myview }</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>The primes up to 100 are: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97. |
<pre>The primes up to 100 are: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97. |
||
Line 6,596: | Line 6,596: | ||
=={{header|Emacs Lisp}}== |
=={{header|Emacs Lisp}}== |
||
{{libheader|cl-lib}} |
{{libheader|cl-lib}} |
||
< |
<syntaxhighlight lang=lisp>(defun sieve-set (limit) |
||
(let ((xs (make-vector (1+ limit) 0))) |
(let ((xs (make-vector (1+ limit) 0))) |
||
(cl-loop for i from 2 to limit |
(cl-loop for i from 2 to limit |
||
Line 6,602: | Line 6,602: | ||
collect i |
collect i |
||
and do (cl-loop for m from (* i i) to limit by i |
and do (cl-loop for m from (* i i) to limit by i |
||
do (aset xs m 1)))))</ |
do (aset xs m 1)))))</syntaxhighlight> |
||
Straightforward implementation of [http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Implementation sieve of Eratosthenes], 2 times faster: |
Straightforward implementation of [http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Implementation sieve of Eratosthenes], 2 times faster: |
||
< |
<syntaxhighlight lang=lisp>(defun sieve (limit) |
||
(let ((xs (vconcat [0 0] (number-sequence 2 limit)))) |
(let ((xs (vconcat [0 0] (number-sequence 2 limit)))) |
||
(cl-loop for i from 2 to (sqrt limit) |
(cl-loop for i from 2 to (sqrt limit) |
||
Line 6,612: | Line 6,612: | ||
do (cl-loop for m from (* i i) to limit by i |
do (cl-loop for m from (* i i) to limit by i |
||
do (aset xs m 0))) |
do (aset xs m 0))) |
||
(remove 0 xs)))</ |
(remove 0 xs)))</syntaxhighlight> |
||
=={{header|Erlang}}== |
=={{header|Erlang}}== |
||
===Erlang using Dicts=== |
===Erlang using Dicts=== |
||
< |
<syntaxhighlight lang=Erlang> |
||
-module( sieve_of_eratosthenes ). |
-module( sieve_of_eratosthenes ). |
||
Line 6,636: | Line 6,636: | ||
{Max, lists:foldl( fun dict:erase/2, Dict, lists:seq(N*N, Max, N))}; |
{Max, lists:foldl( fun dict:erase/2, Dict, lists:seq(N*N, Max, N))}; |
||
find_prime( {ok, _Value}, _, R) -> R. |
find_prime( {ok, _Value}, _, R) -> R. |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,648: | Line 6,648: | ||
Has the virtue of working for any -> N :) |
Has the virtue of working for any -> N :) |
||
< |
<syntaxhighlight lang=Erlang> |
||
-module( sieve ). |
-module( sieve ). |
||
-export( [main/1,primes/2] ). |
-export( [main/1,primes/2] ). |
||
Line 6,682: | Line 6,682: | ||
Primes = lists:filter( fun({_,Y}) -> Y > 0 end, Tuples), |
Primes = lists:filter( fun({_,Y}) -> Y > 0 end, Tuples), |
||
[ X || {X,_} <- Primes ]. |
[ X || {X,_} <- Primes ]. |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,696: | Line 6,696: | ||
Since I had written a really odd and slow one, I thought I'd best do a better performer. Inspired by an example from https://github.com/jupp0r |
Since I had written a really odd and slow one, I thought I'd best do a better performer. Inspired by an example from https://github.com/jupp0r |
||
< |
<syntaxhighlight lang=Erlang> |
||
-module(ossieve). |
-module(ossieve). |
||
Line 6,722: | Line 6,722: | ||
ResultSet = ordsets:add_element(2,sieve(Candidates,Candidates,ordsets:new(),N)), |
ResultSet = ordsets:add_element(2,sieve(Candidates,Candidates,ordsets:new(),N)), |
||
io:fwrite("Sieved... ~w~n",[ResultSet]). |
io:fwrite("Sieved... ~w~n",[ResultSet]). |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,737: | Line 6,737: | ||
A pure list comprehension approach. |
A pure list comprehension approach. |
||
< |
<syntaxhighlight lang=Erlang> |
||
-module(sieveof). |
-module(sieveof). |
||
-export([main/1,primes/1, primes/2]). |
-export([main/1,primes/1, primes/2]). |
||
Line 6,755: | Line 6,755: | ||
remove([H | X], [H | Y]) -> remove(X, Y); |
remove([H | X], [H | Y]) -> remove(X, Y); |
||
remove(X, [H | Y]) -> [H | remove(X, Y)]. |
remove(X, [H | Y]) -> [H | remove(X, Y)]. |
||
</syntaxhighlight> |
|||
</lang> |
|||
{out} |
{out} |
||
<pre> |
<pre> |
||
Line 6,770: | Line 6,770: | ||
===Erlang ets + cpu distributed implementation === |
===Erlang ets + cpu distributed implementation === |
||
much faster previous erlang examples |
much faster previous erlang examples |
||
< |
<syntaxhighlight lang=Erlang> |
||
#!/usr/bin/env escript |
#!/usr/bin/env escript |
||
%% -*- erlang -*- |
%% -*- erlang -*- |
||
Line 6,835: | Line 6,835: | ||
comp_i(J, I, N) when J =< N -> ets:insert(comp, {J, 1}), comp_i(J+I, I, N); |
comp_i(J, I, N) when J =< N -> ets:insert(comp, {J, 1}), comp_i(J+I, I, N); |
||
comp_i(J, _, N) when J > N -> ok. |
comp_i(J, _, N) when J > N -> ok. |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,846: | Line 6,846: | ||
=={{header|ERRE}}== |
=={{header|ERRE}}== |
||
< |
<syntaxhighlight lang=ERRE> |
||
PROGRAM SIEVE_ORG |
PROGRAM SIEVE_ORG |
||
! -------------------------------------------------- |
! -------------------------------------------------- |
||
Line 6,876: | Line 6,876: | ||
PRINT(COUNT%;" PRIMES") |
PRINT(COUNT%;" PRIMES") |
||
END PROGRAM |
END PROGRAM |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
last lines of the output screen |
last lines of the output screen |
||
Line 6,890: | Line 6,890: | ||
=={{header|Euphoria}}== |
=={{header|Euphoria}}== |
||
< |
<syntaxhighlight lang=euphoria>constant limit = 1000 |
||
sequence flags,primes |
sequence flags,primes |
||
flags = repeat(1, limit) |
flags = repeat(1, limit) |
||
Line 6,907: | Line 6,907: | ||
end if |
end if |
||
end for |
end for |
||
? primes</ |
? primes</syntaxhighlight> |
||
Output: |
Output: |
||
Line 6,923: | Line 6,923: | ||
=={{header|F Sharp}}== |
=={{header|F Sharp}}== |
||
===Short with mutable state=== |
===Short with mutable state=== |
||
< |
<syntaxhighlight lang=fsharp> |
||
let primes max = |
let primes max = |
||
let mutable xs = [|2..max|] |
let mutable xs = [|2..max|] |
||
Line 6,930: | Line 6,930: | ||
xs <- xs |> Array.except [|x*x..x..max|] |
xs <- xs |> Array.except [|x*x..x..max|] |
||
xs |
xs |
||
</syntaxhighlight> |
|||
</lang> |
|||
===Short Sweet Functional and Idiotmatic=== |
===Short Sweet Functional and Idiotmatic=== |
||
Well lists may not be lazy, but if you call it a sequence then it's a lazy list! |
Well lists may not be lazy, but if you call it a sequence then it's a lazy list! |
||
< |
<syntaxhighlight lang=fsharp> |
||
(* |
(* |
||
An interesting implementation of The Sieve of Eratosthenes. |
An interesting implementation of The Sieve of Eratosthenes. |
||
Line 6,946: | Line 6,946: | ||
yield g; yield! fn (g - 1) g |> Seq.map2 (&&) ng |> Seq.cache |> fg } |
yield g; yield! fn (g - 1) g |> Seq.map2 (&&) ng |> Seq.cache |> fg } |
||
Seq.initInfinite (fun x -> true) |> fg |
Seq.initInfinite (fun x -> true) |> fg |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,972: | Line 6,972: | ||
This is the idea behind Richard Bird's unbounded code presented in the Epilogue of [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf M. O'Neill's article] in Haskell. It is about twice as much code as the Haskell code because F# does not have a built-in lazy list so that the effect must be constructed using a Co-Inductive Stream (CIS) type since no memoization is required, along with the use of recursive functions in combination with sequences. The type inference needs some help with the new CIS type (including selecting the generic type for speed). Note the use of recursive functions to implement multiple non-sharing delayed generating base primes streams, which along with these being non-memoizing means that the entire primes stream is not held in memory as for the original Bird code: |
This is the idea behind Richard Bird's unbounded code presented in the Epilogue of [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf M. O'Neill's article] in Haskell. It is about twice as much code as the Haskell code because F# does not have a built-in lazy list so that the effect must be constructed using a Co-Inductive Stream (CIS) type since no memoization is required, along with the use of recursive functions in combination with sequences. The type inference needs some help with the new CIS type (including selecting the generic type for speed). Note the use of recursive functions to implement multiple non-sharing delayed generating base primes streams, which along with these being non-memoizing means that the entire primes stream is not held in memory as for the original Bird code: |
||
< |
<syntaxhighlight lang=fsharp>type 'a CIS = CIS of 'a * (unit -> 'a CIS) //'Co Inductive Stream for laziness |
||
let primesBird() = |
let primesBird() = |
||
Line 6,987: | Line 6,987: | ||
else minusat (n + 1u) (ctlf()) |
else minusat (n + 1u) (ctlf()) |
||
let rec baseprms() = CIS(2u, fun() -> baseprms() |> allmltps |> cmpsts |> minusat 3u) |
let rec baseprms() = CIS(2u, fun() -> baseprms() |> allmltps |> cmpsts |> minusat 3u) |
||
Seq.unfold (fun (CIS(p, ptlf)) -> Some(p, ptlf())) (baseprms())</ |
Seq.unfold (fun (CIS(p, ptlf)) -> Some(p, ptlf())) (baseprms())</syntaxhighlight> |
||
The above code sieves all numbers of two and up including all even numbers as per the page specification; the following code makes the very minor changes for an odds-only sieve, with a speedup of over a factor of two: |
The above code sieves all numbers of two and up including all even numbers as per the page specification; the following code makes the very minor changes for an odds-only sieve, with a speedup of over a factor of two: |
||
< |
<syntaxhighlight lang=fsharp>type 'a CIS = CIS of 'a * (unit -> 'a CIS) //'Co Inductive Stream for laziness |
||
let primesBirdOdds() = |
let primesBirdOdds() = |
||
Line 7,006: | Line 7,006: | ||
else minusat (n + 2u) (ctlf()) |
else minusat (n + 2u) (ctlf()) |
||
let rec oddprms() = CIS(3u, fun() -> oddprms() |> allmltps |> cmpsts |> minusat 5u) |
let rec oddprms() = CIS(3u, fun() -> oddprms() |> allmltps |> cmpsts |> minusat 5u) |
||
Seq.unfold (fun (CIS(p, ptlf)) -> Some(p, ptlf())) (CIS(2u, fun() -> oddprms()))</ |
Seq.unfold (fun (CIS(p, ptlf)) -> Some(p, ptlf())) (CIS(2u, fun() -> oddprms()))</syntaxhighlight> |
||
'''Tree Folding Sieve''' |
'''Tree Folding Sieve''' |
||
The above code is still somewhat inefficient as it operates on a linear right extending structure that deepens linearly with increasing base primes (those up to the square root of the currently sieved number); the following code changes the structure into an infinite binary tree-like folding by combining each pair of prime composite streams before further processing as usual - this decreases the processing by approximately a factor of log n: |
The above code is still somewhat inefficient as it operates on a linear right extending structure that deepens linearly with increasing base primes (those up to the square root of the currently sieved number); the following code changes the structure into an infinite binary tree-like folding by combining each pair of prime composite streams before further processing as usual - this decreases the processing by approximately a factor of log n: |
||
< |
<syntaxhighlight lang=fsharp>type 'a CIS = CIS of 'a * (unit -> 'a CIS) //'Co Inductive Stream for laziness |
||
let primesTreeFold() = |
let primesTreeFold() = |
||
Line 7,029: | Line 7,029: | ||
else minusat (n + 2u) (ctlf()) |
else minusat (n + 2u) (ctlf()) |
||
let rec oddprms() = CIS(3u, fun() -> oddprms() |> allmltps |> cmpsts |> minusat 5u) |
let rec oddprms() = CIS(3u, fun() -> oddprms() |> allmltps |> cmpsts |> minusat 5u) |
||
Seq.unfold (fun (CIS(p, ptlf)) -> Some(p, ptlf())) (CIS(2u, fun() -> oddprms()))</ |
Seq.unfold (fun (CIS(p, ptlf)) -> Some(p, ptlf())) (CIS(2u, fun() -> oddprms()))</syntaxhighlight> |
||
The above code is over four times faster than the "BirdOdds" version (at least 10x faster than the first, "primesBird", producing the millionth prime) and is moderately useful for a range of the first million primes or so. |
The above code is over four times faster than the "BirdOdds" version (at least 10x faster than the first, "primesBird", producing the millionth prime) and is moderately useful for a range of the first million primes or so. |
||
Line 7,036: | Line 7,036: | ||
In order to investigate Priority Queue Sieves as espoused by O'Neill in the referenced article, one must find an equivalent implementation of a Min Heap Priority Queue as used by her. There is such an purely functional implementation [http://rosettacode.org/wiki/Priority_queue#Functional in RosettaCode translated from the Haskell code she used], from which the essential parts are duplicated here (Note that the key value is given an integer type in order to avoid the inefficiency of F# in generic comparison): |
In order to investigate Priority Queue Sieves as espoused by O'Neill in the referenced article, one must find an equivalent implementation of a Min Heap Priority Queue as used by her. There is such an purely functional implementation [http://rosettacode.org/wiki/Priority_queue#Functional in RosettaCode translated from the Haskell code she used], from which the essential parts are duplicated here (Note that the key value is given an integer type in order to avoid the inefficiency of F# in generic comparison): |
||
< |
<syntaxhighlight lang=fsharp>[<RequireQualifiedAccess>] |
||
module MinHeap = |
module MinHeap = |
||
Line 7,073: | Line 7,073: | ||
let replaceMin wk wv = function | Mt -> Mt |
let replaceMin wk wv = function | Mt -> Mt |
||
| Br(_, ll, rr) -> siftdown wk wv ll rr</ |
| Br(_, ll, rr) -> siftdown wk wv ll rr</syntaxhighlight> |
||
Except as noted for any individual code, all of the following codes need the following prefix code in order to implement the non-memoizing Co-Inductive Streams (CIS's) and to set the type of particular constants used in the codes to the same time as the "Prime" type: |
Except as noted for any individual code, all of the following codes need the following prefix code in order to implement the non-memoizing Co-Inductive Streams (CIS's) and to set the type of particular constants used in the codes to the same time as the "Prime" type: |
||
< |
<syntaxhighlight lang=fsharp>type CIS<'T> = struct val v: 'T val cont: unit -> CIS<'T> new(v,cont) = {v=v;cont=cont} end |
||
type Prime = uint32 |
type Prime = uint32 |
||
let frstprm = 2u |
let frstprm = 2u |
||
let frstoddprm = 3u |
let frstoddprm = 3u |
||
let inc1 = 1u |
let inc1 = 1u |
||
let inc = 2u</ |
let inc = 2u</syntaxhighlight> |
||
The F# equivalent to O'Neill's "odds-only" code is then implemented as follows, which needs the included changed prefix in order to change the primes type to a larger one to prevent overflow (as well the key type for the MinHeap needs to be changed from uint32 to uint64); it is functionally the same as the O'Neill code other than for minor changes to suit the use of CIS streams and the option output of the "peekMin" function: |
The F# equivalent to O'Neill's "odds-only" code is then implemented as follows, which needs the included changed prefix in order to change the primes type to a larger one to prevent overflow (as well the key type for the MinHeap needs to be changed from uint32 to uint64); it is functionally the same as the O'Neill code other than for minor changes to suit the use of CIS streams and the option output of the "peekMin" function: |
||
< |
<syntaxhighlight lang=fsharp>type CIS<'T> = struct val v: 'T val cont: unit -> CIS<'T> new(v,cont) = {v=v;cont=cont} end |
||
type Prime = uint64 |
type Prime = uint64 |
||
let frstprm = 2UL |
let frstprm = 2UL |
||
Line 7,114: | Line 7,114: | ||
let rec nxto i = CIS(i, fun() -> nxto (i + inc)) in nxto frstoddprm |
let rec nxto i = CIS(i, fun() -> nxto (i + inc)) in nxto frstoddprm |
||
Seq.unfold (fun (cis: CIS<Prime>) -> Some(cis.v, cis.cont())) |
Seq.unfold (fun (cis: CIS<Prime>) -> Some(cis.v, cis.cont())) |
||
(CIS(frstprm, fun() -> (sieve odds)))</ |
(CIS(frstprm, fun() -> (sieve odds)))</syntaxhighlight> |
||
However, that algorithm suffers in speed and memory use due to over-eager adding of prime composite streams to the queue such that the queue used is much larger than it needs to be and a much larger range of primes number must be used in order to avoid numeric overflow on the square of the prime added to the queue. The following code corrects that by using a secondary (actually a multiple of) base primes streams which are constrained to be based on a prime that is no larger than the square root of the currently sieved number - this permits the use of much smaller Prime types as per the default prefix: |
However, that algorithm suffers in speed and memory use due to over-eager adding of prime composite streams to the queue such that the queue used is much larger than it needs to be and a much larger range of primes number must be used in order to avoid numeric overflow on the square of the prime added to the queue. The following code corrects that by using a secondary (actually a multiple of) base primes streams which are constrained to be based on a prime that is no larger than the square root of the currently sieved number - this permits the use of much smaller Prime types as per the default prefix: |
||
< |
<syntaxhighlight lang=fsharp>let primesPQx() = |
||
let rec nxtprm n pq q (bps: CIS<Prime>) = |
let rec nxtprm n pq q (bps: CIS<Prime>) = |
||
if n >= q then let bp = bps.v in let adv = bp + bp |
if n >= q then let bp = bps.v in let adv = bp + bp |
||
Line 7,136: | Line 7,136: | ||
nxtprm (frstoddprm + inc) MinHeap.empty (frstoddprm * frstoddprm) (oddprms())) |
nxtprm (frstoddprm + inc) MinHeap.empty (frstoddprm * frstoddprm) (oddprms())) |
||
Seq.unfold (fun (cis: CIS<Prime>) -> Some(cis.v, cis.cont())) |
Seq.unfold (fun (cis: CIS<Prime>) -> Some(cis.v, cis.cont())) |
||
(CIS(frstprm, fun() -> (oddprms())))</ |
(CIS(frstprm, fun() -> (oddprms())))</syntaxhighlight> |
||
The above code is well over five times faster than the previous translated O'Neill version for the given variety of reasons. |
The above code is well over five times faster than the previous translated O'Neill version for the given variety of reasons. |
||
Line 7,154: | Line 7,154: | ||
The following code is written in functional style other than it uses a mutable bit array to sieve the composites: |
The following code is written in functional style other than it uses a mutable bit array to sieve the composites: |
||
< |
<syntaxhighlight lang=fsharp>let primes limit = |
||
let buf = System.Collections.BitArray(int limit + 1, true) |
let buf = System.Collections.BitArray(int limit + 1, true) |
||
let cull p = { p * p .. p .. limit } |> Seq.iter (fun c -> buf.[int c] <- false) |
let cull p = { p * p .. p .. limit } |> Seq.iter (fun c -> buf.[int c] <- false) |
||
Line 7,164: | Line 7,164: | ||
if argv = null || argv.Length = 0 then failwith "no command line argument for limit!!!" |
if argv = null || argv.Length = 0 then failwith "no command line argument for limit!!!" |
||
printfn "%A" (primes (System.UInt32.Parse argv.[0]) |> Seq.length) |
printfn "%A" (primes (System.UInt32.Parse argv.[0]) |> Seq.length) |
||
0 // return an integer exit code</ |
0 // return an integer exit code</syntaxhighlight> |
||
Substituting the following minor changes to the code for the "primes" function will only deal with the odd prime candidates for a speed up of over a factor of two as well as a reduction of the buffer size by a factor of two: |
Substituting the following minor changes to the code for the "primes" function will only deal with the odd prime candidates for a speed up of over a factor of two as well as a reduction of the buffer size by a factor of two: |
||
< |
<syntaxhighlight lang=fsharp>let primes limit = |
||
let lmtb,lmtbsqrt = (limit - 3u) / 2u, (uint32 (sqrt (double limit)) - 3u) / 2u |
let lmtb,lmtbsqrt = (limit - 3u) / 2u, (uint32 (sqrt (double limit)) - 3u) / 2u |
||
let buf = System.Collections.BitArray(int lmtb + 1, true) |
let buf = System.Collections.BitArray(int lmtb + 1, true) |
||
Line 7,176: | Line 7,176: | ||
let oddprms = { 0u .. lmtb } |> Seq.map (fun i -> if buf.[int i] then i + i + 3u else 0u) |
let oddprms = { 0u .. lmtb } |> Seq.map (fun i -> if buf.[int i] then i + i + 3u else 0u) |
||
|> Seq.filter ((<>) 0u) |
|> Seq.filter ((<>) 0u) |
||
seq { yield 2u; yield! oddprms }</ |
seq { yield 2u; yield! oddprms }</syntaxhighlight> |
||
The following code uses other functional forms for the inner culling loops of the "primes function" to reduce the use of inefficient sequences so as to reduce the execution time by another factor of almost three: |
The following code uses other functional forms for the inner culling loops of the "primes function" to reduce the use of inefficient sequences so as to reduce the execution time by another factor of almost three: |
||
< |
<syntaxhighlight lang=fsharp>let primes limit = |
||
let lmtb,lmtbsqrt = (limit - 3u) / 2u, (uint32 (sqrt (double limit)) - 3u) / 2u |
let lmtb,lmtbsqrt = (limit - 3u) / 2u, (uint32 (sqrt (double limit)) - 3u) / 2u |
||
let buf = System.Collections.BitArray(int lmtb + 1, true) |
let buf = System.Collections.BitArray(int lmtb + 1, true) |
||
Line 7,187: | Line 7,187: | ||
let rec cullp c = if c <= lmtb then buf.[int c] <- false; cullp (c + p) |
let rec cullp c = if c <= lmtb then buf.[int c] <- false; cullp (c + p) |
||
(if buf.[int i] then cullp s); culltest (i + 1u) in culltest 0u |
(if buf.[int i] then cullp s); culltest (i + 1u) in culltest 0u |
||
seq {yield 2u; for i = 0u to lmtb do if buf.[int i] then yield i + i + 3u }</ |
seq {yield 2u; for i = 0u to lmtb do if buf.[int i] then yield i + i + 3u }</syntaxhighlight> |
||
Now much of the remaining execution time is just the time to enumerate the primes as can be seen by turning "primes" into a primes counting function by substituting the following for the last line in the above code doing the enumeration; this makes the code run about a further five times faster: |
Now much of the remaining execution time is just the time to enumerate the primes as can be seen by turning "primes" into a primes counting function by substituting the following for the last line in the above code doing the enumeration; this makes the code run about a further five times faster: |
||
< |
<syntaxhighlight lang=fsharp> let rec count i acc = |
||
if i > int lmtb then acc else if buf.[i] then count (i + 1) (acc + 1) else count (i + 1) acc |
if i > int lmtb then acc else if buf.[i] then count (i + 1) (acc + 1) else count (i + 1) acc |
||
count 0 1</ |
count 0 1</syntaxhighlight> |
||
Since the final enumeration of primes is the main remaining bottleneck, it is worth using a "roll-your-own" enumeration implemented as an object expression so as to save many inefficiencies in the use of the built-in seq computational expression by substituting the following code for the last line of the previous codes, which will decrease the execution time by a factor of over three (instead of almost five for the counting-only version, making it almost as fast): |
Since the final enumeration of primes is the main remaining bottleneck, it is worth using a "roll-your-own" enumeration implemented as an object expression so as to save many inefficiencies in the use of the built-in seq computational expression by substituting the following code for the last line of the previous codes, which will decrease the execution time by a factor of over three (instead of almost five for the counting-only version, making it almost as fast): |
||
< |
<syntaxhighlight lang=fsharp> let nmrtr() = |
||
let i = ref -2 |
let i = ref -2 |
||
let rec nxti() = i:=!i + 1;if !i <= int lmtb && not buf.[!i] then nxti() else !i <= int lmtb |
let rec nxti() = i:=!i + 1;if !i <= int lmtb && not buf.[!i] then nxti() else !i <= int lmtb |
||
Line 7,213: | Line 7,213: | ||
member this.GetEnumerator() = nmrtr() |
member this.GetEnumerator() = nmrtr() |
||
interface System.Collections.IEnumerable with |
interface System.Collections.IEnumerable with |
||
member this.GetEnumerator() = nmrtr() :> System.Collections.IEnumerator }</ |
member this.GetEnumerator() = nmrtr() :> System.Collections.IEnumerator }</syntaxhighlight> |
||
The various optimization techniques shown here can be used "jointly and severally" on any of the basic versions for various trade-offs between code complexity and performance. Not shown here are other techniques of making the sieve faster, including extending wheel factorization to much larger wheels such as 2/3/5/7, pre-culling the arrays, page segmentation, and multi-processing. |
The various optimization techniques shown here can be used "jointly and severally" on any of the basic versions for various trade-offs between code complexity and performance. Not shown here are other techniques of making the sieve faster, including extending wheel factorization to much larger wheels such as 2/3/5/7, pre-culling the arrays, page segmentation, and multi-processing. |
||
Line 7,224: | Line 7,224: | ||
The following code uses the DotNet Dictionary class instead of the above functional Priority Queue to implement the sieve; as average (amortized) hash table access is O(1) rather than O(log n) as for the priority queue, this implementation is slightly faster than the priority queue version for the first million primes and will always be faster for any range above some low range value: |
The following code uses the DotNet Dictionary class instead of the above functional Priority Queue to implement the sieve; as average (amortized) hash table access is O(1) rather than O(log n) as for the priority queue, this implementation is slightly faster than the priority queue version for the first million primes and will always be faster for any range above some low range value: |
||
< |
<syntaxhighlight lang=fsharp>type Prime = uint32 |
||
let frstprm = 2u |
let frstprm = 2u |
||
let frstoddprm = 3u |
let frstoddprm = 3u |
||
Line 7,249: | Line 7,249: | ||
nxtprm (frstoddprm + inc) (frstoddprm * frstoddprm) (oddprms())) |
nxtprm (frstoddprm + inc) (frstoddprm * frstoddprm) (oddprms())) |
||
Seq.unfold (fun (cis: CIS<Prime>) -> Some(cis.v, cis.cont())) |
Seq.unfold (fun (cis: CIS<Prime>) -> Some(cis.v, cis.cont())) |
||
(CIS(frstprm, fun() -> (oddprms())))</ |
(CIS(frstprm, fun() -> (oddprms())))</syntaxhighlight> |
||
The above code uses functional forms of code (with the imperative style commented out to show how it could be done imperatively) and also uses a recursive non-sharing secondary source of base primes just as for the Priority Queue version. As for the functional codes, the Primes type can easily be changed to "uint64" for wider range of sieving. |
The above code uses functional forms of code (with the imperative style commented out to show how it could be done imperatively) and also uses a recursive non-sharing secondary source of base primes just as for the Priority Queue version. As for the functional codes, the Primes type can easily be changed to "uint64" for wider range of sieving. |
||
Line 7,260: | Line 7,260: | ||
All of the above unbounded implementations including the above Dictionary based version are quite slow due to their large constant factor computational overheads, making them more of an intellectual exercise than something practical, especially when larger sieving ranges are required. The following code implements an unbounded page segmented version of the sieve in not that many more lines of code, yet runs about 25 times faster than the Dictionary version for larger ranges of sieving such as to one billion; it uses functional forms without mutability other than for the contents of the arrays and the `primes` enumeration generator function that must use mutability for speed: |
All of the above unbounded implementations including the above Dictionary based version are quite slow due to their large constant factor computational overheads, making them more of an intellectual exercise than something practical, especially when larger sieving ranges are required. The following code implements an unbounded page segmented version of the sieve in not that many more lines of code, yet runs about 25 times faster than the Dictionary version for larger ranges of sieving such as to one billion; it uses functional forms without mutability other than for the contents of the arrays and the `primes` enumeration generator function that must use mutability for speed: |
||
< |
<syntaxhighlight lang=fsharp>type Prime = float // use uint64/int64 for regular 64-bit F# |
||
type private PrimeNdx = float // they are slow in JavaScript polyfills |
type private PrimeNdx = float // they are slow in JavaScript polyfills |
||
Line 7,398: | Line 7,398: | ||
let answr = countPrimesTo limit // over twice as fast way! |
let answr = countPrimesTo limit // over twice as fast way! |
||
let elpsd = (System.DateTime.Now.Ticks - start) / 10000L |
let elpsd = (System.DateTime.Now.Ticks - start) / 10000L |
||
printfn "Found %d primes to %A in %d milliseconds." answr limit elpsd</ |
printfn "Found %d primes to %A in %d milliseconds." answr limit elpsd</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 7,415: | Line 7,415: | ||
Factor is pleasantly multiparadigm. Usually, it's natural to write more functional or declarative code in Factor, but this is an instance where it is more natural to write imperative code. Lexical variables are useful here for expressing the necessary mutations in a clean way. |
Factor is pleasantly multiparadigm. Usually, it's natural to write more functional or declarative code in Factor, but this is an instance where it is more natural to write imperative code. Lexical variables are useful here for expressing the necessary mutations in a clean way. |
||
< |
<syntaxhighlight lang=factor>USING: bit-arrays io kernel locals math math.functions |
||
math.ranges prettyprint sequences ; |
math.ranges prettyprint sequences ; |
||
IN: rosetta-code.sieve-of-erato |
IN: rosetta-code.sieve-of-erato |
||
Line 7,446: | Line 7,446: | ||
120 sieve . ; |
120 sieve . ; |
||
MAIN: sieve-demo</ |
MAIN: sieve-demo</syntaxhighlight> |
||
=={{header|FOCAL}}== |
=={{header|FOCAL}}== |
||
< |
<syntaxhighlight lang=FOCAL>1.1 T "PLEASE ENTER LIMIT" |
||
1.2 A N |
1.2 A N |
||
1.3 I (2047-N)5.1 |
1.3 I (2047-N)5.1 |
||
Line 7,464: | Line 7,464: | ||
4.1 T %4.0,W,! |
4.1 T %4.0,W,! |
||
5.1 T "PLEASE ENTER A NUMBER LESS THAN 2048."!; G 1.1</ |
5.1 T "PLEASE ENTER A NUMBER LESS THAN 2048."!; G 1.1</syntaxhighlight> |
||
Note that with the 4k paper tape version of FOCAL, the program will run out of memory for N>190 or so. |
Note that with the 4k paper tape version of FOCAL, the program will run out of memory for N>190 or so. |
||
Line 7,496: | Line 7,496: | ||
The above code is not really very good Forth style as the main initialization, sieving, and output, are all in one `sieve` routine which makes it difficult to understand and refactor; Forth code is normally written in a series of very small routines which makes it easier to understand what is happening on the data stack, since Forth does not have named local re-entrant variable names as most other languages do for local variables (which other languages also normally store local variables on the stack). Also, it uses the `HERE` pointer to user space which points to the next available memory after all compilation is done as a unsized buffer pointer, but as it does not reserve that space for the sieving buffer, it can be changed by other concatenated routines in unexpected ways; better is to allocate the sieving buffer as required from the available space at the time the routines are run and pass that address between concatenated functions until a finalization function frees the memory and clears the stack; this is equivalent to allocating from the "heap" in other languages. The below code demonstrates these ideas: |
The above code is not really very good Forth style as the main initialization, sieving, and output, are all in one `sieve` routine which makes it difficult to understand and refactor; Forth code is normally written in a series of very small routines which makes it easier to understand what is happening on the data stack, since Forth does not have named local re-entrant variable names as most other languages do for local variables (which other languages also normally store local variables on the stack). Also, it uses the `HERE` pointer to user space which points to the next available memory after all compilation is done as a unsized buffer pointer, but as it does not reserve that space for the sieving buffer, it can be changed by other concatenated routines in unexpected ways; better is to allocate the sieving buffer as required from the available space at the time the routines are run and pass that address between concatenated functions until a finalization function frees the memory and clears the stack; this is equivalent to allocating from the "heap" in other languages. The below code demonstrates these ideas: |
||
< |
<syntaxhighlight lang=forth>: prime? ( addr -- ? ) C@ 0= ; \ test composites array for prime |
||
\ given square index and prime index, u0, sieve the multiples of said prime... |
\ given square index and prime index, u0, sieve the multiples of said prime... |
||
Line 7,541: | Line 7,541: | ||
\ testing the code... |
\ testing the code... |
||
100 initsieve sieve .primes |
100 initsieve sieve .primes |
||
1000000 .countprimesto</ |
1000000 .countprimesto</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 7,639: | Line 7,639: | ||
100 initsieve sieve .primes |
100 initsieve sieve .primes |
||
1000000000 .countprimesto</ |
1000000000 .countprimesto</syntaxhighlight> |
||
The output of the above code is the same as the previous version, but it takes about two thirds the time while using eight times less memory; it takes about 6.5 seconds on my Intel Skylake i5-6500 at 3.6 GHz (turbo) using swiftForth (32-bit) and about 3.5 seconds on VFX Forth (64-bit), both of which compile to machine code but with the latter much more optimized; gforth-fast is about twice as slow as swiftForth and five times slower then VFX Forth as it just compiles to threaded execution tokens (more like an interpreter). |
The output of the above code is the same as the previous version, but it takes about two thirds the time while using eight times less memory; it takes about 6.5 seconds on my Intel Skylake i5-6500 at 3.6 GHz (turbo) using swiftForth (32-bit) and about 3.5 seconds on VFX Forth (64-bit), both of which compile to machine code but with the latter much more optimized; gforth-fast is about twice as slow as swiftForth and five times slower then VFX Forth as it just compiles to threaded execution tokens (more like an interpreter). |
||
Line 7,647: | Line 7,647: | ||
While the above version does greatly reduce the amount of memory used for a given sieving range and thereby also somewhat reduces execution time; any sieve intended for sieving to limits of a hundred million or more should use a page-segmented implementation; page-segmentation means that only storage for a representation of the base primes up to the square root of the limit plus a sieve buffer that should also be at least proportional to the same square root is required; this will again make the execution faster as ranges go up due to better cache associativity with most memory accesses being within the CPU cache sizes. The following Forth code implements a basic version that does this: |
While the above version does greatly reduce the amount of memory used for a given sieving range and thereby also somewhat reduces execution time; any sieve intended for sieving to limits of a hundred million or more should use a page-segmented implementation; page-segmentation means that only storage for a representation of the base primes up to the square root of the limit plus a sieve buffer that should also be at least proportional to the same square root is required; this will again make the execution faster as ranges go up due to better cache associativity with most memory accesses being within the CPU cache sizes. The following Forth code implements a basic version that does this: |
||
< |
<syntaxhighlight lang=forth>\ CPU L1 and L2 cache sizes in bits; power of 2... |
||
1 17 LSHIFT CONSTANT L1CacheBits |
1 17 LSHIFT CONSTANT L1CacheBits |
||
L1CacheBits 8 * CONSTANT L2CacheBits |
L1CacheBits 8 * CONSTANT L2CacheBits |
||
Line 7,758: | Line 7,758: | ||
100 .primes |
100 .primes |
||
1000000000 .countPrimesTo</ |
1000000000 .countPrimesTo</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 7,781: | Line 7,781: | ||
=={{header|Fortran}}== |
=={{header|Fortran}}== |
||
{{works with|Fortran|77}} |
{{works with|Fortran|77}} |
||
< |
<syntaxhighlight lang=fortran> |
||
PROGRAM MAIN |
PROGRAM MAIN |
||
INTEGER LI |
INTEGER LI |
||
Line 7,818: | Line 7,818: | ||
RETURN |
RETURN |
||
END |
END |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{works with|Fortran|90 and later}} |
{{works with|Fortran|90 and later}} |
||
< |
<syntaxhighlight lang=fortran>program sieve |
||
implicit none |
implicit none |
||
Line 7,838: | Line 7,838: | ||
write (*, *) |
write (*, *) |
||
end program sieve</ |
end program sieve</syntaxhighlight> |
||
Output: |
Output: |
||
<lang>2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97</ |
<lang>2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97</syntaxhighlight> |
||
Because it uses four byte logical's (default size) as elements of the sieve buffer, the above code uses 400 bytes of memory for this trivial task of sieving to 100; it also has 49 + 31 + 16 + 8 = 104 (for the culling by the primes of two, three, five, and seven) culling operations. |
Because it uses four byte logical's (default size) as elements of the sieve buffer, the above code uses 400 bytes of memory for this trivial task of sieving to 100; it also has 49 + 31 + 16 + 8 = 104 (for the culling by the primes of two, three, five, and seven) culling operations. |
||
Line 7,846: | Line 7,846: | ||
'''Optimised using a pre-computed wheel based on 2:''' |
'''Optimised using a pre-computed wheel based on 2:''' |
||
< |
<syntaxhighlight lang=fortran>program sieve_wheel_2 |
||
implicit none |
implicit none |
||
Line 7,864: | Line 7,864: | ||
write (*, *) |
write (*, *) |
||
end program sieve_wheel_2</ |
end program sieve_wheel_2</syntaxhighlight> |
||
Output: |
Output: |
||
<lang>2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97</ |
<lang>2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97</syntaxhighlight> |
||
This so-called "optimized" version still uses 400 bytes of memory but slightly reduces to 74 operations from 104 operations including the initialization of marking all of the even representations as composite due to skipping the re-culling of the even representation, so isn't really much of an optimization at all! |
This so-called "optimized" version still uses 400 bytes of memory but slightly reduces to 74 operations from 104 operations including the initialization of marking all of the even representations as composite due to skipping the re-culling of the even representation, so isn't really much of an optimization at all! |
||
Line 7,874: | Line 7,874: | ||
The above implementations, especially the second odds-only code, are some of the most inefficient versions of the Sieve of Eratosthenes in any language here as to time and space efficiency, only worse by some naive JavaScript implementations that use eight-byte Number's as logical values; the second claims to be wheel factorized but still uses all the same memory as the first and still culls by the even numbers in the initialization of the sieve buffer. As well, using four bytes (default logical size) to store a boolean value is terribly wasteful if these implementations were to be extended to non-toy ranges. The following code implements proper wheel factorization by two, reducing the space used by a factor of about eight to 49 bytes by using `byte` as the sieve buffer array elements and not requiring the evens initialization, thus reducing the number of operations to 16 + 8 + 4 = 28 (for the culling primes of three, five, and seven) culling operations: |
The above implementations, especially the second odds-only code, are some of the most inefficient versions of the Sieve of Eratosthenes in any language here as to time and space efficiency, only worse by some naive JavaScript implementations that use eight-byte Number's as logical values; the second claims to be wheel factorized but still uses all the same memory as the first and still culls by the even numbers in the initialization of the sieve buffer. As well, using four bytes (default logical size) to store a boolean value is terribly wasteful if these implementations were to be extended to non-toy ranges. The following code implements proper wheel factorization by two, reducing the space used by a factor of about eight to 49 bytes by using `byte` as the sieve buffer array elements and not requiring the evens initialization, thus reducing the number of operations to 16 + 8 + 4 = 28 (for the culling primes of three, five, and seven) culling operations: |
||
< |
<syntaxhighlight lang=fortran>program sieve_wheel_2 |
||
implicit none |
implicit none |
||
Line 7,892: | Line 7,892: | ||
write (*, *) |
write (*, *) |
||
end program sieve_wheel_2</ |
end program sieve_wheel_2</syntaxhighlight> |
||
The output is the same as the earlier version. |
The output is the same as the earlier version. |
||
Line 7,900: | Line 7,900: | ||
The above implementation is still space inefficient in effectively only using one bit out of eight; the following version implements bit packing to reduce memory use by a factor of eight by using bits to represent composite numbers rather than bytes: |
The above implementation is still space inefficient in effectively only using one bit out of eight; the following version implements bit packing to reduce memory use by a factor of eight by using bits to represent composite numbers rather than bytes: |
||
< |
<syntaxhighlight lang=fortran>program sieve_wheel_2 |
||
implicit none |
implicit none |
||
Line 7,928: | Line 7,928: | ||
print '(a, i0, a, i0, a, f0.0, a)', & |
print '(a, i0, a, i0, a, f0.0, a)', & |
||
'There are ', cnt, ' primes up to ', i_max, '.' |
'There are ', cnt, ' primes up to ', i_max, '.' |
||
end program sieve_wheel_2</ |
end program sieve_wheel_2</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 7,939: | Line 7,939: | ||
As well as adding page-segmentation, the following code adds multi-processing which is onc of the capabilities for which modern Fortran is known: |
As well as adding page-segmentation, the following code adds multi-processing which is onc of the capabilities for which modern Fortran is known: |
||
< |
<syntaxhighlight lang=fortran>subroutine cullSieveBuffer(lwi, size, bpa, sba) |
||
implicit none |
implicit none |
||
Line 8,087: | Line 8,087: | ||
deallocate(sbaa) |
deallocate(sbaa) |
||
end program sieve_paged</ |
end program sieve_paged</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 8,097: | Line 8,097: | ||
===Basic version=== |
===Basic version=== |
||
function Sieve returns a list of primes less than or equal to the given aLimit |
function Sieve returns a list of primes less than or equal to the given aLimit |
||
< |
<syntaxhighlight lang=pascal> |
||
program prime_sieve; |
program prime_sieve; |
||
{$mode objfpc}{$coperators on} |
{$mode objfpc}{$coperators on} |
||
Line 8,171: | Line 8,171: | ||
end; |
end; |
||
end. |
end. |
||
</syntaxhighlight> |
|||
</lang> |
|||
===Alternative segmented(odds only) version=== |
===Alternative segmented(odds only) version=== |
||
function OddSegmentSieve returns a list of primes less than or equal to the given aLimit |
function OddSegmentSieve returns a list of primes less than or equal to the given aLimit |
||
< |
<syntaxhighlight lang=pascal> |
||
program prime_sieve; |
program prime_sieve; |
||
{$mode objfpc}{$coperators on} |
{$mode objfpc}{$coperators on} |
||
Line 8,304: | Line 8,304: | ||
PrintPrimes(OddSegmentSieve(Limit)); |
PrintPrimes(OddSegmentSieve(Limit)); |
||
end. |
end. |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|FreeBASIC}}== |
=={{header|FreeBASIC}}== |
||
< |
<syntaxhighlight lang=freebasic>' FB 1.05.0 |
||
Sub sieve(n As Integer) |
Sub sieve(n As Integer) |
||
Line 8,345: | Line 8,345: | ||
Print |
Print |
||
Print "Press any key to quit" |
Print "Press any key to quit" |
||
Sleep</ |
Sleep</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 8,363: | Line 8,363: | ||
=={{header|Frink}}== |
=={{header|Frink}}== |
||
< |
<syntaxhighlight lang=frink> |
||
n = eval[input["Enter highest number: "]] |
n = eval[input["Enter highest number: "]] |
||
results = array[sieve[n]] |
results = array[sieve[n]] |
||
Line 8,382: | Line 8,382: | ||
return select[array, { |x| x != 0 }] |
return select[array, { |x| x != 0 }] |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Furor}}== |
=={{header|Furor}}== |
||
''Note: With benchmark function'' |
''Note: With benchmark function'' |
||
< |
<syntaxhighlight lang=Furor> |
||
tick sto startingtick |
tick sto startingtick |
||
#g 100000 sto MAX |
#g 100000 sto MAX |
||
Line 8,404: | Line 8,404: | ||
end |
end |
||
{ „MAX” } { „startingtick” } { „primeNumbers” } { „count” } |
{ „MAX” } { „startingtick” } { „primeNumbers” } { „count” } |
||
</syntaxhighlight> |
|||
</lang> |
|||
Line 8,410: | Line 8,410: | ||
=={{header|FutureBasic}}== |
=={{header|FutureBasic}}== |
||
===Basic sieve of array of booleans=== |
===Basic sieve of array of booleans=== |
||
< |
<syntaxhighlight lang=futurebasic>window 1, @"Sieve of Eratosthenes", (0,0,720,300) |
||
begin globals |
begin globals |
||
Line 8,430: | Line 8,430: | ||
fn SieveOfEratosthenes( 100 ) |
fn SieveOfEratosthenes( 100 ) |
||
HandleEvents</ |
HandleEvents</syntaxhighlight> |
||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 8,445: | Line 8,445: | ||
=={{header|GAP}}== |
=={{header|GAP}}== |
||
< |
<syntaxhighlight lang=gap>Eratosthenes := function(n) |
||
local a, i, j; |
local a, i, j; |
||
a := ListWithIdenticalEntries(n, true); |
a := ListWithIdenticalEntries(n, true); |
||
Line 8,469: | Line 8,469: | ||
Eratosthenes(100); |
Eratosthenes(100); |
||
[ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 ]</ |
[ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 ]</syntaxhighlight> |
||
=={{header|GLBasic}}== |
=={{header|GLBasic}}== |
||
< |
<syntaxhighlight lang=GLBasic>// Sieve of Eratosthenes (find primes) |
||
// GLBasic implementation |
// GLBasic implementation |
||
Line 8,496: | Line 8,496: | ||
KEYWAIT |
KEYWAIT |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
===Basic sieve of array of booleans=== |
===Basic sieve of array of booleans=== |
||
< |
<syntaxhighlight lang=go>package main |
||
import "fmt" |
import "fmt" |
||
Line 8,541: | Line 8,541: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 8,560: | Line 8,560: | ||
The above version's output is rather specialized; the following version uses a closure function to enumerate over the culled composite number array, which is bit packed. By using this scheme for output, no extra memory is required above that required for the culling array: |
The above version's output is rather specialized; the following version uses a closure function to enumerate over the culled composite number array, which is bit packed. By using this scheme for output, no extra memory is required above that required for the culling array: |
||
< |
<syntaxhighlight lang=go>package main |
||
import ( |
import ( |
||
Line 8,607: | Line 8,607: | ||
} |
} |
||
fmt.Printf("\r\n%v\r\n", count) |
fmt.Printf("\r\n%v\r\n", count) |
||
}</ |
}</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
<pre>2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
||
Line 8,614: | Line 8,614: | ||
===Sieve Tree=== |
===Sieve Tree=== |
||
A fairly odd sieve tree method: |
A fairly odd sieve tree method: |
||
< |
<syntaxhighlight lang=go>package main |
||
import "fmt" |
import "fmt" |
||
Line 8,673: | Line 8,673: | ||
fmt.Println(p()) |
fmt.Println(p()) |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
===Concurrent Daisy-chain sieve=== |
===Concurrent Daisy-chain sieve=== |
||
A concurrent prime sieve adopted from the example in the "Go Playground" window at http://golang.org/ |
A concurrent prime sieve adopted from the example in the "Go Playground" window at http://golang.org/ |
||
< |
<syntaxhighlight lang=go>package main |
||
import "fmt" |
import "fmt" |
||
Line 8,728: | Line 8,728: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
The output: |
The output: |
||
<pre> |
<pre> |
||
Line 8,738: | Line 8,738: | ||
===Postponed Concurrent Daisy-chain sieve=== |
===Postponed Concurrent Daisy-chain sieve=== |
||
Here we postpone the ''creation'' of filters until the prime's square is seen in the input, to radically reduce the amount of filter channels in the sieve chain. |
Here we postpone the ''creation'' of filters until the prime's square is seen in the input, to radically reduce the amount of filter channels in the sieve chain. |
||
< |
<syntaxhighlight lang=go>package main |
||
import "fmt" |
import "fmt" |
||
Line 8,805: | Line 8,805: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
The output: |
The output: |
||
Line 8,815: | Line 8,815: | ||
===Incremental Odds-only Sieve=== |
===Incremental Odds-only Sieve=== |
||
Uses Go's built-in hash tables to store odd composites, and defers adding new known composites until the square is seen. |
Uses Go's built-in hash tables to store odd composites, and defers adding new known composites until the square is seen. |
||
<syntaxhighlight lang=go> |
|||
<lang go> |
|||
package main |
package main |
||
Line 8,874: | Line 8,874: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
The output: |
The output: |
||
<pre> |
<pre> |
||
Line 8,882: | Line 8,882: | ||
=={{header|Groovy}}== |
=={{header|Groovy}}== |
||
This solution uses a BitSet for compactness and speed, but in [[Groovy]], BitSet has full List semantics. It also uses both the "square root of the boundary" shortcut and the "square of the prime" shortcut. |
This solution uses a BitSet for compactness and speed, but in [[Groovy]], BitSet has full List semantics. It also uses both the "square root of the boundary" shortcut and the "square of the prime" shortcut. |
||
< |
<syntaxhighlight lang=groovy>def sievePrimes = { bound -> |
||
def isPrime = new BitSet(bound) |
def isPrime = new BitSet(bound) |
||
isPrime[0..1] = false |
isPrime[0..1] = false |
||
Line 8,892: | Line 8,892: | ||
} |
} |
||
(0..bound).findAll { isPrime[it] } |
(0..bound).findAll { isPrime[it] } |
||
}</ |
}</syntaxhighlight> |
||
Test: |
Test: |
||
<lang |
<syntaxhighlight lang=groovy>println sievePrimes(100)</syntaxhighlight> |
||
Output: |
Output: |
||
Line 8,902: | Line 8,902: | ||
=={{header|GW-BASIC}}== |
=={{header|GW-BASIC}}== |
||
< |
<syntaxhighlight lang=qbasic>10 INPUT "ENTER NUMBER TO SEARCH TO: ";LIMIT |
||
20 DIM FLAGS(LIMIT) |
20 DIM FLAGS(LIMIT) |
||
30 FOR N = 2 TO SQR (LIMIT) |
30 FOR N = 2 TO SQR (LIMIT) |
||
Line 8,913: | Line 8,913: | ||
100 FOR N = 2 TO LIMIT |
100 FOR N = 2 TO LIMIT |
||
110 IF FLAGS(N) = 0 THEN PRINT N;", "; |
110 IF FLAGS(N) = 0 THEN PRINT N;", "; |
||
120 NEXT N</ |
120 NEXT N</syntaxhighlight> |
||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
Line 8,920: | Line 8,920: | ||
Mutable array of unboxed <code>Bool</code>s indexed by <code>Int</code>s: |
Mutable array of unboxed <code>Bool</code>s indexed by <code>Int</code>s: |
||
< |
<syntaxhighlight lang=haskell>{-# LANGUAGE FlexibleContexts #-} -- too lazy to write contexts... |
||
{-# OPTIONS_GHC -O2 #-} |
{-# OPTIONS_GHC -O2 #-} |
||
Line 8,955: | Line 8,955: | ||
putStrLn $ "Found " ++ show answr ++ " to " ++ show top ++ |
putStrLn $ "Found " ++ show answr ++ " to " ++ show top ++ |
||
" in " ++ show elpsd ++ " milliseconds."</ |
" in " ++ show elpsd ++ " milliseconds."</syntaxhighlight> |
||
The above code chooses conciseness and elegance over speed, but it isn't too slow: |
The above code chooses conciseness and elegance over speed, but it isn't too slow: |
||
Line 8,968: | Line 8,968: | ||
Mutable array of unboxed <code>Bool</code>s indexed by <code>Int</code>s, representing odds only: |
Mutable array of unboxed <code>Bool</code>s indexed by <code>Int</code>s, representing odds only: |
||
< |
<syntaxhighlight lang=haskell>import Control.Monad (forM_, when) |
||
import Control.Monad.ST |
import Control.Monad.ST |
||
import Data.Array.ST |
import Data.Array.ST |
||
Line 8,987: | Line 8,987: | ||
primesToUO :: Int -> [Int] |
primesToUO :: Int -> [Int] |
||
primesToUO top | top > 1 = 2 : [2*i + 1 | (i,True) <- assocs $ sieveUO top] |
primesToUO top | top > 1 = 2 : [2*i + 1 | (i,True) <- assocs $ sieveUO top] |
||
| otherwise = []</ |
| otherwise = []</syntaxhighlight> |
||
This represents ''odds only'' in the array. [http://ideone.com/KwZNc Empirical orders of growth] is ~ <i>n<sup>1.2</sup></i> in ''n'' primes produced, and improving for bigger ''n''‍ ‍s. Memory consumption is low (array seems to be packed) and growing about linearly with ''n''. Can further be [http://ideone.com/j24jxV significantly sped up] by re-writing the <code>forM_</code> loops with direct recursion, and using <code>unsafeRead</code> and <code>unsafeWrite</code> operations. |
This represents ''odds only'' in the array. [http://ideone.com/KwZNc Empirical orders of growth] is ~ <i>n<sup>1.2</sup></i> in ''n'' primes produced, and improving for bigger ''n''‍ ‍s. Memory consumption is low (array seems to be packed) and growing about linearly with ''n''. Can further be [http://ideone.com/j24jxV significantly sped up] by re-writing the <code>forM_</code> loops with direct recursion, and using <code>unsafeRead</code> and <code>unsafeWrite</code> operations. |
||
Line 8,999: | Line 8,999: | ||
The reason for this alternate version is to have an accessible version of "odds only" that uses the same optimizations and is written in the same coding style as the basic version. This can be used by just substituting the following code for the function of the same name in the first base example above. Mutable array of unboxed <code>Bool</code>s indexed by <code>Int</code>s, representing odds only: |
The reason for this alternate version is to have an accessible version of "odds only" that uses the same optimizations and is written in the same coding style as the basic version. This can be used by just substituting the following code for the function of the same name in the first base example above. Mutable array of unboxed <code>Bool</code>s indexed by <code>Int</code>s, representing odds only: |
||
< |
<syntaxhighlight lang=haskell>primesTo :: Int -> [Int] -- generate a list of primes to given limit... |
||
primesTo limit |
primesTo limit |
||
| limit < 2 = [] |
| limit < 2 = [] |
||
Line 9,012: | Line 9,012: | ||
$ takeWhile ((>=) lmt . snd) -- for bp's <= square root limit |
$ takeWhile ((>=) lmt . snd) -- for bp's <= square root limit |
||
[ getbpndx i | (i, False) <- assocs oddcmpstsf ] |
[ getbpndx i | (i, False) <- assocs oddcmpstsf ] |
||
return $ 2 : [ i + i + 3 | (i, False) <- assocs oddcmpstsf ]</ |
return $ 2 : [ i + i + 3 | (i, False) <- assocs oddcmpstsf ]</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 9,035: | Line 9,035: | ||
===Immutable arrays=== |
===Immutable arrays=== |
||
Monolithic sieving array. ''Even'' numbers above 2 are pre-marked as composite, and sieving is done only by ''odd'' multiples of ''odd'' primes: |
Monolithic sieving array. ''Even'' numbers above 2 are pre-marked as composite, and sieving is done only by ''odd'' multiples of ''odd'' primes: |
||
< |
<syntaxhighlight lang=haskell>import Data.Array.Unboxed |
||
primesToA m = sieve 3 (array (3,m) [(i,odd i) | i<-[3..m]] :: UArray Int Bool) |
primesToA m = sieve 3 (array (3,m) [(i,odd i) | i<-[3..m]] :: UArray Int Bool) |
||
Line 9,042: | Line 9,042: | ||
| p*p > m = 2 : [i | (i,True) <- assocs a] |
| p*p > m = 2 : [i | (i,True) <- assocs a] |
||
| a!p = sieve (p+2) $ a//[(i,False) | i <- [p*p, p*p+2*p..m]] |
| a!p = sieve (p+2) $ a//[(i,False) | i <- [p*p, p*p+2*p..m]] |
||
| otherwise = sieve (p+2) a</ |
| otherwise = sieve (p+2) a</syntaxhighlight> |
||
Its performance sharply depends on compiler optimizations. Compiled with -O2 flag in the presence of the explicit type signature, it is very fast in producing first few million primes. <code>(//)</code> is an array update operator. |
Its performance sharply depends on compiler optimizations. Compiled with -O2 flag in the presence of the explicit type signature, it is very fast in producing first few million primes. <code>(//)</code> is an array update operator. |
||
Line 9,049: | Line 9,049: | ||
Works by segments between consecutive primes' squares. Should be the fastest of non-monadic code. ''Evens'' are entirely ignored: |
Works by segments between consecutive primes' squares. Should be the fastest of non-monadic code. ''Evens'' are entirely ignored: |
||
< |
<syntaxhighlight lang=haskell>import Data.Array.Unboxed |
||
primesSA = 2 : prs () |
primesSA = 2 : prs () |
||
Line 9,061: | Line 9,061: | ||
a :: UArray Int Bool |
a :: UArray Int Bool |
||
a = accumArray (\ b c -> False) True (1,q-1) |
a = accumArray (\ b c -> False) True (1,q-1) |
||
[(i,()) | (s,y) <- fs, i <- [y+s, y+s+s..q]]</ |
[(i,()) | (s,y) <- fs, i <- [y+s, y+s+s..q]]</syntaxhighlight> |
||
===Basic list-based sieve=== |
===Basic list-based sieve=== |
||
Straightforward implementation of the sieve of Eratosthenes in its original bounded form. This finds primes in gaps between the composites, and composites as an enumeration of each prime's multiples. |
Straightforward implementation of the sieve of Eratosthenes in its original bounded form. This finds primes in gaps between the composites, and composites as an enumeration of each prime's multiples. |
||
< |
<syntaxhighlight lang=haskell>primesTo m = eratos [2..m] where |
||
eratos (p : xs) |
eratos (p : xs) |
||
| p*p > m = p : xs |
| p*p > m = p : xs |
||
Line 9,076: | Line 9,076: | ||
EQ -> minus xs ys |
EQ -> minus xs ys |
||
GT -> minus a ys |
GT -> minus a ys |
||
minus a b = a </ |
minus a b = a </syntaxhighlight> |
||
Its time complexity is similar to that of optimal [[Primality_by_trial_division#Haskell|trial division]] because of limitations of Haskell linked lists, where <code>(minus a b)</code> takes time proportional to <code>length(union a b)</code> and not <code>(length b)</code>, as achieved in imperative setting with direct-access memory. Uses ordered list representation of sets. |
Its time complexity is similar to that of optimal [[Primality_by_trial_division#Haskell|trial division]] because of limitations of Haskell linked lists, where <code>(minus a b)</code> takes time proportional to <code>length(union a b)</code> and not <code>(length b)</code>, as achieved in imperative setting with direct-access memory. Uses ordered list representation of sets. |
||
Line 9,083: | Line 9,083: | ||
===Unbounded list based sieve=== |
===Unbounded list based sieve=== |
||
Unbounded, "naive", too eager to subtract (see above for the definition of <code>minus</code>): |
Unbounded, "naive", too eager to subtract (see above for the definition of <code>minus</code>): |
||
< |
<syntaxhighlight lang=haskell>primesE = sieve [2..] |
||
where |
where |
||
sieve (p:xs) = p : sieve (minus xs [p, p+p..]) |
sieve (p:xs) = p : sieve (minus xs [p, p+p..]) |
||
-- unfoldr (\(p:xs)-> Just (p, minus xs [p, p+p..])) [2..]</ |
-- unfoldr (\(p:xs)-> Just (p, minus xs [p, p+p..])) [2..]</syntaxhighlight> |
||
This is slow, with complexity increasing as a square law or worse so that it is only moderately useful for the first few thousand primes or so. |
This is slow, with complexity increasing as a square law or worse so that it is only moderately useful for the first few thousand primes or so. |
||
The number of active streams can be limited to what's strictly necessary by postponement until the square of a prime is seen, getting a massive complexity improvement to better than <i>~ n<sup>1.5</sup></i> so it can get first million primes or so in a tolerable time: |
The number of active streams can be limited to what's strictly necessary by postponement until the square of a prime is seen, getting a massive complexity improvement to better than <i>~ n<sup>1.5</sup></i> so it can get first million primes or so in a tolerable time: |
||
< |
<syntaxhighlight lang=haskell>primesPE = 2 : sieve [3..] 4 primesPE |
||
where |
where |
||
sieve (x:xs) q (p:t) |
sieve (x:xs) q (p:t) |
||
Line 9,097: | Line 9,097: | ||
-- fix $ (2:) . concat |
-- fix $ (2:) . concat |
||
-- . unfoldr (\(p:ps,xs)-> Just . second ((ps,) . (`minus` [p*p, p*p+p..])) |
-- . unfoldr (\(p:ps,xs)-> Just . second ((ps,) . (`minus` [p*p, p*p+p..])) |
||
-- . span (< p*p) $ xs) . (,[3..]) </ |
-- . span (< p*p) $ xs) . (,[3..]) </syntaxhighlight> |
||
Transposing the workflow, going by segments between the consecutive squares of primes: |
Transposing the workflow, going by segments between the consecutive squares of primes: |
||
< |
<syntaxhighlight lang=haskell>import Data.List (inits) |
||
primesSE = 2 : sieve 3 4 (tail primesSE) (inits primesSE) |
primesSE = 2 : sieve 3 4 (tail primesSE) (inits primesSE) |
||
Line 9,109: | Line 9,109: | ||
-- True (x,q-1) [(i,()) | f <- fs, let n=div(x+f-1)f*f, |
-- True (x,q-1) [(i,()) | f <- fs, let n=div(x+f-1)f*f, |
||
-- i <- [n, n+f..q-1]] :: UArray Int Bool )] |
-- i <- [n, n+f..q-1]] :: UArray Int Bool )] |
||
++ sieve q (head ps^2) (tail ps) ft</ |
++ sieve q (head ps^2) (tail ps) ft</syntaxhighlight> |
||
The basic gradually-deepening left-leaning <code>(((a-b)-c)- ... )</code> workflow of <code>foldl minus a bs</code> above can be rearranged into the right-leaning <code>(a-(b+(c+ ... )))</code> workflow of <code>minus a (foldr union [] bs)</code>. This is the idea behind Richard Bird's unbounded code presented in [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf M. O'Neill's article], equivalent to: |
The basic gradually-deepening left-leaning <code>(((a-b)-c)- ... )</code> workflow of <code>foldl minus a bs</code> above can be rearranged into the right-leaning <code>(a-(b+(c+ ... )))</code> workflow of <code>minus a (foldr union [] bs)</code>. This is the idea behind Richard Bird's unbounded code presented in [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf M. O'Neill's article], equivalent to: |
||
< |
<syntaxhighlight lang=haskell>primesB = _Y ( (2:) . minus [3..] . foldr (\p-> (p*p :) . union [p*p+p, p*p+2*p..]) [] ) |
||
-- = _Y ( (2:) . minus [3..] . _LU . map(\p-> [p*p, p*p+p..]) ) |
-- = _Y ( (2:) . minus [3..] . _LU . map(\p-> [p*p, p*p+p..]) ) |
||
Line 9,126: | Line 9,126: | ||
LT -> x : union xs b |
LT -> x : union xs b |
||
EQ -> x : union xs ys |
EQ -> x : union xs ys |
||
GT -> y : union a ys</ |
GT -> y : union a ys</syntaxhighlight> |
||
Using <code>_Y</code> is meant to guarantee the separate supply of primes to be independently calculated, recursively, instead of the same one being reused, corecursively; thus the memory footprint is drastically reduced. This idea was introduced by M. ONeill as a double-staged production, with a separate primes feed. |
Using <code>_Y</code> is meant to guarantee the separate supply of primes to be independently calculated, recursively, instead of the same one being reused, corecursively; thus the memory footprint is drastically reduced. This idea was introduced by M. ONeill as a double-staged production, with a separate primes feed. |
||
Line 9,136: | Line 9,136: | ||
This merges primes' multiples streams in a ''tree''-like fashion, as a sequence of balanced trees of <code>union</code> nodes, likely achieving theoretical time complexity only a ''log n'' factor above the optimal ''n log n log (log n)'', for ''n'' primes produced. Indeed, empirically it runs at about ''~ n<sup>1.2</sup>'' (for producing first few million primes), similarly to priority-queue–based version of M. O'Neill's, and with very low space complexity too (not counting the produced sequence of course): |
This merges primes' multiples streams in a ''tree''-like fashion, as a sequence of balanced trees of <code>union</code> nodes, likely achieving theoretical time complexity only a ''log n'' factor above the optimal ''n log n log (log n)'', for ''n'' primes produced. Indeed, empirically it runs at about ''~ n<sup>1.2</sup>'' (for producing first few million primes), similarly to priority-queue–based version of M. O'Neill's, and with very low space complexity too (not counting the produced sequence of course): |
||
< |
<syntaxhighlight lang=haskell>primes :: () -> [Int] |
||
primes() = 2 : _Y ((3:) . gaps 5 . _U . map(\p-> [p*p, p*p+2*p..])) where |
primes() = 2 : _Y ((3:) . gaps 5 . _U . map(\p-> [p*p, p*p+2*p..])) where |
||
_Y g = g (_Y g) -- = g (g (g ( ... ))) non-sharing multistage fixpoint combinator |
_Y g = g (_Y g) -- = g (g (g ( ... ))) non-sharing multistage fixpoint combinator |
||
Line 9,145: | Line 9,145: | ||
merge xs@(x:xt) ys@(y:yt) | x < y = x : merge xt ys |
merge xs@(x:xt) ys@(y:yt) | x < y = x : merge xt ys |
||
| y < x = y : merge xs yt |
| y < x = y : merge xs yt |
||
| otherwise = x : merge xt yt</ |
| otherwise = x : merge xt yt</syntaxhighlight> |
||
Works with odds only, the simplest kind of wheel. Here's the [http://ideone.com/qpnqe test entry] on Ideone.com, and a [http://ideone.com/p0e81 comparison with more versions]. |
Works with odds only, the simplest kind of wheel. Here's the [http://ideone.com/qpnqe test entry] on Ideone.com, and a [http://ideone.com/p0e81 comparison with more versions]. |
||
Line 9,151: | Line 9,151: | ||
====With Wheel==== |
====With Wheel==== |
||
Using <code>_U</code> defined above, |
Using <code>_U</code> defined above, |
||
< |
<syntaxhighlight lang=haskell>primesW :: [Int] |
||
primesW = [2,3,5,7] ++ _Y ( (11:) . gapsW 13 (tail wheel) . _U . |
primesW = [2,3,5,7] ++ _Y ( (11:) . gapsW 13 (tail wheel) . _U . |
||
map (\p-> |
map (\p-> |
||
Line 9,162: | Line 9,162: | ||
wheel = 2:4:2:4:6:2:6:4:2:4:6:6:2:6:4:2:6:4:6:8:4:2:4:2: -- gaps = (`gapsW` cycle [2]) |
wheel = 2:4:2:4:6:2:6:4:2:4:6:6:2:6:4:2:6:4:6:8:4:2:4:2: -- gaps = (`gapsW` cycle [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:wheel |
4:8:6:4:6:2:4:6:2:6:6:4:2:4:6:2:6:4:2:4:2:10:2:10:wheel |
||
-- cycle $ zipWith (-) =<< tail $ [i | i <- [11..221], gcd i 210 == 1]</ |
-- cycle $ zipWith (-) =<< tail $ [i | i <- [11..221], gcd i 210 == 1]</syntaxhighlight> |
||
Used [[Emirp_primes#List-based|here]] and [[Extensible_prime_generator#List_based|here]]. |
Used [[Emirp_primes#List-based|here]] and [[Extensible_prime_generator#List_based|here]]. |
||
Line 9,172: | Line 9,172: | ||
2. Improving the means to re-generate the position on the wheel for the recursive base primes without the use of `dropWhile`, etc. The below improved code uses a copy of the place in the wheel for each found base prime for ease of use in generating the composite number to-be-culled chains. |
2. Improving the means to re-generate the position on the wheel for the recursive base primes without the use of `dropWhile`, etc. The below improved code uses a copy of the place in the wheel for each found base prime for ease of use in generating the composite number to-be-culled chains. |
||
< |
<syntaxhighlight lang=haskell>-- autogenerates wheel primes, first sieve prime, and gaps |
||
wheelGen :: Int -> ([Int],Int,[Int]) |
wheelGen :: Int -> ([Int],Int,[Int]) |
||
wheelGen n = loop 1 3 [2] [2] where |
wheelGen n = loop 1 3 [2] [2] where |
||
Line 9,209: | Line 9,209: | ||
| x < y = x : union xs' ys |
| x < y = x : union xs' ys |
||
| y < x = y : union xs ys' |
| y < x = y : union xs ys' |
||
| otherwise = x : union xs' ys' -- x and y must be equal!</ |
| otherwise = x : union xs' ys' -- x and y must be equal!</syntaxhighlight> |
||
When compiled with -O2 optimization and -fllvm (the LLVM back end), the above code is over twice as fast as the Odds-Only version as it should be as that is about the ratio of reduced operations minus some slightly increased operation complexity, sieving the primes to a hundred million in about seven seconds on a modern middle range desktop computer. It is almost twice as fast as the "primesW" version due to the increased algorithmic efficiency! |
When compiled with -O2 optimization and -fllvm (the LLVM back end), the above code is over twice as fast as the Odds-Only version as it should be as that is about the ratio of reduced operations minus some slightly increased operation complexity, sieving the primes to a hundred million in about seven seconds on a modern middle range desktop computer. It is almost twice as fast as the "primesW" version due to the increased algorithmic efficiency! |
||
Line 9,220: | Line 9,220: | ||
In order to implement a Priority Queue version with Haskell, an efficient Priority Queue, which is not part of the standard Haskell libraries, is required. A Min Heap implementation is likely best suited for this task in providing the most efficient frequently used peeks of the next item in the queue and replacement of the first item in the queue (not using a "pop" followed by a "push) with "pop" operations then not used at all, and "push" operations used relatively infrequently. Judging by O'Neill's use of an efficient "deleteMinAndInsert" operation which she states "(We provide deleteMinAndInsert becausea heap-based implementation can support this operation with considerably less rearrangement than a deleteMin followed by an insert.)", which statement is true for a Min Heap Priority Queue and not others, and her reference to a priority queue by (Paulson, 1996), the queue she used is likely the one as provided as a simple true functional [http://rosettacode.org/wiki/Priority_queue#Haskell Min Heap implementation on RosettaCode], from which the essential functions are reproduced here: |
In order to implement a Priority Queue version with Haskell, an efficient Priority Queue, which is not part of the standard Haskell libraries, is required. A Min Heap implementation is likely best suited for this task in providing the most efficient frequently used peeks of the next item in the queue and replacement of the first item in the queue (not using a "pop" followed by a "push) with "pop" operations then not used at all, and "push" operations used relatively infrequently. Judging by O'Neill's use of an efficient "deleteMinAndInsert" operation which she states "(We provide deleteMinAndInsert becausea heap-based implementation can support this operation with considerably less rearrangement than a deleteMin followed by an insert.)", which statement is true for a Min Heap Priority Queue and not others, and her reference to a priority queue by (Paulson, 1996), the queue she used is likely the one as provided as a simple true functional [http://rosettacode.org/wiki/Priority_queue#Haskell Min Heap implementation on RosettaCode], from which the essential functions are reproduced here: |
||
< |
<syntaxhighlight lang=haskell>data PriorityQ k v = Mt |
||
| Br !k v !(PriorityQ k v) !(PriorityQ k v) |
| Br !k v !(PriorityQ k v) !(PriorityQ k v) |
||
deriving (Eq, Ord, Read, Show) |
deriving (Eq, Ord, Read, Show) |
||
Line 9,249: | Line 9,249: | ||
replaceMinPQ :: Ord k => k -> v -> PriorityQ k v -> PriorityQ k v |
replaceMinPQ :: Ord k => k -> v -> PriorityQ k v -> PriorityQ k v |
||
replaceMinPQ wk wv Mt = Mt |
replaceMinPQ wk wv Mt = Mt |
||
replaceMinPQ wk wv (Br _ _ pl pr) = siftdown wk wv pl pr</ |
replaceMinPQ wk wv (Br _ _ pl pr) = siftdown wk wv pl pr</syntaxhighlight> |
||
The "peekMin" function retrieves both the key and value in a tuple so processing is required to access whichever is required for further processing. As well, the output of the peekMin function is a Maybe with the case of an empty queue providing a Nothing output. |
The "peekMin" function retrieves both the key and value in a tuple so processing is required to access whichever is required for further processing. As well, the output of the peekMin function is a Maybe with the case of an empty queue providing a Nothing output. |
||
The following code is O'Neill's original odds-only code (without wheel factorization) from her paper slightly adjusted as per the requirements of this Min Heap implementation as laid out above; note the `seq` adjustments to the "adjust" function to make the evaluation of the entry tuple more strict for better efficiency: |
The following code is O'Neill's original odds-only code (without wheel factorization) from her paper slightly adjusted as per the requirements of this Min Heap implementation as laid out above; note the `seq` adjustments to the "adjust" function to make the evaluation of the entry tuple more strict for better efficiency: |
||
< |
<syntaxhighlight lang=haskell>-- (c) 2006-2007 Melissa O'Neill. Code may be used freely so long as |
||
-- this copyright message is retained and changed versions of the file |
-- this copyright message is retained and changed versions of the file |
||
-- are clearly marked. |
-- are clearly marked. |
||
Line 9,277: | Line 9,277: | ||
| otherwise = table |
| otherwise = table |
||
where (n, n':ns) = case peekMinPQ table of |
where (n, n':ns) = case peekMinPQ table of |
||
Just tpl -> tpl</ |
Just tpl -> tpl</syntaxhighlight> |
||
The above code is almost four times slower than the version of the Tree Merging sieve above for the first million primes although it is about the same speed as the original Richard Bird sieve with the "odds-only" adaptation as above. It is slow and uses a huge amount of memory for primarily one reason: over eagerness in adding prime composite streams to the queue, which are added as the primes are listed rather than when they are required as the output primes stream reaches the square of a given base prime; this over eagerness also means that the processed numbers must have a large range in order to not overflow when squared (as in the default Integer = infinite precision integers as used here and by O'Neill, but Int64's or Word64's would give a practical range) which processing of wide range numbers adds processing and memory requirement overhead. Although O'Neill's code is elegant, it also loses some efficiency due to the extensive use of lazy list processing, not all of which is required even for a wheel factorization implementation. |
The above code is almost four times slower than the version of the Tree Merging sieve above for the first million primes although it is about the same speed as the original Richard Bird sieve with the "odds-only" adaptation as above. It is slow and uses a huge amount of memory for primarily one reason: over eagerness in adding prime composite streams to the queue, which are added as the primes are listed rather than when they are required as the output primes stream reaches the square of a given base prime; this over eagerness also means that the processed numbers must have a large range in order to not overflow when squared (as in the default Integer = infinite precision integers as used here and by O'Neill, but Int64's or Word64's would give a practical range) which processing of wide range numbers adds processing and memory requirement overhead. Although O'Neill's code is elegant, it also loses some efficiency due to the extensive use of lazy list processing, not all of which is required even for a wheel factorization implementation. |
||
The following code is adjusted to reduce the amount of lazy list processing and to add a secondary base primes stream (or a succession of streams when the combinator is used) so as to overcome the above problems and reduce memory consumption to only that required for the primes below the square root of the currently sieved number; using this means that 32-bit Int's are sufficient for a reasonable range and memory requirements become relatively negligible: |
The following code is adjusted to reduce the amount of lazy list processing and to add a secondary base primes stream (or a succession of streams when the combinator is used) so as to overcome the above problems and reduce memory consumption to only that required for the primes below the square root of the currently sieved number; using this means that 32-bit Int's are sufficient for a reasonable range and memory requirements become relatively negligible: |
||
< |
<syntaxhighlight lang=haskell>primesPQx :: () -> [Int] |
||
primesPQx() = 2 : _Y ((3 :) . sieve 5 emptyPQ 9) -- initBasePrms |
primesPQx() = 2 : _Y ((3 :) . sieve 5 emptyPQ 9) -- initBasePrms |
||
where |
where |
||
Line 9,303: | Line 9,303: | ||
in ntbl `seq` adjust ntbl |
in ntbl `seq` adjust ntbl |
||
| otherwise = table |
| otherwise = table |
||
where (c, adv) = case peekMinPQ table of Just ct -> ct `seq` ct</ |
where (c, adv) = case peekMinPQ table of Just ct -> ct `seq` ct</syntaxhighlight> |
||
The above code is over five times faster than the previous (O'Neill) Priority Queue code half again faster than the Tree-Merging Odds-Only code for a range of a hundred million primes; it is likely faster as the Min Heap is slightly more efficient than Tree Merging due to better tree balancing. |
The above code is over five times faster than the previous (O'Neill) Priority Queue code half again faster than the Tree-Merging Odds-Only code for a range of a hundred million primes; it is likely faster as the Min Heap is slightly more efficient than Tree Merging due to better tree balancing. |
||
Line 9,309: | Line 9,309: | ||
Since the Tree-Folding version above includes the minor changes to work with a factorization wheel, this should have the same minor modifications for comparison purposes, with the code as follows: |
Since the Tree-Folding version above includes the minor changes to work with a factorization wheel, this should have the same minor modifications for comparison purposes, with the code as follows: |
||
< |
<syntaxhighlight lang=haskell>-- Note: this code segment uses the same wheelGen as the Tree-Folding version... |
||
primesPQWheeled :: () -> [Int] |
primesPQWheeled :: () -> [Int] |
||
Line 9,339: | Line 9,339: | ||
in ntbl `seq` adjust ntbl |
in ntbl `seq` adjust ntbl |
||
| otherwise = table |
| otherwise = table |
||
where (c, (a:as')) = case peekMinPQ table of Just ct -> ct `seq` ct</ |
where (c, (a:as')) = case peekMinPQ table of Just ct -> ct `seq` ct</syntaxhighlight> |
||
Compiled with -O2 optimization and -fllvm (the LLVM back end), this code gains about the expected ratio in performance in sieving to a range of a hundred million, sieving to this range in about five seconds on a modern medium range desktop computer. This is likely the fastest purely functional incremental type SoE useful for moderate ranges up to about a hundred million to a billion. |
Compiled with -O2 optimization and -fllvm (the LLVM back end), this code gains about the expected ratio in performance in sieving to a range of a hundred million, sieving to this range in about five seconds on a modern medium range desktop computer. This is likely the fastest purely functional incremental type SoE useful for moderate ranges up to about a hundred million to a billion. |
||
Line 9,346: | Line 9,346: | ||
All of the above unbounded sieves are quite limited in practical sieving range due to the large constant factor overheads in computation, making them mostly just interesting intellectual exercises other than for small ranges of up to about the first million to ten million primes; the following '''"odds-only"''' page-segmented version using (bit-packed internally) mutable unboxed arrays is about 50 times faster than the fastest of the above algorithms for ranges of about that and higher, making it practical for the first several hundred million primes: |
All of the above unbounded sieves are quite limited in practical sieving range due to the large constant factor overheads in computation, making them mostly just interesting intellectual exercises other than for small ranges of up to about the first million to ten million primes; the following '''"odds-only"''' page-segmented version using (bit-packed internally) mutable unboxed arrays is about 50 times faster than the fastest of the above algorithms for ranges of about that and higher, making it practical for the first several hundred million primes: |
||
< |
<syntaxhighlight lang=haskell>{-# OPTIONS_GHC -O2 -fllvm #-} -- use LLVM for about double speed! |
||
import Data.Int ( Int64 ) |
import Data.Int ( Int64 ) |
||
Line 9,387: | Line 9,387: | ||
return cmpsts |
return cmpsts |
||
pagesFrom lwi bps = map (`makePg` bps) |
pagesFrom lwi bps = map (`makePg` bps) |
||
[ lwi, lwi + fromIntegral szblmt + 1 .. ]</ |
[ lwi, lwi + fromIntegral szblmt + 1 .. ]</syntaxhighlight> |
||
The above code as written has a maximum practical range of about 10^12 or so in about an hour. |
The above code as written has a maximum practical range of about 10^12 or so in about an hour. |
||
Line 9,405: | Line 9,405: | ||
To show the limitations of the individual prime enumeration, the following code has been refactored from the above to provide an alternate very fast method of counting the unset bits in the culled array (the primes = none composite) using a CPU native pop count instruction: |
To show the limitations of the individual prime enumeration, the following code has been refactored from the above to provide an alternate very fast method of counting the unset bits in the culled array (the primes = none composite) using a CPU native pop count instruction: |
||
< |
<syntaxhighlight lang=haskell>{-# LANGUAGE FlexibleContexts #-} |
||
{-# OPTIONS_GHC -O2 -fllvm #-} -- use LLVM for about double speed! |
{-# OPTIONS_GHC -O2 -fllvm #-} -- use LLVM for about double speed! |
||
Line 9,508: | Line 9,508: | ||
putStr $ "Found " ++ show answr |
putStr $ "Found " ++ show answr |
||
putStr $ " primes up to " ++ show limit |
putStr $ " primes up to " ++ show limit |
||
putStrLn $ " in " ++ show elpsd ++ " milliseconds."</ |
putStrLn $ " in " ++ show elpsd ++ " milliseconds."</syntaxhighlight> |
||
When compiled with the "fast way" commented out and the "slow way enabled, the time to find the number of primes up to one billion is about 3.65 seconds on an Intel Sandy Bridge i3-2100 at 3.1 Ghz; with the "fast way" enabled instead, the time is only about 1.45 seconds for the same range, both compiled with the LLVM back end. This shows that more than half of the time for the "slow way" is spent just producing and enumerating the list of primes! |
When compiled with the "fast way" commented out and the "slow way enabled, the time to find the number of primes up to one billion is about 3.65 seconds on an Intel Sandy Bridge i3-2100 at 3.1 Ghz; with the "fast way" enabled instead, the time is only about 1.45 seconds for the same range, both compiled with the LLVM back end. This shows that more than half of the time for the "slow way" is spent just producing and enumerating the list of primes! |
||
Line 9,524: | Line 9,524: | ||
===APL-style=== |
===APL-style=== |
||
Rolling set subtraction over the rolling element-wise addition on integers. Basic, slow, worse than quadratic in the number of primes produced, empirically: |
Rolling set subtraction over the rolling element-wise addition on integers. Basic, slow, worse than quadratic in the number of primes produced, empirically: |
||
< |
<syntaxhighlight lang=haskell>zipWith (flip (!!)) [0..] -- or: take n . last . take n ... |
||
. scanl1 minus |
. scanl1 minus |
||
. scanl1 (zipWith (+)) $ repeat [2..]</ |
. scanl1 (zipWith (+)) $ repeat [2..]</syntaxhighlight> |
||
Or, a wee bit faster: |
Or, a wee bit faster: |
||
< |
<syntaxhighlight lang=haskell>unfoldr (\(a:b:t) -> Just . (head &&& (:t) . (`minus` b) |
||
. tail) $ a) |
. tail) $ a) |
||
. scanl1 (zipWith (+)) $ repeat [2..]</ |
. scanl1 (zipWith (+)) $ repeat [2..]</syntaxhighlight> |
||
A bit optimized, much faster, with better complexity, |
A bit optimized, much faster, with better complexity, |
||
< |
<syntaxhighlight lang=haskell>tail . concat |
||
. unfoldr (\(a:b:t) -> Just . second ((:t) . (`minus` b)) |
. unfoldr (\(a:b:t) -> Just . second ((:t) . (`minus` b)) |
||
. span (< head b) $ a) |
. span (< head b) $ a) |
||
. scanl1 (zipWith (+) . tail) $ tails [1..] |
. scanl1 (zipWith (+) . tail) $ tails [1..] |
||
-- $ [ [n*n, n*n+n..] | n <- [1..] ]</ |
-- $ [ [n*n, n*n+n..] | n <- [1..] ]</syntaxhighlight> |
||
getting nearer to the functional equivalent of the <code>primesPE</code> above, i.e. |
getting nearer to the functional equivalent of the <code>primesPE</code> above, i.e. |
||
< |
<syntaxhighlight lang=haskell>fix ( (2:) . concat |
||
. unfoldr (\(a:b:t) -> Just . second ((:t) . (`minus` b)) |
. unfoldr (\(a:b:t) -> Just . second ((:t) . (`minus` b)) |
||
. span (< head b) $ a) |
. span (< head b) $ a) |
||
. ([3..] :) . map (\p-> [p*p, p*p+p..]) )</ |
. ([3..] :) . map (\p-> [p*p, p*p+p..]) )</syntaxhighlight> |
||
An illustration: |
An illustration: |
||
< |
<syntaxhighlight lang=haskell>> mapM_ (print . take 15) $ take 10 $ scanl1 (zipWith(+)) $ repeat [2..] |
||
[ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] |
[ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] |
||
[ 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32] |
[ 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32] |
||
Line 9,567: | Line 9,567: | ||
[ 64, 72, 80, 88, 96,104,112,120,128,136,144,152,160,168,176] |
[ 64, 72, 80, 88, 96,104,112,120,128,136,144,152,160,168,176] |
||
[ 81, 90, 99,108,117,126,135,144,153,162,171,180,189,198,207] |
[ 81, 90, 99,108,117,126,135,144,153,162,171,180,189,198,207] |
||
[100,110,120,130,140,150,160,170,180,190,200,210,220,230,240]</ |
[100,110,120,130,140,150,160,170,180,190,200,210,220,230,240]</syntaxhighlight> |
||
=={{header|HicEst}}== |
=={{header|HicEst}}== |
||
< |
<syntaxhighlight lang=hicest>REAL :: N=100, sieve(N) |
||
sieve = $ > 1 ! = 0 1 1 1 1 ... |
sieve = $ > 1 ! = 0 1 1 1 1 ... |
||
Line 9,583: | Line 9,583: | ||
DO i = 1, N |
DO i = 1, N |
||
IF( sieve(i) ) WRITE() i |
IF( sieve(i) ) WRITE() i |
||
ENDDO </ |
ENDDO </syntaxhighlight> |
||
=={{header|Hoon}}== |
=={{header|Hoon}}== |
||
< |
<syntaxhighlight lang=hoon>:: Find primes by the sieve of Eratosthenes |
||
!: |
!: |
||
|= end=@ud |
|= end=@ud |
||
Line 9,594: | Line 9,594: | ||
?: (gte index (lent primes)) primes |
?: (gte index (lent primes)) primes |
||
$(index +(index), primes +:(skid primes |=([a=@ud] &((gth a index) =(0 (mod a index)))))) |
$(index +(index), primes +:(skid primes |=([a=@ud] &((gth a index) =(0 (mod a index)))))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Icon}} and {{header|Unicon}}== |
=={{header|Icon}} and {{header|Unicon}}== |
||
< |
<syntaxhighlight lang=Icon> procedure main() |
||
sieve(100) |
sieve(100) |
||
end |
end |
||
Line 9,607: | Line 9,607: | ||
do p[j] := 0 |
do p[j] := 0 |
||
every write(i:=2 to n & p[i] == 1 & i) |
every write(i:=2 to n & p[i] == 1 & i) |
||
end</ |
end</syntaxhighlight> |
||
Alternatively using sets |
Alternatively using sets |
||
< |
<syntaxhighlight lang=Icon> procedure main() |
||
sieve(100) |
sieve(100) |
||
end |
end |
||
Line 9,621: | Line 9,621: | ||
delete(primes,1) |
delete(primes,1) |
||
every write(!sort(primes)) |
every write(!sort(primes)) |
||
end</ |
end</syntaxhighlight> |
||
=={{header|J}}== |
=={{header|J}}== |
||
{{eff note|J|i.&.(p:inv) }} |
{{eff note|J|i.&.(p:inv) }} |
||
Implementation:< |
Implementation:<syntaxhighlight lang=J>sieve=: {{ |
||
r=. 0#t=. y# j=.1 |
r=. 0#t=. y# j=.1 |
||
while. y>j=.j+1 do. |
while. y>j=.j+1 do. |
||
Line 9,634: | Line 9,634: | ||
end. |
end. |
||
end. |
end. |
||
}}</ |
}}</syntaxhighlight> |
||
Example: |
Example: |
||
< |
<syntaxhighlight lang=J> sieve 100 |
||
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97</ |
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97</syntaxhighlight> |
||
To see into how this works, we can change the definition: |
To see into how this works, we can change the definition: |
||
< |
<syntaxhighlight lang=J>sieve=: {{ |
||
r=. 0#t=. y# j=.1 |
r=. 0#t=. y# j=.1 |
||
while. y>j=.j+1 do. |
while. y>j=.j+1 do. |
||
Line 9,651: | Line 9,651: | ||
end. |
end. |
||
end. |
end. |
||
}}</ |
}}</syntaxhighlight> |
||
And go:< |
And go:<syntaxhighlight lang=J> sieve 10 |
||
┌─┬───────────────────┬───────────────────┐ |
┌─┬───────────────────┬───────────────────┐ |
||
│2│1 0 1 0 1 0 1 0 1 0│0 1 0 1 0 1 0 1 0 1│ |
│2│1 0 1 0 1 0 1 0 1 0│0 1 0 1 0 1 0 1 0 1│ |
||
Line 9,666: | Line 9,666: | ||
│7│1 0 0 0 0 0 0 1 0 0│0 1 0 0 0 0 0 0 0 0│ |
│7│1 0 0 0 0 0 0 1 0 0│0 1 0 0 0 0 0 0 0 0│ |
||
└─┴───────────────────┴───────────────────┘ |
└─┴───────────────────┴───────────────────┘ |
||
2 3 5 7</ |
2 3 5 7</syntaxhighlight> |
||
Thus, here, <code>t</code> would select numbers which have not yet been determined to be a multiple of a prime number. |
Thus, here, <code>t</code> would select numbers which have not yet been determined to be a multiple of a prime number. |
||
Line 9,677: | Line 9,677: | ||
This is based off the Python version. |
This is based off the Python version. |
||
< |
<syntaxhighlight lang=janet>(defn primes-before |
||
"Gives all the primes < limit" |
"Gives all the primes < limit" |
||
[limit] |
[limit] |
||
Line 9,698: | Line 9,698: | ||
(if (buffer/bit is-prime i) |
(if (buffer/bit is-prime i) |
||
(array/push res i))) |
(array/push res i))) |
||
res)</ |
res)</syntaxhighlight> |
||
=={{header|Java}}== |
=={{header|Java}}== |
||
{{works with|Java|1.5+}} |
{{works with|Java|1.5+}} |
||
< |
<syntaxhighlight lang=java5>import java.util.LinkedList; |
||
public class Sieve{ |
public class Sieve{ |
||
Line 9,724: | Line 9,724: | ||
return primes; |
return primes; |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
To optimize by testing only odd numbers, replace the loop marked "unoptimized" with these lines: |
To optimize by testing only odd numbers, replace the loop marked "unoptimized" with these lines: |
||
< |
<syntaxhighlight lang=java5>nums.add(2); |
||
for(int i = 3;i <= n;i += 2){ |
for(int i = 3;i <= n;i += 2){ |
||
nums.add(i); |
nums.add(i); |
||
}</ |
}</syntaxhighlight> |
||
Version using List: |
Version using List: |
||
< |
<syntaxhighlight lang=java5> |
||
import java.util.ArrayList; |
import java.util.ArrayList; |
||
import java.util.List; |
import java.util.List; |
||
Line 9,752: | Line 9,752: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
Version using a BitSet: |
Version using a BitSet: |
||
< |
<syntaxhighlight lang=java5>import java.util.LinkedList; |
||
import java.util.BitSet; |
import java.util.BitSet; |
||
Line 9,769: | Line 9,769: | ||
return primes; |
return primes; |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
Version using a TreeSet: |
Version using a TreeSet: |
||
< |
<syntaxhighlight lang=java5>import java.util.Set; |
||
import java.util.TreeSet; |
import java.util.TreeSet; |
||
Line 9,800: | Line 9,800: | ||
return list; |
return list; |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
===Infinite iterator=== |
===Infinite iterator=== |
||
Line 9,806: | Line 9,806: | ||
{{trans|Python}} |
{{trans|Python}} |
||
{{works with|Java|1.5+}} |
{{works with|Java|1.5+}} |
||
< |
<syntaxhighlight lang=java5>import java.util.Iterator; |
||
import java.util.PriorityQueue; |
import java.util.PriorityQueue; |
||
import java.math.BigInteger; |
import java.math.BigInteger; |
||
Line 9,859: | Line 9,859: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 9,878: | Line 9,878: | ||
{{trans|Python}} |
{{trans|Python}} |
||
{{works with|Java|1.5+}} |
{{works with|Java|1.5+}} |
||
< |
<syntaxhighlight lang=java5>import java.util.Iterator; |
||
import java.util.HashMap; |
import java.util.HashMap; |
||
Line 9,936: | Line 9,936: | ||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}}<pre>Found 5761455 primes up to 100000000 in 4297 milliseconds.</pre> |
{{out}}<pre>Found 5761455 primes up to 100000000 in 4297 milliseconds.</pre> |
||
Line 9,946: | Line 9,946: | ||
{{trans|JavaScript}} |
{{trans|JavaScript}} |
||
{{works with|Java|1.5+}} |
{{works with|Java|1.5+}} |
||
< |
<syntaxhighlight lang=java5>import java.util.Iterator; |
||
import java.util.ArrayList; |
import java.util.ArrayList; |
||
Line 10,023: | Line 10,023: | ||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}}<pre>Found 50847534 primes up to 1000000000 in 3201 milliseconds.</pre> |
{{out}}<pre>Found 50847534 primes up to 1000000000 in 3201 milliseconds.</pre> |
||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
< |
<syntaxhighlight lang=javascript>function eratosthenes(limit) { |
||
var primes = []; |
var primes = []; |
||
if (limit >= 2) { |
if (limit >= 2) { |
||
Line 10,054: | Line 10,054: | ||
if (typeof print == "undefined") |
if (typeof print == "undefined") |
||
print = (typeof WScript != "undefined") ? WScript.Echo : alert; |
print = (typeof WScript != "undefined") ? WScript.Echo : alert; |
||
print(primes);</ |
print(primes);</syntaxhighlight> |
||
outputs: |
outputs: |
||
<pre>2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97</pre> |
<pre>2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97</pre> |
||
Line 10,060: | Line 10,060: | ||
Substituting the following code for the function for '''an odds-only algorithm using bit packing''' for the array produces code that is many times faster than the above: |
Substituting the following code for the function for '''an odds-only algorithm using bit packing''' for the array produces code that is many times faster than the above: |
||
< |
<syntaxhighlight lang=javascript>function eratosthenes(limit) { |
||
var prms = []; |
var prms = []; |
||
if (limit >= 2) prms = [2]; |
if (limit >= 2) prms = [2]; |
||
Line 10,081: | Line 10,081: | ||
} |
} |
||
return prms; |
return prms; |
||
}</ |
}</syntaxhighlight> |
||
While the above code is quite fast especially using an efficient JavaScript engine such as Google Chrome's V8, it isn't as elegant as it could be using the features of the new EcmaScript6 specification when it comes out about the end of 2014 and when JavaScript engines including those of browsers implement that standard in that we might choose to implement an incremental algorithm iterators or generators similar to as implemented in Python or F# (yield). Meanwhile, we can emulate some of those features by using a simulation of an iterator class (which is easier than using a call-back function) for an '''"infinite" generator based on an Object dictionary''' as in the following odds-only code written as a JavaScript class: |
While the above code is quite fast especially using an efficient JavaScript engine such as Google Chrome's V8, it isn't as elegant as it could be using the features of the new EcmaScript6 specification when it comes out about the end of 2014 and when JavaScript engines including those of browsers implement that standard in that we might choose to implement an incremental algorithm iterators or generators similar to as implemented in Python or F# (yield). Meanwhile, we can emulate some of those features by using a simulation of an iterator class (which is easier than using a call-back function) for an '''"infinite" generator based on an Object dictionary''' as in the following odds-only code written as a JavaScript class: |
||
< |
<syntaxhighlight lang=javascript>var SoEIncClass = (function () { |
||
function SoEIncClass() { |
function SoEIncClass() { |
||
this.n = 0; |
this.n = 0; |
||
Line 10,126: | Line 10,126: | ||
}; |
}; |
||
return SoEIncClass; |
return SoEIncClass; |
||
})();</ |
})();</syntaxhighlight> |
||
The above code can be used to find the nth prime (which would require estimating the required range limit using the previous fixed range code) by using the following code: |
The above code can be used to find the nth prime (which would require estimating the required range limit using the previous fixed range code) by using the following code: |
||
< |
<syntaxhighlight lang=javascript>var gen = new SoEIncClass(); |
||
for (var i = 1; i < 1000000; i++, gen.next()); |
for (var i = 1; i < 1000000; i++, gen.next()); |
||
var prime = gen.next(); |
var prime = gen.next(); |
||
Line 10,136: | Line 10,136: | ||
if (typeof print == "undefined") |
if (typeof print == "undefined") |
||
print = (typeof WScript != "undefined") ? WScript.Echo : alert; |
print = (typeof WScript != "undefined") ? WScript.Echo : alert; |
||
print(prime);</ |
print(prime);</syntaxhighlight> |
||
to produce the following output (about five seconds using Google Chrome's V8 JavaScript engine): |
to produce the following output (about five seconds using Google Chrome's V8 JavaScript engine): |
||
Line 10,146: | Line 10,146: | ||
This can be implemented as '''an "infinite" odds-only generator using page segmentation''' for a considerable speed-up with the alternate JavaScript class code as follows: |
This can be implemented as '''an "infinite" odds-only generator using page segmentation''' for a considerable speed-up with the alternate JavaScript class code as follows: |
||
< |
<syntaxhighlight lang=javascript>var SoEPgClass = (function () { |
||
function SoEPgClass() { |
function SoEPgClass() { |
||
this.bi = -1; // constructor resets the enumeration to start... |
this.bi = -1; // constructor resets the enumeration to start... |
||
Line 10,202: | Line 10,202: | ||
}; |
}; |
||
return SoEPgClass; |
return SoEPgClass; |
||
})();</ |
})();</syntaxhighlight> |
||
The above code is about fifty times faster (about five seconds to calculate 50 million primes to about a billion on the Google Chrome V8 JavaScript engine) than the above dictionary based code. |
The above code is about fifty times faster (about five seconds to calculate 50 million primes to about a billion on the Google Chrome V8 JavaScript engine) than the above dictionary based code. |
||
Line 10,209: | Line 10,209: | ||
function is copy-pasted from above to produce a webpage version for beginners: |
function is copy-pasted from above to produce a webpage version for beginners: |
||
< |
<syntaxhighlight lang=javascript> |
||
<script> |
<script> |
||
function eratosthenes(limit) { |
function eratosthenes(limit) { |
||
Line 10,240: | Line 10,240: | ||
document.write(output); |
document.write(output); |
||
</script> |
</script> |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|JOVIAL}}== |
=={{header|JOVIAL}}== |
||
< |
<syntaxhighlight lang=JOVIAL> |
||
START |
START |
||
FILE MYOUTPUT ... $ ''Insufficient information to complete this declaration'' |
FILE MYOUTPUT ... $ ''Insufficient information to complete this declaration'' |
||
Line 10,297: | Line 10,297: | ||
END |
END |
||
TERM$ |
TERM$ |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|jq}}== |
=={{header|jq}}== |
||
Line 10,304: | Line 10,304: | ||
Short and sweet ... |
Short and sweet ... |
||
< |
<syntaxhighlight lang=jq># Denoting the input by $n, which is assumed to be a positive integer, |
||
# eratosthenes/0 produces an array of primes less than or equal to $n: |
# eratosthenes/0 produces an array of primes less than or equal to $n: |
||
def eratosthenes: |
def eratosthenes: |
||
Line 10,318: | Line 10,318: | ||
| [null, null, range(2; $n)] |
| [null, null, range(2; $n)] |
||
| reduce (2, 1 + (2 * range(1; $s))) as $i (.; erase($i)) |
| reduce (2, 1 + (2 * range(1; $s))) as $i (.; erase($i)) |
||
| map(select(.));</ |
| map(select(.));</syntaxhighlight> |
||
'''Examples''': |
'''Examples''': |
||
<lang |
<syntaxhighlight lang=jq>100 | eratosthenes</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97] |
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97] |
||
<lang |
<syntaxhighlight lang=jq>1e7 | eratosthenes | length</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
664579 |
664579 |
||
Line 10,331: | Line 10,331: | ||
Started with 2 already in the array, and then test only for odd numbers and push the prime ones onto the array. |
Started with 2 already in the array, and then test only for odd numbers and push the prime ones onto the array. |
||
< |
<syntaxhighlight lang=julia># Returns an array of positive prime numbers less than or equal to lim |
||
function sieve(lim :: Int) |
function sieve(lim :: Int) |
||
if lim < 2 return [] end |
if lim < 2 return [] end |
||
Line 10,350: | Line 10,350: | ||
end |
end |
||
return result |
return result |
||
end</ |
end</syntaxhighlight> |
||
Alternate version using <code>findall</code> to get all primes at once in the end |
Alternate version using <code>findall</code> to get all primes at once in the end |
||
< |
<syntaxhighlight lang=julia>function sieve(n :: Int) |
||
isprime = trues(n) |
isprime = trues(n) |
||
isprime[1] = false |
isprime[1] = false |
||
Line 10,369: | Line 10,369: | ||
end |
end |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
At about 35 seconds for a range of a billion on my Intel Atom i5-Z8350 CPU at 1.92 GHz (single threaded) or about 70 CPU clock cycles per culling operation, the above examples are two of the very slowest ways to compute the Sieve of Eratosthenes over any kind of a reasonable range due to a couple of factors: |
At about 35 seconds for a range of a billion on my Intel Atom i5-Z8350 CPU at 1.92 GHz (single threaded) or about 70 CPU clock cycles per culling operation, the above examples are two of the very slowest ways to compute the Sieve of Eratosthenes over any kind of a reasonable range due to a couple of factors: |
||
Line 10,382: | Line 10,382: | ||
If one is going to "crib" the MatLab algorithm as above, one may as well do it using odds-only as per the MatLab built-in. The following alternate code improves on the "Alternate" example above by making it sieve odds-only and adjusting the result array contents after to suit: |
If one is going to "crib" the MatLab algorithm as above, one may as well do it using odds-only as per the MatLab built-in. The following alternate code improves on the "Alternate" example above by making it sieve odds-only and adjusting the result array contents after to suit: |
||
< |
<syntaxhighlight lang=julia>function sieve2(n :: Int) |
||
ni = (n - 1) ÷ 2 |
ni = (n - 1) ÷ 2 |
||
isprime = trues(ni) |
isprime = trues(ni) |
||
Line 10,401: | Line 10,401: | ||
end |
end |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
This takes less about 18.5 seconds or 36 CPU cycles per culling operation to find the primes to a billion, but that is still quite slow compared to what can be done below. Note that the result array needs to be created then copied, created by the <code>findall</code> function, then modified in place by the <code>map!</code> function to transform the indices to primes, and finally copied by the <code>pushfirst!</code> function to add the only even prime of two to the beginning, but these operations are quire fast. However, this still consumes a lot of memory, as in about 64 Megabytes for the sieve buffer and over 400 Megabytes for the result (8-byte Int's for 64 bit execution) to sieve to a billion, and culling the huge culling buffer that doesn't fit the CPU cache sizes is what makes it slow. |
This takes less about 18.5 seconds or 36 CPU cycles per culling operation to find the primes to a billion, but that is still quite slow compared to what can be done below. Note that the result array needs to be created then copied, created by the <code>findall</code> function, then modified in place by the <code>map!</code> function to transform the indices to primes, and finally copied by the <code>pushfirst!</code> function to add the only even prime of two to the beginning, but these operations are quire fast. However, this still consumes a lot of memory, as in about 64 Megabytes for the sieve buffer and over 400 Megabytes for the result (8-byte Int's for 64 bit execution) to sieve to a billion, and culling the huge culling buffer that doesn't fit the CPU cache sizes is what makes it slow. |
||
Line 10,409: | Line 10,409: | ||
The creation of an output results array is not necessary if the purpose is just to scan across the resulting primes once, they can be output using an iterator (from a `BitArray`) as in the following odds-only code: |
The creation of an output results array is not necessary if the purpose is just to scan across the resulting primes once, they can be output using an iterator (from a `BitArray`) as in the following odds-only code: |
||
< |
<syntaxhighlight lang=julia>const Prime = UInt64 |
||
struct Primes |
struct Primes |
||
Line 10,457: | Line 10,457: | ||
return (i + i + 1, i + 1) |
return (i + i + 1, i + 1) |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
for which using the following code: |
for which using the following code: |
||
< |
<syntaxhighlight lang=julia>function bench() |
||
@time length(Primes(100)) # warm up JIT |
@time length(Primes(100)) # warm up JIT |
||
# println(@time count(x->true, Primes(1000000000))) # about 1.5 seconds slower counting over iteration |
# println(@time count(x->true, Primes(1000000000))) # about 1.5 seconds slower counting over iteration |
||
println(@time length(Primes(1000000000))) |
println(@time length(Primes(1000000000))) |
||
end |
end |
||
bench()</ |
bench()</syntaxhighlight> |
||
results in the following output: |
results in the following output: |
||
Line 10,480: | Line 10,480: | ||
For any kind of reasonably large range such as a billion, a page segmented version should be used with the pages sized to the CPU caches for much better memory access times. As well, the following odds-only example uses a custom bit packing algorithm for a further two times speed-up, also reducing the memory allocation delays by reusing the sieve buffers when possible (usually possible): |
For any kind of reasonably large range such as a billion, a page segmented version should be used with the pages sized to the CPU caches for much better memory access times. As well, the following odds-only example uses a custom bit packing algorithm for a further two times speed-up, also reducing the memory allocation delays by reusing the sieve buffers when possible (usually possible): |
||
< |
<syntaxhighlight lang=julia>const Prime = UInt64 |
||
const BasePrime = UInt32 |
const BasePrime = UInt32 |
||
const BasePrimesArray = Array{BasePrime,1} |
const BasePrimesArray = Array{BasePrime,1} |
||
Line 10,677: | Line 10,677: | ||
end |
end |
||
low + state + state, state + 1 |
low + state + state, state + 1 |
||
end</ |
end</syntaxhighlight> |
||
When tested with the following code: |
When tested with the following code: |
||
< |
<syntaxhighlight lang=julia>function bench() |
||
print("( ") |
print("( ") |
||
for p in PrimesPaged() p > 100 && break; print(p, " ") end |
for p in PrimesPaged() p > 100 && break; print(p, " ") end |
||
Line 10,695: | Line 10,695: | ||
println(@time countPrimesTo(Prime(1000000000))) |
println(@time countPrimesTo(Prime(1000000000))) |
||
end |
end |
||
bench()</ |
bench()</syntaxhighlight> |
||
it produces the following: |
it produces the following: |
||
Line 10,715: | Line 10,715: | ||
One of the best simple purely functional Sieve of Eratosthenes algorithms is the infinite tree folding sequence algorithm as implemented in Haskell. As Julia does not have a standard LazyList implementation or library and as a full memoizing lazy list is not required for this algorithm, the following odds-only code implements the rudiments of a Co-Inductive Stream (CIS) in its implementation: |
One of the best simple purely functional Sieve of Eratosthenes algorithms is the infinite tree folding sequence algorithm as implemented in Haskell. As Julia does not have a standard LazyList implementation or library and as a full memoizing lazy list is not required for this algorithm, the following odds-only code implements the rudiments of a Co-Inductive Stream (CIS) in its implementation: |
||
< |
<syntaxhighlight lang=julia>const Thunk = Function # can't define other than as a generalized Function |
||
struct CIS{T} |
struct CIS{T} |
||
Line 10,757: | Line 10,757: | ||
|> allmultiples |> composites)) |
|> allmultiples |> composites)) |
||
CIS{Int}(2, () -> oddprimes()) |
CIS{Int}(2, () -> oddprimes()) |
||
end</ |
end</syntaxhighlight> |
||
when tested with the following: |
when tested with the following: |
||
< |
<syntaxhighlight lang=julia>@time let count = 0; for p in treefoldingprimes() p > 1000000 && break; count += 1 end; count end</syntaxhighlight> |
||
it outputs the following: |
it outputs the following: |
||
Line 10,776: | Line 10,776: | ||
To gain some extra speed above the purely functional algorithm above, the Python'ish version as a mutable iterator embedding a mutable standard base Dictionary can be used. The following version uses a secondary delayed injection stream of "base" primes defined recursively to provide the successions of composite values in the Dictionary to be used for sieving: |
To gain some extra speed above the purely functional algorithm above, the Python'ish version as a mutable iterator embedding a mutable standard base Dictionary can be used. The following version uses a secondary delayed injection stream of "base" primes defined recursively to provide the successions of composite values in the Dictionary to be used for sieving: |
||
< |
<syntaxhighlight lang=Julia>const Prime = UInt64 |
||
abstract type PrimesDictAbstract end # used for forward reference |
abstract type PrimesDictAbstract end # used for forward reference |
||
mutable struct PrimesDict <: PrimesDictAbstract |
mutable struct PrimesDict <: PrimesDictAbstract |
||
Line 10,814: | Line 10,814: | ||
end |
end |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
The above version can be used and tested with similar code as for the functional version, but is about ten times faster at about 400 CPU clock cycles per culling operation, meaning it has a practical range ten times larger although it still has a O(n (log n) (log log n)) asymptotic performance complexity; for larger ranges such as sieving to a billion or more, this is still over a hundred times slower than the page segmented version using a page segmented sieving array. |
The above version can be used and tested with similar code as for the functional version, but is about ten times faster at about 400 CPU clock cycles per culling operation, meaning it has a practical range ten times larger although it still has a O(n (log n) (log log n)) asymptotic performance complexity; for larger ranges such as sieving to a billion or more, this is still over a hundred times slower than the page segmented version using a page segmented sieving array. |
||
=={{header|Klingphix}}== |
=={{header|Klingphix}}== |
||
< |
<syntaxhighlight lang=Klingphix>include ..\Utilitys.tlhy |
||
%limit %i |
%limit %i |
||
Line 10,829: | Line 10,829: | ||
pstack |
pstack |
||
"Press ENTER to end " input</ |
"Press ENTER to end " input</syntaxhighlight> |
||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
< |
<syntaxhighlight lang=kotlin>import kotlin.math.sqrt |
||
fun sieve(max: Int): List<Int> { |
fun sieve(max: Int): List<Int> { |
||
Line 10,843: | Line 10,843: | ||
fun main(args: Array<String>) { |
fun main(args: Array<String>) { |
||
println(sieve(100)) |
println(sieve(100)) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 10,854: | Line 10,854: | ||
The following code overcomes most of those problems: It only culls odd composites; it culls a bit-packed primitive array (also saving memory); It uses tailcall recursive functions for the loops, which are compiled into simple loops. It also outputs the results as an enumeration, which isn't fast but does not consume any more memory than the culling array. In this way, the program is only limited in sieving range by the maximum size limit of the culling array, although as it grows larger than the CPU cache sizes, it loses greatly in speed; however, that doesn't matter so much if just enumerating the results. |
The following code overcomes most of those problems: It only culls odd composites; it culls a bit-packed primitive array (also saving memory); It uses tailcall recursive functions for the loops, which are compiled into simple loops. It also outputs the results as an enumeration, which isn't fast but does not consume any more memory than the culling array. In this way, the program is only limited in sieving range by the maximum size limit of the culling array, although as it grows larger than the CPU cache sizes, it loses greatly in speed; however, that doesn't matter so much if just enumerating the results. |
||
< |
<syntaxhighlight lang=kotlin>fun primesOdds(rng: Int): Iterable<Int> { |
||
val topi = (rng - 3) shr 1 |
val topi = (rng - 3) shr 1 |
||
val lstw = topi shr 5 |
val lstw = topi shr 5 |
||
Line 10,902: | Line 10,902: | ||
println() |
println() |
||
println(primesOdds(1000000).count()) |
println(primesOdds(1000000).count()) |
||
}</ |
}</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
<pre>2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
||
Line 10,911: | Line 10,911: | ||
Ah, one might say, for such a trivial range one writes for conciseness and not for speed. Well, I say, one can still save memory and some time using odds-only and a bit-packed array, but write very clear and concise (but slower) code using nothing but higher order functions and function calling. The following code using such techniques can use the same "main" function for the same output but is about two times slower, mostly due to the extra time spent making (nested) function calls, including the function calls necessary for enumeration. Note that the effect of using the "(l .. h).forEach { .. }" is the same as the "for i in l .. h { .. }" as both use an iteration across the range but the second is just syntax sugar to make it look more imperative: |
Ah, one might say, for such a trivial range one writes for conciseness and not for speed. Well, I say, one can still save memory and some time using odds-only and a bit-packed array, but write very clear and concise (but slower) code using nothing but higher order functions and function calling. The following code using such techniques can use the same "main" function for the same output but is about two times slower, mostly due to the extra time spent making (nested) function calls, including the function calls necessary for enumeration. Note that the effect of using the "(l .. h).forEach { .. }" is the same as the "for i in l .. h { .. }" as both use an iteration across the range but the second is just syntax sugar to make it look more imperative: |
||
< |
<syntaxhighlight lang=kotlin>fun primesOdds(rng: Int): Iterable<Int> { |
||
val topi = (rng - 3) / 2 //convert to nearest index |
val topi = (rng - 3) / 2 //convert to nearest index |
||
val size = topi / 32 + 1 //word size to include index |
val size = topi / 32 + 1 //word size to include index |
||
Line 10,923: | Line 10,923: | ||
val orng = (-1 .. topi).filter { it < 0 || is_p(it) }.map { i2p(it) } |
val orng = (-1 .. topi).filter { it < 0 || is_p(it) }.map { i2p(it) } |
||
return Iterable { -> orng.iterator() } |
return Iterable { -> orng.iterator() } |
||
}</ |
}</syntaxhighlight> |
||
The trouble with the above version is that, at least for Kotlin version 1.0, the ".filter" and ".map" extension functions for Iterable<Int> create Java "ArrayList"'s as their output (which are wrapped to return the Kotlin "List<Int>" interface), thus take a considerable amount of memory worse than the first version (using an ArrayList to store the resulting primes), since as the calculations are chained to ".map", require a second ArrayList of up to the same size while the mapping is being done. The following version uses Sequences , which aren't backed by any permanent structure, but it is another small factor slower due to the nested function calls: |
The trouble with the above version is that, at least for Kotlin version 1.0, the ".filter" and ".map" extension functions for Iterable<Int> create Java "ArrayList"'s as their output (which are wrapped to return the Kotlin "List<Int>" interface), thus take a considerable amount of memory worse than the first version (using an ArrayList to store the resulting primes), since as the calculations are chained to ".map", require a second ArrayList of up to the same size while the mapping is being done. The following version uses Sequences , which aren't backed by any permanent structure, but it is another small factor slower due to the nested function calls: |
||
< |
<syntaxhighlight lang=kotlin>fun primesOdds(rng: Int): Iterable<Int> { |
||
val topi = (rng - 3) / 2 //convert to nearest index |
val topi = (rng - 3) / 2 //convert to nearest index |
||
val size = topi / 32 + 1 //word size to include index |
val size = topi / 32 + 1 //word size to include index |
||
Line 10,941: | Line 10,941: | ||
val oseq = iseq(topi, -1).filter { it < 0 || is_p(it) }.map { i2p(it) } |
val oseq = iseq(topi, -1).filter { it < 0 || is_p(it) }.map { i2p(it) } |
||
return Iterable { -> oseq.iterator() } |
return Iterable { -> oseq.iterator() } |
||
}</ |
}</syntaxhighlight> |
||
===Unbounded Versions=== |
===Unbounded Versions=== |
||
Line 10,948: | Line 10,948: | ||
The following Sieve of Eratosthenes is not purely functional in that it uses a Mutable HashMap to store the state of succeeding composite numbers to be skipped over, but embodies the principles of an incremental implementation of the Sieve of Eratosthenes sieving odds-only and is faster than most incremental sieves due to using mutability. As with the fastest of this kind of sieve, it uses a delayed secondary primes feed as a source of base primes to generate the composite number progressions. The code as follows: |
The following Sieve of Eratosthenes is not purely functional in that it uses a Mutable HashMap to store the state of succeeding composite numbers to be skipped over, but embodies the principles of an incremental implementation of the Sieve of Eratosthenes sieving odds-only and is faster than most incremental sieves due to using mutability. As with the fastest of this kind of sieve, it uses a delayed secondary primes feed as a source of base primes to generate the composite number progressions. The code as follows: |
||
< |
<syntaxhighlight lang=kotlin>fun primesHM(): Sequence<Int> = sequence { |
||
yield(2) |
yield(2) |
||
fun oddprms(): Sequence<Int> = sequence { |
fun oddprms(): Sequence<Int> = sequence { |
||
Line 10,980: | Line 10,980: | ||
} |
} |
||
yieldAll(oddprms()) |
yieldAll(oddprms()) |
||
}</ |
}</syntaxhighlight> |
||
At about 370 clock cycles per culling operation (about 3,800 cycles per prime) on my tablet class Intel CPU, this is not blazing fast but adequate for ranges of a few millions to a hundred million and thus fine for doing things like solving Euler problems. For instance, Euler Problem 10 of summing the primes to two million can be done with the following "one-liner": |
At about 370 clock cycles per culling operation (about 3,800 cycles per prime) on my tablet class Intel CPU, this is not blazing fast but adequate for ranges of a few millions to a hundred million and thus fine for doing things like solving Euler problems. For instance, Euler Problem 10 of summing the primes to two million can be done with the following "one-liner": |
||
< |
<syntaxhighlight lang=kotlin>primesHM().takeWhile { it <= 2_000_000 }.map { it.toLong() }.sum()</syntaxhighlight> |
||
to output the correct answer of the following in about 270 milliseconds for my Intel x5-Z8350 at 1.92 Gigahertz: |
to output the correct answer of the following in about 270 milliseconds for my Intel x5-Z8350 at 1.92 Gigahertz: |
||
Line 10,995: | Line 10,995: | ||
{{trans|Haskell}} |
{{trans|Haskell}} |
||
< |
<syntaxhighlight lang=kotlin>data class CIS<T>(val head: T, val tailf: () -> CIS<T>) { |
||
fun toSequence() = generateSequence(this) { it.tailf() } .map { it.head } |
fun toSequence() = generateSequence(this) { it.tailf() } .map { it.head } |
||
} |
} |
||
Line 11,032: | Line 11,032: | ||
val stop = System.currentTimeMillis() |
val stop = System.currentTimeMillis() |
||
println("Took ${stop - strt} milliseconds.") |
println("Took ${stop - strt} milliseconds.") |
||
}</ |
}</syntaxhighlight> |
||
The code is about five times slower than the more imperative hash table based version immediately above due to the costs of the extra levels of function calls in the functional style. The Haskell version from which this is derived is much faster due to the extensive optimizations it does to do with function/closure "lifting" as well as a Garbage Collector specifically tuned for functional code. |
The code is about five times slower than the more imperative hash table based version immediately above due to the costs of the extra levels of function calls in the functional style. The Haskell version from which this is derived is much faster due to the extensive optimizations it does to do with function/closure "lifting" as well as a Garbage Collector specifically tuned for functional code. |
||
Line 11,039: | Line 11,039: | ||
The very fastest implementations of a primes sieve are all based on bit-packed mutable arrays which can be made unbounded by setting them up so that they are a succession of sieved bit-packed arrays that have been culled of composites. The following code is an odds=only implementation that, again, uses a secondary feed of base primes that is only expanded as necessary (in this case memoized by a rudimentary lazy list structure to avoid recalculation for every base primes sweep per page segment): |
The very fastest implementations of a primes sieve are all based on bit-packed mutable arrays which can be made unbounded by setting them up so that they are a succession of sieved bit-packed arrays that have been culled of composites. The following code is an odds=only implementation that, again, uses a secondary feed of base primes that is only expanded as necessary (in this case memoized by a rudimentary lazy list structure to avoid recalculation for every base primes sweep per page segment): |
||
< |
<syntaxhighlight lang=kotlin>internal typealias Prime = Long |
||
internal typealias BasePrime = Int |
internal typealias BasePrime = Int |
||
internal typealias BasePrimeArray = IntArray |
internal typealias BasePrimeArray = IntArray |
||
Line 11,212: | Line 11,212: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
For this implementation, counting the primes to a million is trivial at about 15 milliseconds on the same CPU as above, or almost too short to count. |
For this implementation, counting the primes to a million is trivial at about 15 milliseconds on the same CPU as above, or almost too short to count. |
||
Line 11,227: | Line 11,227: | ||
=={{header|Lambdatalk}}== |
=={{header|Lambdatalk}}== |
||
< |
<syntaxhighlight lang=Scheme> |
||
{def sieve |
{def sieve |
||
Line 11,259: | Line 11,259: | ||
{sieve 100} |
{sieve 100} |
||
-> 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
-> 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|langur}}== |
=={{header|langur}}== |
||
{{trans|D}} |
{{trans|D}} |
||
< |
<syntaxhighlight lang=langur>val .sieve = f(.limit) { |
||
if .limit < 2 { |
if .limit < 2 { |
||
return [] |
return [] |
||
Line 11,282: | Line 11,282: | ||
} |
} |
||
writeln .sieve(100)</ |
writeln .sieve(100)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 11,288: | Line 11,288: | ||
=={{header|Liberty BASIC}}== |
=={{header|Liberty BASIC}}== |
||
< |
<syntaxhighlight lang=lb> 'Notice that arrays are globally visible to functions. |
||
'The sieve() function uses the flags() array. |
'The sieve() function uses the flags() array. |
||
'This is a Sieve benchmark adapted from BYTE 1985 |
'This is a Sieve benchmark adapted from BYTE 1985 |
||
Line 11,312: | Line 11,312: | ||
end if |
end if |
||
next i |
next i |
||
end function</ |
end function</syntaxhighlight> |
||
=={{header|Limbo}}== |
=={{header|Limbo}}== |
||
< |
<syntaxhighlight lang=Go>implement Sieve; |
||
include "sys.m"; |
include "sys.m"; |
||
Line 11,355: | Line 11,355: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Lingo}}== |
=={{header|Lingo}}== |
||
< |
<syntaxhighlight lang=Lingo>-- parent script "sieve" |
||
property _sieve |
property _sieve |
||
Line 11,398: | Line 11,398: | ||
end repeat |
end repeat |
||
end repeat |
end repeat |
||
end</ |
end</syntaxhighlight> |
||
< |
<syntaxhighlight lang=Lingo>sieve = script("sieve").new() |
||
put sieve.getPrimes(100)</ |
put sieve.getPrimes(100)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 11,409: | Line 11,409: | ||
=={{header|LiveCode}}== |
=={{header|LiveCode}}== |
||
< |
<syntaxhighlight lang=LiveCode>function sieveE int |
||
set itemdel to comma |
set itemdel to comma |
||
local sieve |
local sieve |
||
Line 11,430: | Line 11,430: | ||
sort items of sieve ascending numeric |
sort items of sieve ascending numeric |
||
return sieve |
return sieve |
||
end sieveE</ |
end sieveE</syntaxhighlight> |
||
Example< |
Example<syntaxhighlight lang=LiveCode>put sieveE(121) |
||
-- 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113</ |
-- 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113</syntaxhighlight> |
||
< |
<syntaxhighlight lang=LiveCode># Sieve of Eratosthenes |
||
# calculates prime numbers up to a given number |
# calculates prime numbers up to a given number |
||
Line 11,462: | Line 11,462: | ||
end mouseUp |
end mouseUp |
||
</syntaxhighlight> |
|||
</lang> |
|||
[http://www.melellington.com/sieve/livecode-sieve-output.png LiveCode output example] |
[http://www.melellington.com/sieve/livecode-sieve-output.png LiveCode output example] |
||
Line 11,495: | Line 11,495: | ||
due to the use of mod (modulo = division) in the filter function. |
due to the use of mod (modulo = division) in the filter function. |
||
A coinduction based solution just for fun: |
A coinduction based solution just for fun: |
||
< |
<syntaxhighlight lang=logtalk> |
||
:- object(sieve). |
:- object(sieve). |
||
Line 11,534: | Line 11,534: | ||
:- end_object. |
:- end_object. |
||
</syntaxhighlight> |
|||
</lang> |
|||
Example query: |
Example query: |
||
< |
<syntaxhighlight lang=logtalk> |
||
?- sieve::primes(20, P). |
?- sieve::primes(20, P). |
||
P = [2, 3|_S1], % where |
P = [2, 3|_S1], % where |
||
_S1 = [5, 7, 11, 13, 17, 19, 2, 3|_S1] . |
_S1 = [5, 7, 11, 13, 17, 19, 2, 3|_S1] . |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|LOLCODE}}== |
=={{header|LOLCODE}}== |
||
< |
<syntaxhighlight lang=lolcode>HAI 1.2 |
||
CAN HAS STDIO? |
CAN HAS STDIO? |
||
Line 11,591: | Line 11,591: | ||
I IZ Eratosumthin YR 100 MKAY |
I IZ Eratosumthin YR 100 MKAY |
||
KTHXBYE</ |
KTHXBYE</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
Line 11,597: | Line 11,597: | ||
=={{header|Lua}}== |
=={{header|Lua}}== |
||
< |
<syntaxhighlight lang=lua>function erato(n) |
||
if n < 2 then return {} end |
if n < 2 then return {} end |
||
local t = {0} -- clears '1' |
local t = {0} -- clears '1' |
||
Line 11,606: | Line 11,606: | ||
for i = 2, n do if t[i] ~= 0 then table.insert(primes, i) end end |
for i = 2, n do if t[i] ~= 0 then table.insert(primes, i) end end |
||
return primes |
return primes |
||
end</ |
end</syntaxhighlight> |
||
The following changes the code to '''odds-only''' using the same large array-based algorithm: |
The following changes the code to '''odds-only''' using the same large array-based algorithm: |
||
< |
<syntaxhighlight lang=lua>function erato2(n) |
||
if n < 2 then return {} end |
if n < 2 then return {} end |
||
if n < 3 then return {2} end |
if n < 3 then return {2} end |
||
Line 11,622: | Line 11,622: | ||
for i = 0, lmt do if t[i] ~= 0 then table.insert(primes, i + i + 3) end end |
for i = 0, lmt do if t[i] ~= 0 then table.insert(primes, i + i + 3) end end |
||
return primes |
return primes |
||
end</ |
end</syntaxhighlight> |
||
The following code implements '''an odds-only "infinite" generator style using a table as a hash table''', including postponing adding base primes to the table: |
The following code implements '''an odds-only "infinite" generator style using a table as a hash table''', including postponing adding base primes to the table: |
||
< |
<syntaxhighlight lang=lua>function newEratoInf() |
||
local _cand = 0; local _lstbp = 3; local _lstsqr = 9 |
local _cand = 0; local _lstbp = 3; local _lstsqr = 9 |
||
local _composites = {}; local _bps = nil |
local _composites = {}; local _bps = nil |
||
Line 11,659: | Line 11,659: | ||
while gen.next() <= 10000000 do count = count + 1 end -- sieves to 10 million |
while gen.next() <= 10000000 do count = count + 1 end -- sieves to 10 million |
||
print(count) |
print(count) |
||
</syntaxhighlight> |
|||
</lang> |
|||
which outputs "664579" in about three seconds. As this code uses much less memory for a given range than the previous ones and retains efficiency better with range, it is likely more appropriate for larger sieve ranges. |
which outputs "664579" in about three seconds. As this code uses much less memory for a given range than the previous ones and retains efficiency better with range, it is likely more appropriate for larger sieve ranges. |
||
Line 11,685: | Line 11,685: | ||
=={{header|M2000 Interpreter}}== |
=={{header|M2000 Interpreter}}== |
||
< |
<syntaxhighlight lang=M2000 Interpreter> |
||
Module EratosthenesSieve (x) { |
Module EratosthenesSieve (x) { |
||
\\ Κόσκινο του Ερατοσθένη |
\\ Κόσκινο του Ερατοσθένη |
||
Line 11,706: | Line 11,706: | ||
} |
} |
||
EratosthenesSieve 1000 |
EratosthenesSieve 1000 |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|M4}}== |
=={{header|M4}}== |
||
< |
<syntaxhighlight lang=M4>define(`lim',100)dnl |
||
define(`for', |
define(`for', |
||
`ifelse($#,0, |
`ifelse($#,0, |
||
Line 11,720: | Line 11,720: | ||
`j for(`k',eval(j*j),lim,j, |
`j for(`k',eval(j*j),lim,j, |
||
`define(a[k],1)')')') |
`define(a[k],1)')')') |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
Line 11,729: | Line 11,729: | ||
=={{header|MAD}}== |
=={{header|MAD}}== |
||
< |
<syntaxhighlight lang=MAD> NORMAL MODE IS INTEGER |
||
R TO GENERATE MORE PRIMES, CHANGE BOTH THESE NUMBERS |
R TO GENERATE MORE PRIMES, CHANGE BOTH THESE NUMBERS |
||
Line 11,755: | Line 11,755: | ||
VECTOR VALUES BEGIN = $13HPRIMES UP TO ,I9*$ |
VECTOR VALUES BEGIN = $13HPRIMES UP TO ,I9*$ |
||
VECTOR VALUES NUMFMT = $I9*$ |
VECTOR VALUES NUMFMT = $I9*$ |
||
END OF PROGRAM</ |
END OF PROGRAM</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 11,777: | Line 11,777: | ||
=={{header|Maple}}== |
=={{header|Maple}}== |
||
< |
<syntaxhighlight lang=Maple>Eratosthenes := proc(n::posint) |
||
local numbers_to_check, i, k; |
local numbers_to_check, i, k; |
||
numbers_to_check := [seq(2 .. n)]; |
numbers_to_check := [seq(2 .. n)]; |
||
Line 11,790: | Line 11,790: | ||
return numbers_to_check; |
return numbers_to_check; |
||
end proc: |
end proc: |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 11,798: | Line 11,798: | ||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
||
< |
<syntaxhighlight lang=Mathematica>Eratosthenes[n_] := Module[{numbers = Range[n]}, |
||
Do[If[numbers[[i]] != 0, Do[numbers[[i j]] = 0, {j, 2, n/i}]], {i, |
Do[If[numbers[[i]] != 0, Do[numbers[[i j]] = 0, {j, 2, n/i}]], {i, |
||
2, Sqrt[n]}]; |
2, Sqrt[n]}]; |
||
Select[numbers, # > 1 &]] |
Select[numbers, # > 1 &]] |
||
Eratosthenes[100]</ |
Eratosthenes[100]</syntaxhighlight> |
||
===Slightly Optimized Version=== |
===Slightly Optimized Version=== |
||
The below has been improved to not require so many operations per composite number cull for about two thirds the execution time: |
The below has been improved to not require so many operations per composite number cull for about two thirds the execution time: |
||
< |
<syntaxhighlight lang=Mathematica>Eratosthenes[n_] := Module[{numbers = Range[n]}, |
||
Do[If[numbers[[i]] != 0, Do[numbers[[j]] = 0, {j,i i,n,i}]],{i,2,Sqrt[n]}]; |
Do[If[numbers[[i]] != 0, Do[numbers[[j]] = 0, {j,i i,n,i}]],{i,2,Sqrt[n]}]; |
||
Select[numbers, # > 1 &]] |
Select[numbers, # > 1 &]] |
||
Eratosthenes[100]</ |
Eratosthenes[100]</syntaxhighlight> |
||
===Sieving Odds-Only Version=== |
===Sieving Odds-Only Version=== |
||
The below has been further improved to only sieve odd numbers for a further reduction in execution time by a factor of over two: |
The below has been further improved to only sieve odd numbers for a further reduction in execution time by a factor of over two: |
||
< |
<syntaxhighlight lang=Mathematica>Eratosthenes2[n_] := Module[{numbers = Range[3, n, 2], limit = (n - 1)/2}, |
||
Do[c = numbers[[i]]; If[c != 0, |
Do[c = numbers[[i]]; If[c != 0, |
||
Do[numbers[[j]] = 0, {j,(c c - 1)/2,limit,c}]], {i,1,(Sqrt[n] - 1)/2}]; |
Do[numbers[[j]] = 0, {j,(c c - 1)/2,limit,c}]], {i,1,(Sqrt[n] - 1)/2}]; |
||
Prepend[Select[numbers, # > 1 &], 2]] |
Prepend[Select[numbers, # > 1 &], 2]] |
||
Eratosthenes2[100]</ |
Eratosthenes2[100]</syntaxhighlight> |
||
=={{header|MATLAB}} / {{header|Octave}}== |
=={{header|MATLAB}} / {{header|Octave}}== |
||
===Somewhat optimized true Sieve of Eratosthenes=== |
===Somewhat optimized true Sieve of Eratosthenes=== |
||
< |
<syntaxhighlight lang=MATLAB>function P = erato(x) % Sieve of Eratosthenes: returns all primes between 2 and x |
||
P = [0 2:x]; % Create vector with all ints between 2 and x where |
P = [0 2:x]; % Create vector with all ints between 2 and x where |
||
Line 11,834: | Line 11,834: | ||
P = P(P ~= 0); % Remove all zeroes from P, leaving only the primes. |
P = P(P ~= 0); % Remove all zeroes from P, leaving only the primes. |
||
end</ |
end</syntaxhighlight>The optimization lies in fewer steps in the for loop, use of MATLAB's built-in array operations and no modulo calculation. |
||
'''Limitation:''' your machine has to be able to allocate enough memory for an array of length x. |
'''Limitation:''' your machine has to be able to allocate enough memory for an array of length x. |
||
Line 11,841: | Line 11,841: | ||
A more efficient Sieve avoids creating a large double precision vector P, instead using a logical array (which consumes 1/8 the memory of a double array of the same size) and only converting to double those values corresponding to primes. |
A more efficient Sieve avoids creating a large double precision vector P, instead using a logical array (which consumes 1/8 the memory of a double array of the same size) and only converting to double those values corresponding to primes. |
||
< |
<syntaxhighlight lang=MATLAB>function P = sieveOfEratosthenes(x) |
||
ISP = [false true(1, x-1)]; % 1 is not prime, but we start off assuming all numbers between 2 and x are |
ISP = [false true(1, x-1)]; % 1 is not prime, but we start off assuming all numbers between 2 and x are |
||
for n = 2:sqrt(x) |
for n = 2:sqrt(x) |
||
Line 11,851: | Line 11,851: | ||
P = find(ISP); % Convert the ISPRIME output to the values of the primes by finding the locations |
P = find(ISP); % Convert the ISPRIME output to the values of the primes by finding the locations |
||
% of the TRUE values in S. |
% of the TRUE values in S. |
||
end</ |
end</syntaxhighlight> |
||
You can compare the output of this function against the PRIMES function included in MATLAB, which performs a somewhat more memory-efficient Sieve (by not storing even numbers, at the expense of a more complicated indexing expression inside the IF statement.) |
You can compare the output of this function against the PRIMES function included in MATLAB, which performs a somewhat more memory-efficient Sieve (by not storing even numbers, at the expense of a more complicated indexing expression inside the IF statement.) |
||
=={{header|Maxima}}== |
=={{header|Maxima}}== |
||
< |
<syntaxhighlight lang=maxima>sieve(n):=block( |
||
[a:makelist(true,n),i:1,j], |
[a:makelist(true,n),i:1,j], |
||
a[1]:false, |
a[1]:false, |
||
Line 11,865: | Line 11,865: | ||
for j from i*i step i while j<=n do a[j]:false |
for j from i*i step i while j<=n do a[j]:false |
||
) |
) |
||
)$</ |
)$</syntaxhighlight> |
||
=={{header|MAXScript}}== |
=={{header|MAXScript}}== |
||
Line 11,888: | Line 11,888: | ||
=={{header|Mercury}}== |
=={{header|Mercury}}== |
||
< |
<syntaxhighlight lang=Mercury>:- module sieve. |
||
:- interface. |
:- interface. |
||
:- import_module io. |
:- import_module io. |
||
Line 11,946: | Line 11,946: | ||
else |
else |
||
true |
true |
||
).</ |
).</syntaxhighlight> |
||
=={{header|Microsoft Small Basic}}== |
=={{header|Microsoft Small Basic}}== |
||
{{trans|GW-BASIC}} |
{{trans|GW-BASIC}} |
||
< |
<syntaxhighlight lang=microsoftsmallbasic> |
||
TextWindow.Write("Enter number to search to: ") |
TextWindow.Write("Enter number to search to: ") |
||
limit = TextWindow.ReadNumber() |
limit = TextWindow.ReadNumber() |
||
Line 11,973: | Line 11,973: | ||
TextWindow.WriteLine("") |
TextWindow.WriteLine("") |
||
EndIf |
EndIf |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Modula-2}}== |
=={{header|Modula-2}}== |
||
< |
<syntaxhighlight lang=modula2>MODULE Erato; |
||
FROM InOut IMPORT WriteCard, WriteLn; |
FROM InOut IMPORT WriteCard, WriteLn; |
||
FROM MathLib IMPORT sqrt; |
FROM MathLib IMPORT sqrt; |
||
Line 12,011: | Line 12,011: | ||
END; |
END; |
||
END; |
END; |
||
END Erato.</ |
END Erato.</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre style='height:50ex;'> 2 |
<pre style='height:50ex;'> 2 |
||
Line 12,042: | Line 12,042: | ||
===Regular version=== |
===Regular version=== |
||
This version runs slow because of the way I/O is implemented in the CM3 compiler. Setting <code>ListPrimes = FALSE</code> achieves speed comparable to C on sufficiently high values of <code>LastNum</code> (e.g., 10^6). |
This version runs slow because of the way I/O is implemented in the CM3 compiler. Setting <code>ListPrimes = FALSE</code> achieves speed comparable to C on sufficiently high values of <code>LastNum</code> (e.g., 10^6). |
||
< |
<syntaxhighlight lang=modula3>MODULE Eratosthenes EXPORTS Main; |
||
IMPORT IO; |
IMPORT IO; |
||
Line 12,100: | Line 12,100: | ||
IO.PutChar('\n'); |
IO.PutChar('\n'); |
||
END Eratosthenes.</ |
END Eratosthenes.</syntaxhighlight> |
||
===Advanced version=== |
===Advanced version=== |
||
This version uses more "advanced" types. |
This version uses more "advanced" types. |
||
< |
<syntaxhighlight lang=modula3>(* From the CM3 examples folder (comments removed). *) |
||
MODULE Sieve EXPORTS Main; |
MODULE Sieve EXPORTS Main; |
||
Line 12,129: | Line 12,129: | ||
END; |
END; |
||
IO.Put("\n"); |
IO.Put("\n"); |
||
END Sieve.</ |
END Sieve.</syntaxhighlight> |
||
=={{header|MUMPS}}== |
=={{header|MUMPS}}== |
||
< |
<syntaxhighlight lang=MUMPS>ERATO1(HI) |
||
;performs the Sieve of Erotosethenes up to the number passed in. |
;performs the Sieve of Erotosethenes up to the number passed in. |
||
;This version sets an array containing the primes |
;This version sets an array containing the primes |
||
Line 12,141: | Line 12,141: | ||
FOR I=2:1:HI S:'$DATA(P(I)) ERATO1(I)=I |
FOR I=2:1:HI S:'$DATA(P(I)) ERATO1(I)=I |
||
KILL I,J,P |
KILL I,J,P |
||
QUIT</ |
QUIT</syntaxhighlight> |
||
Example: |
Example: |
||
<pre>USER>SET MAX=100,C=0 DO ERATO1^ROSETTA(MAX) |
<pre>USER>SET MAX=100,C=0 DO ERATO1^ROSETTA(MAX) |
||
Line 12,150: | Line 12,150: | ||
=={{header|Neko}}== |
=={{header|Neko}}== |
||
< |
<syntaxhighlight lang=ActionScript>/* The Computer Language Shootout |
||
http://shootout.alioth.debian.org/ |
http://shootout.alioth.debian.org/ |
||
Line 12,185: | Line 12,185: | ||
nsieve(10000 << (n - i)); |
nsieve(10000 << (n - i)); |
||
i += 1; |
i += 1; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 12,200: | Line 12,200: | ||
=={{header|NetRexx}}== |
=={{header|NetRexx}}== |
||
===Version 1 (slow)=== |
===Version 1 (slow)=== |
||
< |
<syntaxhighlight lang=Rexx>/* NetRexx */ |
||
options replace format comments java crossref savelog symbols binary |
options replace format comments java crossref savelog symbols binary |
||
Line 12,256: | Line 12,256: | ||
method isFalse public constant binary returns boolean |
method isFalse public constant binary returns boolean |
||
return \isTrue |
return \isTrue |
||
</syntaxhighlight> |
|||
</lang> |
|||
;Output |
;Output |
||
<pre style="overflow:scroll"> |
<pre style="overflow:scroll"> |
||
Line 12,264: | Line 12,264: | ||
</pre> |
</pre> |
||
===Version 2 (significantly, i.e. 10 times faster)=== |
===Version 2 (significantly, i.e. 10 times faster)=== |
||
< |
<syntaxhighlight lang=NetRexx>/* NetRexx ************************************************************ |
||
* Essential improvements:Use boolean instead of Rexx for sv |
* Essential improvements:Use boolean instead of Rexx for sv |
||
* and remove methods isTrue and isFalse |
* and remove methods isTrue and isFalse |
||
Line 12,330: | Line 12,330: | ||
end p_ |
end p_ |
||
return primes</ |
return primes</syntaxhighlight> |
||
=={{header|newLISP}}== |
=={{header|newLISP}}== |
||
Line 12,338: | Line 12,338: | ||
Note that the lambda expression in the following script does not involve a closure; newLISP has dynamic scope, so it matters that the same variable names will not be reused for some other purpose (at runtime) before the anonymous function is called. |
Note that the lambda expression in the following script does not involve a closure; newLISP has dynamic scope, so it matters that the same variable names will not be reused for some other purpose (at runtime) before the anonymous function is called. |
||
< |
<syntaxhighlight lang=newlisp>(set 'upper-bound 1000) |
||
; The initial sieve is a list of all the numbers starting at 2. |
; The initial sieve is a list of all the numbers starting at 2. |
||
Line 12,357: | Line 12,357: | ||
sieve))) |
sieve))) |
||
(exit)</ |
(exit)</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
Line 12,538: | Line 12,538: | ||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
< |
<syntaxhighlight lang=nim>from math import sqrt |
||
iterator primesUpto(limit: int): int = |
iterator primesUpto(limit: int): int = |
||
Line 12,559: | Line 12,559: | ||
for p in primesUpto(1000000): |
for p in primesUpto(1000000): |
||
count += 1 |
count += 1 |
||
echo "There are ", count, " primes up to 1000000."</ |
echo "There are ", count, " primes up to 1000000."</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Primes are: |
<pre>Primes are: |
||
Line 12,569: | Line 12,569: | ||
The above version wastes quite a lot of memory by using a sequence of boolean values to sieve the composite numbers and sieving all numbers when two is the only even prime. The below code uses a bit-packed sequence to save a factor of eight in memory and also sieves only odd primes for another memory saving by a factor of two; it is also over two and a half times faster due to reduced number of culling operations and better use of the CPU cache as a little cache goes a lot further - this better use of cache is more than enough to make up for the extra bit-packing shifting operations: |
The above version wastes quite a lot of memory by using a sequence of boolean values to sieve the composite numbers and sieving all numbers when two is the only even prime. The below code uses a bit-packed sequence to save a factor of eight in memory and also sieves only odd primes for another memory saving by a factor of two; it is also over two and a half times faster due to reduced number of culling operations and better use of the CPU cache as a little cache goes a lot further - this better use of cache is more than enough to make up for the extra bit-packing shifting operations: |
||
< |
<syntaxhighlight lang=nim>iterator isoe_upto(top: uint): uint = |
||
let topndx = int((top - 3) div 2) |
let topndx = int((top - 3) div 2) |
||
let sqrtndx = (int(sqrt float64(top)) - 3) div 2 |
let sqrtndx = (int(sqrt float64(top)) - 3) div 2 |
||
Line 12,581: | Line 12,581: | ||
for i in 0 .. topndx: |
for i in 0 .. topndx: |
||
if (cmpsts[i shr 5] and (1u32 shl (i and 31))) == 0: |
if (cmpsts[i shr 5] and (1u32 shl (i and 31))) == 0: |
||
yield uint(i + i + 3)</ |
yield uint(i + i + 3)</syntaxhighlight> |
||
The above code can be used with the same output functions as in the first code, just replacing the name of the iterator "iprimes_upto" with this iterator's name "isoe_upto" in two places. The output will be identical. |
The above code can be used with the same output functions as in the first code, just replacing the name of the iterator "iprimes_upto" with this iterator's name "isoe_upto" in two places. The output will be identical. |
||
Line 12,588: | Line 12,588: | ||
For many purposes, one doesn't know the exact upper limit desired to easily use the above versions; in addition, those versions use an amount of memory proportional to the range sieved. In contrast, unbounded versions continuously update their range as they progress and only use memory proportional to the secondary base primes stream, which is only proportional to the square root of the range. One of the most basic functional versions is the TreeFolding sieve which is based on merging lazy streams as per Richard Bird's contribution to incremental sieves in Haskell, but which has a much better asymptotic execution complexity due to the added tree folding. The following code is a version of that in Nim (odds-only): |
For many purposes, one doesn't know the exact upper limit desired to easily use the above versions; in addition, those versions use an amount of memory proportional to the range sieved. In contrast, unbounded versions continuously update their range as they progress and only use memory proportional to the secondary base primes stream, which is only proportional to the square root of the range. One of the most basic functional versions is the TreeFolding sieve which is based on merging lazy streams as per Richard Bird's contribution to incremental sieves in Haskell, but which has a much better asymptotic execution complexity due to the added tree folding. The following code is a version of that in Nim (odds-only): |
||
< |
<syntaxhighlight lang=nim>import sugar |
||
from times import epochTime |
from times import epochTime |
||
Line 12,669: | Line 12,669: | ||
let elapsed = epochTime() - start |
let elapsed = epochTime() - start |
||
echo "There are ", counter, " primes up to 1000000." |
echo "There are ", counter, " primes up to 1000000." |
||
echo "This test took ", elapsed, " seconds."</ |
echo "This test took ", elapsed, " seconds."</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>The first 25 primes are: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
<pre>The first 25 primes are: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
||
Line 12,682: | Line 12,682: | ||
To show the cost of functional forms of code, the following code is written embracing mutability, both by using a mutable hash table to store the state of incremental culling by the secondary stream of base primes and by using mutable values to store the state wherever possible, as per the following code: |
To show the cost of functional forms of code, the following code is written embracing mutability, both by using a mutable hash table to store the state of incremental culling by the secondary stream of base primes and by using mutable values to store the state wherever possible, as per the following code: |
||
< |
<syntaxhighlight lang=nim>import tables, times |
||
type PrimeType = int |
type PrimeType = int |
||
Line 12,731: | Line 12,731: | ||
let elapsed = epochTime() - start |
let elapsed = epochTime() - start |
||
echo "The number of primes up to a million is: ", counter |
echo "The number of primes up to a million is: ", counter |
||
stdout.write("This test took ", elapsed, " seconds.\n")</ |
stdout.write("This test took ", elapsed, " seconds.\n")</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 12,746: | Line 12,746: | ||
For the highest speeds, one needs to use page segmented mutable arrays as in the bit-packed version here: |
For the highest speeds, one needs to use page segmented mutable arrays as in the bit-packed version here: |
||
< |
<syntaxhighlight lang=nim># a Page Segmented Odd-Only Bit-Packed Sieve of Eratosthenes... |
||
from times import epochTime # for testing |
from times import epochTime # for testing |
||
Line 12,916: | Line 12,916: | ||
let elpsd = epochTime() - start |
let elpsd = epochTime() - start |
||
echo "Found ", counter, " primes up to ", LIMIT, " in ", elpsd, " seconds."</ |
echo "Found ", counter, " primes up to ", LIMIT, " in ", elpsd, " seconds."</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
Time is obtained with Nim 1.4 with options <code>-d:danger --gc:arc</code>. |
Time is obtained with Nim 1.4 with options <code>-d:danger --gc:arc</code>. |
||
Line 12,934: | Line 12,934: | ||
=={{header|Niue}}== |
=={{header|Niue}}== |
||
{{incorrect|Niue|It uses rem testing and so is a trial division algorithm, not a sieve of Eratosthenes.}} |
{{incorrect|Niue|It uses rem testing and so is a trial division algorithm, not a sieve of Eratosthenes.}} |
||
< |
<syntaxhighlight lang=Niue>[ dup 2 < ] '<2 ; |
||
[ 1 + 'count ; [ <2 [ , ] when ] count times ] 'fill-stack ; |
[ 1 + 'count ; [ <2 [ , ] when ] count times ] 'fill-stack ; |
||
Line 12,954: | Line 12,954: | ||
10 sieve .s ( => 2 3 5 7 9 ) reset newline |
10 sieve .s ( => 2 3 5 7 9 ) reset newline |
||
30 sieve .s ( => 2 3 5 7 11 13 17 19 23 29 ) </ |
30 sieve .s ( => 2 3 5 7 11 13 17 19 23 29 ) </syntaxhighlight> |
||
=={{header|Oberon-2}}== |
=={{header|Oberon-2}}== |
||
< |
<syntaxhighlight lang=oberon2>MODULE Primes; |
||
IMPORT Out, Math; |
IMPORT Out, Math; |
||
Line 12,990: | Line 12,990: | ||
END; |
END; |
||
Out.Ln; |
Out.Ln; |
||
END Primes.</ |
END Primes.</syntaxhighlight> |
||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
===Imperative=== |
===Imperative=== |
||
< |
<syntaxhighlight lang=ocaml>let sieve n = |
||
let is_prime = Array.create n true in |
let is_prime = Array.create n true in |
||
let limit = truncate(sqrt (float (n - 1))) in |
let limit = truncate(sqrt (float (n - 1))) in |
||
Line 13,007: | Line 13,007: | ||
is_prime.(0) <- false; |
is_prime.(0) <- false; |
||
is_prime.(1) <- false; |
is_prime.(1) <- false; |
||
is_prime</ |
is_prime</syntaxhighlight> |
||
< |
<syntaxhighlight lang=ocaml>let primes n = |
||
let primes, _ = |
let primes, _ = |
||
let sieve = sieve n in |
let sieve = sieve n in |
||
Line 13,017: | Line 13,017: | ||
([], Array.length sieve - 1) |
([], Array.length sieve - 1) |
||
in |
in |
||
primes</ |
primes</syntaxhighlight> |
||
in the top-level: |
in the top-level: |
||
Line 13,026: | Line 13,026: | ||
===Functional=== |
===Functional=== |
||
< |
<syntaxhighlight lang=ocaml>(* first define some iterators *) |
||
let fold_iter f init a b = |
let fold_iter f init a b = |
||
let rec aux acc i = |
let rec aux acc i = |
||
Line 13,068: | Line 13,068: | ||
li 2 (pred limit) |
li 2 (pred limit) |
||
(* val primes : int -> int list *) |
(* val primes : int -> int list *) |
||
</syntaxhighlight> |
|||
</lang> |
|||
in the top-level: |
in the top-level: |
||
< |
<syntaxhighlight lang=ocaml># primes 200 ;; |
||
- : int list = |
- : int list = |
||
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71; |
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71; |
||
73; 79; 83; 89; 97; 101; 103; 107; 109; 113; 127; 131; 137; 139; 149; 151; |
73; 79; 83; 89; 97; 101; 103; 107; 109; 113; 127; 131; 137; 139; 149; 151; |
||
157; 163; 167; 173; 179; 181; 191; 193; 197; 199]</ |
157; 163; 167; 173; 179; 181; 191; 193; 197; 199]</syntaxhighlight> |
||
=== Another functional version === |
=== Another functional version === |
||
Line 13,080: | Line 13,080: | ||
This uses zero to denote struck-out numbers. It is slightly inefficient as it strikes-out multiples above p rather than p<sup>2</sup> |
This uses zero to denote struck-out numbers. It is slightly inefficient as it strikes-out multiples above p rather than p<sup>2</sup> |
||
< |
<syntaxhighlight lang=ocaml>let rec strike_nth k n l = match l with |
||
| [] -> [] |
| [] -> [] |
||
| h :: t -> |
| h :: t -> |
||
Line 13,098: | Line 13,098: | ||
(* val primes : int -> int list *) |
(* val primes : int -> int list *) |
||
</syntaxhighlight> |
|||
</lang> |
|||
in the top-level: |
in the top-level: |
||
< |
<syntaxhighlight lang=ocaml># primes 200;; |
||
- : int list = |
- : int list = |
||
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71; |
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71; |
||
73; 79; 83; 89; 97; 101; 103; 107; 109; 113; 127; 131; 137; 139; 149; 151; |
73; 79; 83; 89; 97; 101; 103; 107; 109; 113; 127; 131; 137; 139; 149; 151; |
||
157; 163; 167; 173; 179; 181; 191; 193; 197; 199]</ |
157; 163; 167; 173; 179; 181; 191; 193; 197; 199]</syntaxhighlight> |
||
=={{header|Oforth}}== |
=={{header|Oforth}}== |
||
< |
<syntaxhighlight lang=Oforth>: eratosthenes(n) |
||
| i j | |
| i j | |
||
ListBuffer newSize(n) dup add(null) seqFrom(2, n) over addAll |
ListBuffer newSize(n) dup add(null) seqFrom(2, n) over addAll |
||
Line 13,114: | Line 13,114: | ||
dup at(i) ifNotNull: [ i sq n i step: j [ dup put(j, null) ] ] |
dup at(i) ifNotNull: [ i sq n i step: j [ dup put(j, null) ] ] |
||
] |
] |
||
filter(#notNull) ;</ |
filter(#notNull) ;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 13,123: | Line 13,123: | ||
=={{header|Ol}}== |
=={{header|Ol}}== |
||
< |
<syntaxhighlight lang=scheme> |
||
(define all (iota 999 2)) |
(define all (iota 999 2)) |
||
Line 13,140: | Line 13,140: | ||
(loop (cons (car r) l) (cdr r) (+ n 1) every))))))) |
(loop (cons (car r) l) (cdr r) (+ n 1) every))))))) |
||
) |
) |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
Line 13,149: | Line 13,149: | ||
=={{header|Oz}}== |
=={{header|Oz}}== |
||
{{trans|Haskell}} |
{{trans|Haskell}} |
||
< |
<syntaxhighlight lang=oz>declare |
||
fun {Sieve N} |
fun {Sieve N} |
||
S = {Array.new 2 N true} |
S = {Array.new 2 N true} |
||
Line 13,172: | Line 13,172: | ||
end |
end |
||
in |
in |
||
{Show {Primes 30}}</ |
{Show {Primes 30}}</syntaxhighlight> |
||
=={{header|PARI/GP}}== |
=={{header|PARI/GP}}== |
||
< |
<syntaxhighlight lang=parigp>Eratosthenes(lim)={ |
||
my(v=Vecsmall(lim\1,unused,1)); |
my(v=Vecsmall(lim\1,unused,1)); |
||
forprime(p=2,sqrt(lim), |
forprime(p=2,sqrt(lim), |
||
Line 13,183: | Line 13,183: | ||
); |
); |
||
for(i=1,lim,if(v[i],print1(i", "))) |
for(i=1,lim,if(v[i],print1(i", "))) |
||
};</ |
};</syntaxhighlight> |
||
An alternate version: |
An alternate version: |
||
< |
<syntaxhighlight lang=parigp>Sieve(n)= |
||
{ |
{ |
||
v=vector(n,unused,1); |
v=vector(n,unused,1); |
||
Line 13,194: | Line 13,194: | ||
forstep(j=i^2,n,i,v[j]=0))); |
forstep(j=i^2,n,i,v[j]=0))); |
||
for(i=2,n,if(v[i],print1(i","))) |
for(i=2,n,if(v[i],print1(i","))) |
||
};</ |
};</syntaxhighlight> |
||
=={{header|Pascal}}== |
=={{header|Pascal}}== |
||
Note: Some Pascal implementations put quite low limits on the size of a set (e.g. Turbo Pascal doesn't allow more than 256 members). To compile on such an implementation, reduce the constant PrimeLimit accordingly. |
Note: Some Pascal implementations put quite low limits on the size of a set (e.g. Turbo Pascal doesn't allow more than 256 members). To compile on such an implementation, reduce the constant PrimeLimit accordingly. |
||
< |
<syntaxhighlight lang=pascal> |
||
program primes(output) |
program primes(output) |
||
Line 13,239: | Line 13,239: | ||
end |
end |
||
end. |
end. |
||
</syntaxhighlight> |
|||
</lang> |
|||
===alternative using wheel === |
===alternative using wheel === |
||
Using growing wheel to fill array for sieving for minimal unmark operations. |
Using growing wheel to fill array for sieving for minimal unmark operations. |
||
Sieving only with possible-prime factors. |
Sieving only with possible-prime factors. |
||
< |
<syntaxhighlight lang=pascal> |
||
program prim(output); |
program prim(output); |
||
//Sieve of Erathosthenes with fast elimination of multiples of small primes |
//Sieve of Erathosthenes with fast elimination of multiples of small primes |
||
Line 13,373: | Line 13,373: | ||
inc(prCnt,Ord(primes[i])); |
inc(prCnt,Ord(primes[i])); |
||
writeln(prCnt,' primes up to ',PrimeLimit); |
writeln(prCnt,' primes up to ',PrimeLimit); |
||
end.</ |
end.</syntaxhighlight> |
||
output: ( i3 4330 Haswell 3.5 Ghz fpc 2.6.4 -O3 ) |
output: ( i3 4330 Haswell 3.5 Ghz fpc 2.6.4 -O3 ) |
||
Line 13,389: | Line 13,389: | ||
===Classic Sieve=== |
===Classic Sieve=== |
||
< |
<syntaxhighlight lang=perl>sub sieve { |
||
my $n = shift; |
my $n = shift; |
||
my @composite; |
my @composite; |
||
Line 13,404: | Line 13,404: | ||
} |
} |
||
@primes; |
@primes; |
||
}</ |
}</syntaxhighlight> |
||
===Odds only (faster)=== |
===Odds only (faster)=== |
||
< |
<syntaxhighlight lang=perl>sub sieve2 { |
||
my($n) = @_; |
my($n) = @_; |
||
return @{([],[],[2],[2,3],[2,3])[$n]} if $n <= 4; |
return @{([],[],[2],[2,3],[2,3])[$n]} if $n <= 4; |
||
Line 13,423: | Line 13,423: | ||
} |
} |
||
@primes; |
@primes; |
||
}</ |
}</syntaxhighlight> |
||
===Odds only, using vectors for lower memory use=== |
===Odds only, using vectors for lower memory use=== |
||
< |
<syntaxhighlight lang=perl>sub dj_vector { |
||
my($end) = @_; |
my($end) = @_; |
||
return @{([],[],[2],[2,3],[2,3])[$end]} if $end <= 4; |
return @{([],[],[2],[2,3],[2,3])[$end]} if $end <= 4; |
||
Line 13,441: | Line 13,441: | ||
do { push @primes, 2*$_+1 if !vec($sieve,$_,1) } for (1..int(($end-1)/2)); |
do { push @primes, 2*$_+1 if !vec($sieve,$_,1) } for (1..int(($end-1)/2)); |
||
@primes; |
@primes; |
||
}</ |
}</syntaxhighlight> |
||
===Odds only, using strings for best performance=== |
===Odds only, using strings for best performance=== |
||
Compared to array versions, about 2x faster (with 5.16.0 or later) and lower memory. Much faster than the experimental versions below. It's possible a mod-6 or mod-30 wheel could give more improvement, though possibly with obfuscation. The best next step for performance and functionality would be segmenting. |
Compared to array versions, about 2x faster (with 5.16.0 or later) and lower memory. Much faster than the experimental versions below. It's possible a mod-6 or mod-30 wheel could give more improvement, though possibly with obfuscation. The best next step for performance and functionality would be segmenting. |
||
< |
<syntaxhighlight lang=perl>sub string_sieve { |
||
my ($n, $i, $s, $d, @primes) = (shift, 7); |
my ($n, $i, $s, $d, @primes) = (shift, 7); |
||
Line 13,460: | Line 13,460: | ||
push @primes, pos while m/0/g; |
push @primes, pos while m/0/g; |
||
@primes; |
@primes; |
||
}</ |
}</syntaxhighlight> |
||
This older version uses half the memory, but at the expense of a bit of speed and code complexity: |
This older version uses half the memory, but at the expense of a bit of speed and code complexity: |
||
< |
<syntaxhighlight lang=perl>sub dj_string { |
||
my($end) = @_; |
my($end) = @_; |
||
return @{([],[],[2],[2,3],[2,3])[$end]} if $end <= 4; |
return @{([],[],[2],[2,3],[2,3])[$end]} if $end <= 4; |
||
Line 13,484: | Line 13,484: | ||
push @primes, 2*pos($sieve)-1 while $sieve =~ m/0/g; |
push @primes, 2*pos($sieve)-1 while $sieve =~ m/0/g; |
||
@primes; |
@primes; |
||
}</ |
}</syntaxhighlight> |
||
===Experimental=== |
===Experimental=== |
||
Line 13,490: | Line 13,490: | ||
Golfing a bit, at the expense of speed: |
Golfing a bit, at the expense of speed: |
||
< |
<syntaxhighlight lang=perl>sub sieve{ my (@s, $i); |
||
grep { not $s[ $i = $_ ] and do |
grep { not $s[ $i = $_ ] and do |
||
{ $s[ $i += $_ ]++ while $i <= $_[0]; 1 } |
{ $s[ $i += $_ ]++ while $i <= $_[0]; 1 } |
||
Line 13,496: | Line 13,496: | ||
} |
} |
||
print join ", " => sieve 100;</ |
print join ", " => sieve 100;</syntaxhighlight> |
||
Or with bit strings (much slower than the vector version above): |
Or with bit strings (much slower than the vector version above): |
||
< |
<syntaxhighlight lang=perl>sub sieve{ my ($s, $i); |
||
grep { not vec $s, $i = $_, 1 and do |
grep { not vec $s, $i = $_, 1 and do |
||
{ (vec $s, $i += $_, 1) = 1 while $i <= $_[0]; 1 } |
{ (vec $s, $i += $_, 1) = 1 while $i <= $_[0]; 1 } |
||
Line 13,505: | Line 13,505: | ||
} |
} |
||
print join ", " => sieve 100;</ |
print join ", " => sieve 100;</syntaxhighlight> |
||
A short recursive version: |
A short recursive version: |
||
< |
<syntaxhighlight lang=perl>sub erat { |
||
my $p = shift; |
my $p = shift; |
||
return $p, $p**2 > $_[$#_] ? @_ : erat(grep $_%$p, @_) |
return $p, $p**2 > $_[$#_] ? @_ : erat(grep $_%$p, @_) |
||
} |
} |
||
print join ', ' => erat 2..100000;</ |
print join ', ' => erat 2..100000;</syntaxhighlight> |
||
Regexp (purely an example -- the regex engine limits it to only 32769):< |
Regexp (purely an example -- the regex engine limits it to only 32769):<syntaxhighlight lang=perl>sub sieve { |
||
my ($s, $p) = "." . ("x" x shift); |
my ($s, $p) = "." . ("x" x shift); |
||
Line 13,526: | Line 13,526: | ||
} |
} |
||
print sieve(1000);</ |
print sieve(1000);</syntaxhighlight> |
||
===Extensible sieves=== |
===Extensible sieves=== |
||
Here are two incremental versions, which allows one to create a tied array of primes: |
Here are two incremental versions, which allows one to create a tied array of primes: |
||
< |
<syntaxhighlight lang=perl>use strict; |
||
use warnings; |
use warnings; |
||
package Tie::SieveOfEratosthenes; |
package Tie::SieveOfEratosthenes; |
||
Line 13,636: | Line 13,636: | ||
} |
} |
||
1;</ |
1;</syntaxhighlight> |
||
This one is based on the vector sieve shown earlier, but adds to a list as needed, just sieving in the segment. Slightly faster and half the memory vs. the previous incremental sieve. It uses the same API -- arguably we should be offset by one so $primes[$n] returns the $n'th prime. |
This one is based on the vector sieve shown earlier, but adds to a list as needed, just sieving in the segment. Slightly faster and half the memory vs. the previous incremental sieve. It uses the same API -- arguably we should be offset by one so $primes[$n] returns the $n'th prime. |
||
< |
<syntaxhighlight lang=perl>use strict; |
||
use warnings; |
use warnings; |
||
package Tie::SieveOfEratosthenes; |
package Tie::SieveOfEratosthenes; |
||
Line 13,691: | Line 13,691: | ||
} |
} |
||
1;</ |
1;</syntaxhighlight> |
||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
{{Trans|Euphoria}} |
{{Trans|Euphoria}} |
||
<!--< |
<!--<syntaxhighlight lang=Phix>(phixonline)--> |
||
<span style="color: #008080;">constant</span> <span style="color: #000000;">limit</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1000</span> |
<span style="color: #008080;">constant</span> <span style="color: #000000;">limit</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1000</span> |
||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">primes</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> |
<span style="color: #004080;">sequence</span> <span style="color: #000000;">primes</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> |
||
Line 13,712: | Line 13,712: | ||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
||
<span style="color: #7060A8;">pp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">primes</span><span style="color: #0000FF;">,{</span><span style="color: #004600;">pp_Maxlen</span><span style="color: #0000FF;">,</span><span style="color: #000000;">77</span><span style="color: #0000FF;">})</span> |
<span style="color: #7060A8;">pp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">primes</span><span style="color: #0000FF;">,{</span><span style="color: #004600;">pp_Maxlen</span><span style="color: #0000FF;">,</span><span style="color: #000000;">77</span><span style="color: #0000FF;">})</span> |
||
<!--</ |
<!--</syntaxhighlight>--> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 13,729: | Line 13,729: | ||
=={{header|Phixmonti}}== |
=={{header|Phixmonti}}== |
||
< |
<syntaxhighlight lang=Phixmonti>include ..\Utilitys.pmt |
||
def sequence /# ( ini end [step] ) #/ |
def sequence /# ( ini end [step] ) #/ |
||
Line 13,746: | Line 13,746: | ||
endfor |
endfor |
||
( 1 limit 0 ) remove |
( 1 limit 0 ) remove |
||
pstack</ |
pstack</syntaxhighlight> |
||
Another solution |
Another solution |
||
< |
<syntaxhighlight lang=Phixmonti>include ..\Utilitys.pmt |
||
1000 |
1000 |
||
Line 13,764: | Line 13,764: | ||
endfor |
endfor |
||
pstack</ |
pstack</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Primes in 1000: |
<pre>Primes in 1000: |
||
Line 13,772: | Line 13,772: | ||
=={{header|PHP}}== |
=={{header|PHP}}== |
||
< |
<syntaxhighlight lang=php> |
||
function iprimes_upto($limit) |
function iprimes_upto($limit) |
||
{ |
{ |
||
Line 13,799: | Line 13,799: | ||
100 |
100 |
||
); |
); |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 13,813: | Line 13,813: | ||
=={{header|Picat}}== |
=={{header|Picat}}== |
||
The SoE is provided in the standard library, defined as follows: |
The SoE is provided in the standard library, defined as follows: |
||
< |
<syntaxhighlight lang=Picat> |
||
primes(N) = L => |
primes(N) = L => |
||
A = new_array(N), |
A = new_array(N), |
||
Line 13,824: | Line 13,824: | ||
end, |
end, |
||
L=[I : I in 2..N, var(A[I])]. |
L=[I : I in 2..N, var(A[I])]. |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Out}} |
{{Out}} |
||
<pre> |
<pre> |
||
Line 13,832: | Line 13,832: | ||
</pre> |
</pre> |
||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
< |
<syntaxhighlight lang=PicoLisp>(de sieve (N) |
||
(let Sieve (range 1 N) |
(let Sieve (range 1 N) |
||
(set Sieve) |
(set Sieve) |
||
Line 13,839: | Line 13,839: | ||
(for (S (nth Sieve (* I I)) S (nth (cdr S) I)) |
(for (S (nth Sieve (* I I)) S (nth (cdr S) I)) |
||
(set S) ) ) ) |
(set S) ) ) ) |
||
(filter bool Sieve) ) )</ |
(filter bool Sieve) ) )</syntaxhighlight> |
||
Output: |
Output: |
||
<pre>: (sieve 100) |
<pre>: (sieve 100) |
||
Line 13,845: | Line 13,845: | ||
===Alternate Version Using a 2x3x5x7 Wheel=== |
===Alternate Version Using a 2x3x5x7 Wheel=== |
||
This works by destructively modifying the CDR of the previous cell when it finds a composite number. For sieving large sets (e.g. 1,000,000) it's much faster than the above. |
This works by destructively modifying the CDR of the previous cell when it finds a composite number. For sieving large sets (e.g. 1,000,000) it's much faster than the above. |
||
< |
<syntaxhighlight lang=PicoLisp> |
||
(setq WHEEL-2357 |
(setq WHEEL-2357 |
||
(2 4 2 4 6 2 6 4 |
(2 4 2 4 6 2 6 4 |
||
Line 13,878: | Line 13,878: | ||
(remove-multiples P)) |
(remove-multiples P)) |
||
(append (2 3 5 7) Sieve))) |
(append (2 3 5 7) Sieve))) |
||
</ |
</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre> |
<pre> |
||
Line 13,890: | Line 13,890: | ||
=={{header|PL/I}}== |
=={{header|PL/I}}== |
||
< |
<syntaxhighlight lang=pli>eratos: proc options (main) reorder; |
||
dcl i fixed bin (31); |
dcl i fixed bin (31); |
||
Line 13,926: | Line 13,926: | ||
end; |
end; |
||
end; |
end; |
||
end eratos;</ |
end eratos;</syntaxhighlight> |
||
=={{header|PL/M}}== |
=={{header|PL/M}}== |
||
< |
<syntaxhighlight lang=plm>100H: |
||
DECLARE PRIME$MAX LITERALLY '5000'; |
DECLARE PRIME$MAX LITERALLY '5000'; |
||
Line 13,989: | Line 13,989: | ||
CALL BDOS(BDOS$EXIT, 0); |
CALL BDOS(BDOS$EXIT, 0); |
||
EOF</ |
EOF</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>2 |
<pre>2 |
||
Line 14,004: | Line 14,004: | ||
=={{header|PL/SQL}}== |
=={{header|PL/SQL}}== |
||
< |
<syntaxhighlight lang=plsql>create or replace package sieve_of_eratosthenes as |
||
type array_of_booleans is varray(100000000) of boolean; |
type array_of_booleans is varray(100000000) of boolean; |
||
type table_of_integers is table of integer; |
type table_of_integers is table of integer; |
||
Line 14,040: | Line 14,040: | ||
end find_primes; |
end find_primes; |
||
end sieve_of_eratosthenes; |
end sieve_of_eratosthenes; |
||
/</ |
/</syntaxhighlight> |
||
Usage: |
Usage: |
||
< |
<syntaxhighlight lang=sql>select column_value as prime_number |
||
from table(sieve_of_eratosthenes.find_primes(30)); |
from table(sieve_of_eratosthenes.find_primes(30)); |
||
Line 14,071: | Line 14,071: | ||
664579 3203324994356 |
664579 3203324994356 |
||
Elapsed: 00:00:02.60</ |
Elapsed: 00:00:02.60</syntaxhighlight> |
||
=={{header|Pony}}== |
=={{header|Pony}}== |
||
< |
<syntaxhighlight lang=pony>use "time" // for testing |
||
use "collections" |
use "collections" |
||
Line 14,132: | Line 14,132: | ||
env.out.print("Found " + count.string() + " primes to " + limit.string() + ".") |
env.out.print("Found " + count.string() + " primes to " + limit.string() + ".") |
||
env.out.print("This took " + elpsd.string() + " milliseconds.") |
env.out.print("This took " + elpsd.string() + " milliseconds.") |
||
end</ |
end</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Primes to 100: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
<pre>Primes to 100: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 |
||
Line 14,149: | Line 14,149: | ||
It is a waste not to do the trivial changes to the above code to sieve odds-only, which is about two and a half times faster due to the decreased number of culling operations; it doesn't really do much about the huge array problem though, other than to reduce it by a factor of two. |
It is a waste not to do the trivial changes to the above code to sieve odds-only, which is about two and a half times faster due to the decreased number of culling operations; it doesn't really do much about the huge array problem though, other than to reduce it by a factor of two. |
||
< |
<syntaxhighlight lang=pony>use "time" // for testing |
||
use "collections" |
use "collections" |
||
Line 14,208: | Line 14,208: | ||
env.out.print("Found " + count.string() + " primes to " + limit.string() + ".") |
env.out.print("Found " + count.string() + " primes to " + limit.string() + ".") |
||
env.out.print("This took " + elpsd.string() + " milliseconds.") |
env.out.print("This took " + elpsd.string() + " milliseconds.") |
||
end</ |
end</syntaxhighlight> |
||
The output is the same as the above except that it is about two and a half times faster due to that many less culling operations. |
The output is the same as the above except that it is about two and a half times faster due to that many less culling operations. |
||
Line 14,230: | Line 14,230: | ||
===Basic procedure=== |
===Basic procedure=== |
||
It outputs immediately so that the number can be used by the pipeline. |
It outputs immediately so that the number can be used by the pipeline. |
||
< |
<syntaxhighlight lang=PowerShell>function Sieve ( [int] $num ) |
||
{ |
{ |
||
$isprime = @{} |
$isprime = @{} |
||
Line 14,241: | Line 14,241: | ||
{ $isprime[$i] = $false } |
{ $isprime[$i] = $false } |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
===Another implementation=== |
===Another implementation=== |
||
< |
<syntaxhighlight lang=PowerShell> |
||
function eratosthenes ($n) { |
function eratosthenes ($n) { |
||
if($n -ge 1){ |
if($n -ge 1){ |
||
Line 14,262: | Line 14,262: | ||
} |
} |
||
"$(eratosthenes 100)" |
"$(eratosthenes 100)" |
||
</syntaxhighlight> |
|||
</lang> |
|||
<b>Output:</b> |
<b>Output:</b> |
||
<pre> |
<pre> |
||
Line 14,270: | Line 14,270: | ||
=={{header|Processing}}== |
=={{header|Processing}}== |
||
Calculate the primes up to 1000000 with Processing, including a visualisation of the process. |
Calculate the primes up to 1000000 with Processing, including a visualisation of the process. |
||
< |
<syntaxhighlight lang=java>int i=2; |
||
int maxx; |
int maxx; |
||
int maxy; |
int maxy; |
||
Line 14,318: | Line 14,318: | ||
void plot(int pos, boolean active) { |
void plot(int pos, boolean active) { |
||
set(pos%maxx, pos/maxx, active?#000000:#ffffff); |
set(pos%maxx, pos/maxx, active?#000000:#ffffff); |
||
}</ |
}</syntaxhighlight> |
||
As an additional visual effect, the layout of the pixel could be changed from the line-by-line layout to a spiral-like layout starting in the middle of the screen. |
As an additional visual effect, the layout of the pixel could be changed from the line-by-line layout to a spiral-like layout starting in the middle of the screen. |
||
Line 14,324: | Line 14,324: | ||
==={{header|Processing Python mode}}=== |
==={{header|Processing Python mode}}=== |
||
< |
<syntaxhighlight lang=python>from __future__ import print_function |
||
i = 2 |
i = 2 |
||
Line 14,366: | Line 14,366: | ||
def plot(pos, active): |
def plot(pos, active): |
||
set(pos % maxx, pos / maxx, color(0) if active else color(255))</ |
set(pos % maxx, pos / maxx, color(0) if active else color(255))</syntaxhighlight> |
||
=={{header|Prolog}}== |
=={{header|Prolog}}== |
||
===Using lists=== |
===Using lists=== |
||
====Basic bounded sieve==== |
====Basic bounded sieve==== |
||
< |
<syntaxhighlight lang=Prolog>primes(N, L) :- numlist(2, N, Xs), |
||
sieve(Xs, L). |
sieve(Xs, L). |
||
Line 14,384: | Line 14,384: | ||
; H3 is H2 + H, |
; H3 is H2 + H, |
||
( H1 =:= H2 -> filter(H, H3, T, R) |
( H1 =:= H2 -> filter(H, H3, T, R) |
||
; filter(H, H3, [H1|T], R) ) ).</ |
; filter(H, H3, [H1|T], R) ) ).</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 14,399: | Line 14,399: | ||
This is actually the Euler's variant of the sieve of Eratosthenes, generating (and thus removing) each multiple only once, though a sub-optimal implementation. |
This is actually the Euler's variant of the sieve of Eratosthenes, generating (and thus removing) each multiple only once, though a sub-optimal implementation. |
||
< |
<syntaxhighlight lang=Prolog>primes(X, PS) :- X > 1, range(2, X, R), sieve(R, PS). |
||
range(X, X, [X]) :- !. |
range(X, X, [X]) :- !. |
||
Line 14,412: | Line 14,412: | ||
remove( _, [], [] ) :- !. |
remove( _, [], [] ) :- !. |
||
remove( [H | X], [H | Y], R ) :- !, remove(X, Y, R). |
remove( [H | X], [H | Y], R ) :- !, remove(X, Y, R). |
||
remove( X, [H | Y], [H | R]) :- remove(X, Y, R). </ |
remove( X, [H | Y], [H | R]) :- remove(X, Y, R). </syntaxhighlight> |
||
Running in SWI Prolog, |
Running in SWI Prolog, |
||
Line 14,426: | Line 14,426: | ||
We can stop early, with massive improvement in complexity (below ~ <i>n<sup>1.5</sup></i> inferences, empirically, vs. the ~ <i>n<sup>2</sup></i> of the above, in ''n'' primes produced; showing only the modified predicates): |
We can stop early, with massive improvement in complexity (below ~ <i>n<sup>1.5</sup></i> inferences, empirically, vs. the ~ <i>n<sup>2</sup></i> of the above, in ''n'' primes produced; showing only the modified predicates): |
||
< |
<syntaxhighlight lang=Prolog>primes(X, PS) :- X > 1, range(2, X, R), sieve(X, R, PS). |
||
sieve(X, [H | T], [H | T]) :- H*H > X, !. |
sieve(X, [H | T], [H | T]) :- H*H > X, !. |
||
sieve(X, [H | T], [H | S]) :- maplist( mult(H), [H | T], MS), |
sieve(X, [H | T], [H | S]) :- maplist( mult(H), [H | T], MS), |
||
remove(MS, T, R), sieve(X, R, S).</ |
remove(MS, T, R), sieve(X, R, S).</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 14,442: | Line 14,442: | ||
Optimized by stopping early, traditional sieve of Eratosthenes generating multiples by iterated addition. |
Optimized by stopping early, traditional sieve of Eratosthenes generating multiples by iterated addition. |
||
< |
<syntaxhighlight lang=Prolog>primes(X, PS) :- X > 1, range(2, X, R), sieve(X, R, PS). |
||
range(X, X, [X]) :- !. |
range(X, X, [X]) :- !. |
||
Line 14,457: | Line 14,457: | ||
remove( [H | X], [H | Y], R ) :- !, remove(X, Y, R). |
remove( [H | X], [H | Y], R ) :- !, remove(X, Y, R). |
||
remove( [H | X], [G | Y], R ) :- H < G, !, remove(X, [G | Y], R). |
remove( [H | X], [G | Y], R ) :- H < G, !, remove(X, [G | Y], R). |
||
remove( X, [H | Y], [H | R]) :- remove(X, Y, R). </ |
remove( X, [H | Y], [H | R]) :- remove(X, Y, R). </syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 14,468: | Line 14,468: | ||
====Sift the Two's and Sift the Three's==== |
====Sift the Two's and Sift the Three's==== |
||
Another version, based on Cloksin&Mellish p.175, modified to stop early as well as to work with odds only and use addition in the removing predicate, instead of the <code>mod</code> testing as the original was doing: |
Another version, based on Cloksin&Mellish p.175, modified to stop early as well as to work with odds only and use addition in the removing predicate, instead of the <code>mod</code> testing as the original was doing: |
||
< |
<syntaxhighlight lang=Prolog>primes(N,[]):- N < 2, !. |
||
primes(N,[2|R]):- ints(3,N,L), sift(N,L,R). |
primes(N,[2|R]):- ints(3,N,L), sift(N,L,R). |
||
ints(A,B,[A|C]):- A=<B -> D is A+2, ints(D,B,C). |
ints(A,B,[A|C]):- A=<B -> D is A+2, ints(D,B,C). |
||
Line 14,480: | Line 14,480: | ||
; M==A -> M2 is M+2*P, rmv(P,M2,B,C) |
; M==A -> M2 is M+2*P, rmv(P,M2,B,C) |
||
; M<A -> M2 is M+2*P, rmv(P,M2,[A|B],C) |
; M<A -> M2 is M+2*P, rmv(P,M2,[A|B],C) |
||
).</ |
).</syntaxhighlight> |
||
Runs at about n^1.4 time empirically, producing 20,000 primes in 1.4 secs [https://swish.swi-prolog.org/p/modified_C&M_SoE.pl on the SWISH platform] as of 2021-11-26. |
Runs at about n^1.4 time empirically, producing 20,000 primes in 1.4 secs [https://swish.swi-prolog.org/p/modified_C&M_SoE.pl on the SWISH platform] as of 2021-11-26. |
||
Line 14,490: | Line 14,490: | ||
====Basic variant==== |
====Basic variant==== |
||
< |
<syntaxhighlight lang=prolog>primes(PS):- count(2, 1, NS), sieve(NS, PS). |
||
count(N, D, [N|T]):- freeze(T, (N2 is N+D, count(N2, D, T))). |
count(N, D, [N|T]):- freeze(T, (N2 is N+D, count(N2, D, T))). |
||
Line 14,500: | Line 14,500: | ||
remove([A|T],[B|S],R):- A < B -> remove(T,[B|S],R) ; |
remove([A|T],[B|S],R):- A < B -> remove(T,[B|S],R) ; |
||
A=:=B -> remove(T,S,R) ; |
A=:=B -> remove(T,S,R) ; |
||
R = [B|R2], freeze(R2, remove([A|T], S, R2)).</ |
R = [B|R2], freeze(R2, remove([A|T], S, R2)).</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 14,512: | Line 14,512: | ||
====Optimized by postponed removal==== |
====Optimized by postponed removal==== |
||
Showing only changed predicates. |
Showing only changed predicates. |
||
< |
<syntaxhighlight lang=prolog>primes([2|PS]):- |
||
freeze(PS, (primes(BPS), count(3, 1, NS), sieve(NS, BPS, 4, PS))). |
freeze(PS, (primes(BPS), count(3, 1, NS), sieve(NS, BPS, 4, PS))). |
||
Line 14,518: | Line 14,518: | ||
N < Q -> PS = [N|PS2], freeze(PS2, sieve(NS, BPS, Q, PS2)) |
N < Q -> PS = [N|PS2], freeze(PS2, sieve(NS, BPS, Q, PS2)) |
||
; BPS = [BP,BP2|BPS2], Q2 is BP2*BP2, count(Q, BP, MS), |
; BPS = [BP,BP2|BPS2], Q2 is BP2*BP2, count(Q, BP, MS), |
||
remove(MS, NS, R), sieve(R, [BP2|BPS2], Q2, PS). </ |
remove(MS, NS, R), sieve(R, [BP2|BPS2], Q2, PS). </syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 14,539: | Line 14,539: | ||
to record integers that are found to be composite. |
to record integers that are found to be composite. |
||
< |
<syntaxhighlight lang=Prolog>% %sieve( +N, -Primes ) is true if Primes is the list of consecutive primes |
||
% that are less than or equal to N |
% that are less than or equal to N |
||
sieve( N, [2|Rest]) :- |
sieve( N, [2|Rest]) :- |
||
Line 14,574: | Line 14,574: | ||
:- dynamic( composite/1 ). |
:- dynamic( composite/1 ). |
||
</syntaxhighlight> |
|||
</lang> |
|||
The above has been tested with SWI-Prolog and gprolog. |
The above has been tested with SWI-Prolog and gprolog. |
||
< |
<syntaxhighlight lang=Prolog>% SWI-Prolog: |
||
?- time( (sieve(100000,P), length(P,N), writeln(N), last(P, LP), writeln(LP) )). |
?- time( (sieve(100000,P), length(P,N), writeln(N), last(P, LP), writeln(LP) )). |
||
Line 14,584: | Line 14,584: | ||
N = 9592, |
N = 9592, |
||
LP = 99991. |
LP = 99991. |
||
</syntaxhighlight> |
|||
</lang> |
|||
==== Optimized approach==== |
==== Optimized approach==== |
||
[http://ideone.com/WDC7z Works with SWI-Prolog]. |
[http://ideone.com/WDC7z Works with SWI-Prolog]. |
||
< |
<syntaxhighlight lang=Prolog>sieve(N, [2|PS]) :- % PS is list of odd primes up to N |
||
retractall(mult(_)), |
retractall(mult(_)), |
||
sieve_O(3,N,PS). |
sieve_O(3,N,PS). |
||
Line 14,618: | Line 14,618: | ||
:- dynamic( mult/1 ). |
:- dynamic( mult/1 ). |
||
:- main(100000), main(1000000).</ |
:- main(100000), main(1000000).</syntaxhighlight> |
||
Running it produces |
Running it produces |
||
< |
<syntaxhighlight lang=Prolog>%% stdout copy |
||
[9592, 99991] |
[9592, 99991] |
||
[78498, 999983] |
[78498, 999983] |
||
Line 14,628: | Line 14,628: | ||
%% stderr copy |
%% stderr copy |
||
% 293,176 inferences, 0.14 CPU in 0.14 seconds (101% CPU, 2094114 Lips) |
% 293,176 inferences, 0.14 CPU in 0.14 seconds (101% CPU, 2094114 Lips) |
||
% 3,122,303 inferences, 1.63 CPU in 1.67 seconds (97% CPU, 1915523 Lips)</ |
% 3,122,303 inferences, 1.63 CPU in 1.67 seconds (97% CPU, 1915523 Lips)</syntaxhighlight> |
||
which indicates <i>~ N<sup>1.1</sup></i> [http://en.wikipedia.org/wiki/Analysis_of_algorithms#Empirical_orders_of_growth empirical orders of growth], which is consistent with the ''O(N log log N)'' theoretical runtime complexity. |
which indicates <i>~ N<sup>1.1</sup></i> [http://en.wikipedia.org/wiki/Analysis_of_algorithms#Empirical_orders_of_growth empirical orders of growth], which is consistent with the ''O(N log log N)'' theoretical runtime complexity. |
||
Line 14,636: | Line 14,636: | ||
Uses a ariority queue, from the paper "The Genuine Sieve of Eratosthenes" by Melissa O'Neill. Works with YAP (Yet Another Prolog) |
Uses a ariority queue, from the paper "The Genuine Sieve of Eratosthenes" by Melissa O'Neill. Works with YAP (Yet Another Prolog) |
||
< |
<syntaxhighlight lang=Prolog>?- use_module(library(heaps)). |
||
prime(2). |
prime(2). |
||
Line 14,661: | Line 14,661: | ||
adjust_heap(H2, N, H). |
adjust_heap(H2, N, H). |
||
adjust_heap(H, N, H) :- |
adjust_heap(H, N, H) :- |
||
\+ min_of_heap(H, N, _).</ |
\+ min_of_heap(H, N, _).</syntaxhighlight> |
||
=={{header|PureBasic}}== |
=={{header|PureBasic}}== |
||
===Basic procedure=== |
===Basic procedure=== |
||
< |
<syntaxhighlight lang=PureBasic>For n=2 To Sqr(lim) |
||
If Nums(n)=0 |
If Nums(n)=0 |
||
m=n*n |
m=n*n |
||
Line 14,674: | Line 14,674: | ||
Wend |
Wend |
||
EndIf |
EndIf |
||
Next n</ |
Next n</syntaxhighlight> |
||
===Working example=== |
===Working example=== |
||
< |
<syntaxhighlight lang=PureBasic>Dim Nums.i(0) |
||
Define l, n, m, lim |
Define l, n, m, lim |
||
Line 14,713: | Line 14,713: | ||
Print(#CRLF$+#CRLF$+"Press ENTER to exit"): Input() |
Print(#CRLF$+#CRLF$+"Press ENTER to exit"): Input() |
||
CloseConsole() |
CloseConsole() |
||
EndIf</ |
EndIf</syntaxhighlight> |
||
Output may look like; |
Output may look like; |
||
Line 14,738: | Line 14,738: | ||
avoids explicit iteration in the interpreter, giving a further speed improvement. |
avoids explicit iteration in the interpreter, giving a further speed improvement. |
||
< |
<syntaxhighlight lang=python>def eratosthenes2(n): |
||
multiples = set() |
multiples = set() |
||
for i in range(2, n+1): |
for i in range(2, n+1): |
||
Line 14,745: | Line 14,745: | ||
multiples.update(range(i*i, n+1, i)) |
multiples.update(range(i*i, n+1, i)) |
||
print(list(eratosthenes2(100)))</ |
print(list(eratosthenes2(100)))</syntaxhighlight> |
||
===Using array lookup=== |
===Using array lookup=== |
||
The version below uses array lookup to test for primality. The function <tt>primes_upto()</tt> is a straightforward implementation of [http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Algorithm Sieve of Eratosthenes]algorithm. It returns prime numbers less than or equal to <tt>limit</tt>. |
The version below uses array lookup to test for primality. The function <tt>primes_upto()</tt> is a straightforward implementation of [http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Algorithm Sieve of Eratosthenes]algorithm. It returns prime numbers less than or equal to <tt>limit</tt>. |
||
< |
<syntaxhighlight lang=python>def primes_upto(limit): |
||
is_prime = [False] * 2 + [True] * (limit - 1) |
is_prime = [False] * 2 + [True] * (limit - 1) |
||
for n in range(int(limit**0.5 + 1.5)): # stop at ``sqrt(limit)`` |
for n in range(int(limit**0.5 + 1.5)): # stop at ``sqrt(limit)`` |
||
Line 14,755: | Line 14,755: | ||
for i in range(n*n, limit+1, n): |
for i in range(n*n, limit+1, n): |
||
is_prime[i] = False |
is_prime[i] = False |
||
return [i for i, prime in enumerate(is_prime) if prime]</ |
return [i for i, prime in enumerate(is_prime) if prime]</syntaxhighlight> |
||
===Using generator=== |
===Using generator=== |
||
The following code may be slightly slower than using the array/list as above, but uses no memory for output: |
The following code may be slightly slower than using the array/list as above, but uses no memory for output: |
||
< |
<syntaxhighlight lang=python>def iprimes_upto(limit): |
||
is_prime = [False] * 2 + [True] * (limit - 1) |
is_prime = [False] * 2 + [True] * (limit - 1) |
||
for n in xrange(int(limit**0.5 + 1.5)): # stop at ``sqrt(limit)`` |
for n in xrange(int(limit**0.5 + 1.5)): # stop at ``sqrt(limit)`` |
||
Line 14,766: | Line 14,766: | ||
is_prime[i] = False |
is_prime[i] = False |
||
for i in xrange(limit + 1): |
for i in xrange(limit + 1): |
||
if is_prime[i]: yield i</ |
if is_prime[i]: yield i</syntaxhighlight>{{out|Example}}<syntaxhighlight lang=python>>>> list(iprimes_upto(15)) |
||
[2, 3, 5, 7, 11, 13]</ |
[2, 3, 5, 7, 11, 13]</syntaxhighlight> |
||
===Odds-only version of the array sieve above=== |
===Odds-only version of the array sieve above=== |
||
The following code is faster than the above array version using only odd composite operations (for a factor of over two) and because it has been optimized to use slice operations for composite number culling to avoid extra work by the interpreter: |
The following code is faster than the above array version using only odd composite operations (for a factor of over two) and because it has been optimized to use slice operations for composite number culling to avoid extra work by the interpreter: |
||
< |
<syntaxhighlight lang=python>def primes2(limit): |
||
if limit < 2: return [] |
if limit < 2: return [] |
||
if limit < 3: return [2] |
if limit < 3: return [2] |
||
Line 14,781: | Line 14,781: | ||
s = p * (i + 1) + i |
s = p * (i + 1) + i |
||
buf[s::p] = [False] * ((lmtbf - s) // p + 1) |
buf[s::p] = [False] * ((lmtbf - s) // p + 1) |
||
return [2] + [i + i + 3 for i, v in enumerate(buf) if v]</ |
return [2] + [i + i + 3 for i, v in enumerate(buf) if v]</syntaxhighlight> |
||
Note that "range" needs to be changed to "xrange" for maximum speed with Python 2. |
Note that "range" needs to be changed to "xrange" for maximum speed with Python 2. |
||
Line 14,788: | Line 14,788: | ||
The following code is faster than the above generator version using only odd composite operations (for a factor of over two) and because it has been optimized to use slice operations for composite number culling to avoid extra work by the interpreter: |
The following code is faster than the above generator version using only odd composite operations (for a factor of over two) and because it has been optimized to use slice operations for composite number culling to avoid extra work by the interpreter: |
||
< |
<syntaxhighlight lang=python>def iprimes2(limit): |
||
yield 2 |
yield 2 |
||
if limit < 3: return |
if limit < 3: return |
||
Line 14,799: | Line 14,799: | ||
buf[s::p] = [False] * ((lmtbf - s) // p + 1) |
buf[s::p] = [False] * ((lmtbf - s) // p + 1) |
||
for i in range(lmtbf + 1): |
for i in range(lmtbf + 1): |
||
if buf[i]: yield (i + i + 3)</ |
if buf[i]: yield (i + i + 3)</syntaxhighlight> |
||
Note that this version may actually run slightly faster than the equivalent array version with the advantage that the output doesn't require any memory. |
Note that this version may actually run slightly faster than the equivalent array version with the advantage that the output doesn't require any memory. |
||
Line 14,808: | Line 14,808: | ||
This uses a 235 factorial wheel for further reductions in operations; the same techniques can be applied to the array version as well; it runs slightly faster and uses slightly less memory as compared to the odds-only algorithms: |
This uses a 235 factorial wheel for further reductions in operations; the same techniques can be applied to the array version as well; it runs slightly faster and uses slightly less memory as compared to the odds-only algorithms: |
||
< |
<syntaxhighlight lang=python>def primes235(limit): |
||
yield 2; yield 3; yield 5 |
yield 2; yield 3; yield 5 |
||
if limit < 7: return |
if limit < 7: return |
||
Line 14,827: | Line 14,827: | ||
s += p * gaps[ci]; ci += 1 |
s += p * gaps[ci]; ci += 1 |
||
for i in range(lmtbf - 6 + (ndxs[(limit - 7) % 30])): # adjust for extras |
for i in range(lmtbf - 6 + (ndxs[(limit - 7) % 30])): # adjust for extras |
||
if buf[i]: yield (30 * (i >> 3) + modPrms[i & 7])</ |
if buf[i]: yield (30 * (i >> 3) + modPrms[i & 7])</syntaxhighlight> |
||
Note: Much of the time (almost two thirds for this last case for Python 2.7.6) for any of these array/list or generator algorithms is used in the computation and enumeration of the final output in the last line(s), so any slight changes to those lines can greatly affect execution time. For Python 3 this enumeration is about twice as slow as Python 2 (Python 3.3 slow and 3.4 slower) for an even bigger percentage of time spent just outputting the results. This slow enumeration means that there is little advantage to versions that use even further wheel factorization, as the composite number culling is a small part of the time to enumerate the results. |
Note: Much of the time (almost two thirds for this last case for Python 2.7.6) for any of these array/list or generator algorithms is used in the computation and enumeration of the final output in the last line(s), so any slight changes to those lines can greatly affect execution time. For Python 3 this enumeration is about twice as slow as Python 2 (Python 3.3 slow and 3.4 slower) for an even bigger percentage of time spent just outputting the results. This slow enumeration means that there is little advantage to versions that use even further wheel factorization, as the composite number culling is a small part of the time to enumerate the results. |
||
Line 14,838: | Line 14,838: | ||
{{libheader|NumPy}} |
{{libheader|NumPy}} |
||
Below code adapted from [http://en.literateprograms.org/Sieve_of_Eratosthenes_(Python,_arrays)#simple_implementation literateprograms.org] using [http://numpy.scipy.org/ numpy] |
Below code adapted from [http://en.literateprograms.org/Sieve_of_Eratosthenes_(Python,_arrays)#simple_implementation literateprograms.org] using [http://numpy.scipy.org/ numpy] |
||
< |
<syntaxhighlight lang=python>import numpy |
||
def primes_upto2(limit): |
def primes_upto2(limit): |
||
is_prime = numpy.ones(limit + 1, dtype=numpy.bool) |
is_prime = numpy.ones(limit + 1, dtype=numpy.bool) |
||
Line 14,844: | Line 14,844: | ||
if is_prime[n]: |
if is_prime[n]: |
||
is_prime[n*n::n] = 0 |
is_prime[n*n::n] = 0 |
||
return numpy.nonzero(is_prime)[0][2:]</ |
return numpy.nonzero(is_prime)[0][2:]</syntaxhighlight> |
||
'''Performance note:''' there is no point to add wheels here, due to execution of <tt>p[n*n::n] = 0</tt> and <tt>nonzero()</tt> takes us almost all time. |
'''Performance note:''' there is no point to add wheels here, due to execution of <tt>p[n*n::n] = 0</tt> and <tt>nonzero()</tt> takes us almost all time. |
||
Line 14,851: | Line 14,851: | ||
===Using wheels with numpy=== |
===Using wheels with numpy=== |
||
Version with wheel based optimization: |
Version with wheel based optimization: |
||
< |
<syntaxhighlight lang=python>from numpy import array, bool_, multiply, nonzero, ones, put, resize |
||
# |
# |
||
def makepattern(smallprimes): |
def makepattern(smallprimes): |
||
Line 14,870: | Line 14,870: | ||
if isprime[n]: |
if isprime[n]: |
||
isprime[n*n::n] = 0 |
isprime[n*n::n] = 0 |
||
return nonzero(isprime)[0]</ |
return nonzero(isprime)[0]</syntaxhighlight> |
||
Examples: |
Examples: |
||
< |
<syntaxhighlight lang=python>>>> primes_upto3(10**6, smallprimes=(2,3)) # Wall time: 0.17 |
||
array([ 2, 3, 5, ..., 999961, 999979, 999983]) |
array([ 2, 3, 5, ..., 999961, 999979, 999983]) |
||
>>> primes_upto3(10**7, smallprimes=(2,3)) # Wall time: '''2.13''' |
>>> primes_upto3(10**7, smallprimes=(2,3)) # Wall time: '''2.13''' |
||
Line 14,884: | Line 14,884: | ||
array([ 2, 3, 5, ..., 9999971, 9999973, 9999991]) |
array([ 2, 3, 5, ..., 9999971, 9999973, 9999991]) |
||
>>> primes_upto3(10**7) # Wall time: '''1.30''' |
>>> primes_upto3(10**7) # Wall time: '''1.30''' |
||
array([ 2, 3, 5, ..., 9999971, 9999973, 9999991])</ |
array([ 2, 3, 5, ..., 9999971, 9999973, 9999991])</syntaxhighlight> |
||
The above-mentioned examples demonstrate that the ''given'' wheel based optimization does not show significant performance gain. |
The above-mentioned examples demonstrate that the ''given'' wheel based optimization does not show significant performance gain. |
||
Line 14,891: | Line 14,891: | ||
{{works with|Python|2.6+, 3.x}} |
{{works with|Python|2.6+, 3.x}} |
||
< |
<syntaxhighlight lang=python>import heapq |
||
# generates all prime numbers |
# generates all prime numbers |
||
Line 14,918: | Line 14,918: | ||
yield i |
yield i |
||
i += 1</ |
i += 1</syntaxhighlight> |
||
Example: |
Example: |
||
<pre> |
<pre> |
||
Line 14,939: | Line 14,939: | ||
The adding of each discovered prime's incremental step info to the mapping should be '''''postponed''''' until the prime's ''square'' is seen amongst the candidate numbers, as it is useless before that point. This drastically reduces the space complexity from <i>O(n)</i> to <i>O(sqrt(n/log(n)))</i>, in ''<code>n</code>'' primes produced, and also lowers the run time complexity quite low ([http://ideone.com/VXep9F this test entry in Python 2.7] and [http://ideone.com/muuS4H this test entry in Python 3.x] shows about <i>~ n<sup>1.08</sup></i> [http://en.wikipedia.org/wiki/Analysis_of_algorithms#Empirical_orders_of_growth empirical order of growth] which is very close to the theoretical value of <i>O(n log(n) log(log(n)))</i>, in ''<code>n</code>'' primes produced): |
The adding of each discovered prime's incremental step info to the mapping should be '''''postponed''''' until the prime's ''square'' is seen amongst the candidate numbers, as it is useless before that point. This drastically reduces the space complexity from <i>O(n)</i> to <i>O(sqrt(n/log(n)))</i>, in ''<code>n</code>'' primes produced, and also lowers the run time complexity quite low ([http://ideone.com/VXep9F this test entry in Python 2.7] and [http://ideone.com/muuS4H this test entry in Python 3.x] shows about <i>~ n<sup>1.08</sup></i> [http://en.wikipedia.org/wiki/Analysis_of_algorithms#Empirical_orders_of_growth empirical order of growth] which is very close to the theoretical value of <i>O(n log(n) log(log(n)))</i>, in ''<code>n</code>'' primes produced): |
||
{{works with|Python|2.6+, 3.x}} |
{{works with|Python|2.6+, 3.x}} |
||
< |
<syntaxhighlight lang=python>def primes(): |
||
yield 2; yield 3; yield 5; yield 7; |
yield 2; yield 3; yield 5; yield 7; |
||
bps = (p for p in primes()) # separate supply of "base" primes (b.p.) |
bps = (p for p in primes()) # separate supply of "base" primes (b.p.) |
||
Line 14,962: | Line 14,962: | ||
import itertools |
import itertools |
||
def primes_up_to(limit): |
def primes_up_to(limit): |
||
return list(itertools.takewhile(lambda p: p <= limit, primes()))</ |
return list(itertools.takewhile(lambda p: p <= limit, primes()))</syntaxhighlight> |
||
===Fast infinite generator using a wheel=== |
===Fast infinite generator using a wheel=== |
||
Although theoretically over three times faster than odds-only, the following code using a 2/3/5/7 wheel is only about 1.5 times faster than the above odds-only code due to the extra overheads in code complexity. The [http://ideone.com/LFaRnT test link for Python 2.7] and [http://ideone.com/ZAY0T2 test link for Python 3.x] show about the same empirical order of growth as the odds-only implementation above once the range grows enough so the dict operations become amortized to a constant factor. |
Although theoretically over three times faster than odds-only, the following code using a 2/3/5/7 wheel is only about 1.5 times faster than the above odds-only code due to the extra overheads in code complexity. The [http://ideone.com/LFaRnT test link for Python 2.7] and [http://ideone.com/ZAY0T2 test link for Python 3.x] show about the same empirical order of growth as the odds-only implementation above once the range grows enough so the dict operations become amortized to a constant factor. |
||
{{works with|Python|2.6+, 3.x}} |
{{works with|Python|2.6+, 3.x}} |
||
< |
<syntaxhighlight lang=python>def primes(): |
||
for p in [2,3,5,7]: yield p # base wheel primes |
for p in [2,3,5,7]: yield p # base wheel primes |
||
gaps1 = [ 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 ] |
gaps1 = [ 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 ] |
||
Line 14,996: | Line 14,996: | ||
if nni > 47: nni = 0 |
if nni > 47: nni = 0 |
||
n += gaps[ni]; ni = nni # advance on the wheel |
n += gaps[ni]; ni = nni # advance on the wheel |
||
for p, pi in wheel_prime_pairs(): yield p # strip out indexes</ |
for p, pi in wheel_prime_pairs(): yield p # strip out indexes</syntaxhighlight> |
||
Further gains of about 1.5 times in speed can be made using the same code by only changing the tables and a few constants for a further constant factor gain of about 1.5 times in speed by using a 2/3/5/7/11/13/17 wheel (with the gaps list 92160 elements long) computed for a slight constant overhead time as per the [http://ideone.com/4Ld26g test link for Python 2.7] and [http://ideone.com/72Dmyt test link for Python 3.x]. Further wheel factorization will not really be worth it as the gains will be small (if any and not losses) and the gaps table huge - it is already too big for efficient use by 32-bit Python 3 and the wheel should likely be stopped at 13: |
Further gains of about 1.5 times in speed can be made using the same code by only changing the tables and a few constants for a further constant factor gain of about 1.5 times in speed by using a 2/3/5/7/11/13/17 wheel (with the gaps list 92160 elements long) computed for a slight constant overhead time as per the [http://ideone.com/4Ld26g test link for Python 2.7] and [http://ideone.com/72Dmyt test link for Python 3.x]. Further wheel factorization will not really be worth it as the gains will be small (if any and not losses) and the gaps table huge - it is already too big for efficient use by 32-bit Python 3 and the wheel should likely be stopped at 13: |
||
< |
<syntaxhighlight lang=python>def primes(): |
||
whlPrms = [2,3,5,7,11,13,17] # base wheel primes |
whlPrms = [2,3,5,7,11,13,17] # base wheel primes |
||
for p in whlPrms: yield p |
for p in whlPrms: yield p |
||
Line 15,039: | Line 15,039: | ||
n += gaps[ni]; ni = nni # advance on the wheel |
n += gaps[ni]; ni = nni # advance on the wheel |
||
for p, pi in wheel_prime_pairs(): yield p # strip out indexes |
for p, pi in wheel_prime_pairs(): yield p # strip out indexes |
||
</syntaxhighlight> |
|||
</lang> |
|||
Line 15,046: | Line 15,046: | ||
=={{header|Quackery}}== |
=={{header|Quackery}}== |
||
< |
<syntaxhighlight lang=Quackery> [ dup 1 |
||
[ 2dup > while |
[ 2dup > while |
||
+ 1 >> |
+ 1 >> |
||
Line 15,078: | Line 15,078: | ||
100 eratosthenes |
100 eratosthenes |
||
100 times [ i^ isprime if [ i^ echo sp ] ]</ |
100 times [ i^ isprime if [ i^ echo sp ] ]</syntaxhighlight> |
||
'''Output:''' |
'''Output:''' |
||
Line 15,085: | Line 15,085: | ||
=={{header|R}}== |
=={{header|R}}== |
||
< |
<syntaxhighlight lang=rsplus>sieve <- function(n) { |
||
if (n < 2) integer(0) |
if (n < 2) integer(0) |
||
else { |
else { |
||
Line 15,099: | Line 15,099: | ||
} |
} |
||
sieve(1000)</ |
sieve(1000)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 15,115: | Line 15,115: | ||
'''Alternate Odds-Only Version''' |
'''Alternate Odds-Only Version''' |
||
< |
<syntaxhighlight lang=rsplus>sieve <- function(n) { |
||
if (n < 2) return(integer(0)) |
if (n < 2) return(integer(0)) |
||
lmt <- (sqrt(n) - 1) / 2 |
lmt <- (sqrt(n) - 1) / 2 |
||
Line 15,133: | Line 15,133: | ||
} |
} |
||
sieve(1000)</ |
sieve(1000)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 15,141: | Line 15,141: | ||
===Imperative versions=== |
===Imperative versions=== |
||
Ugly imperative version: |
Ugly imperative version: |
||
< |
<syntaxhighlight lang=Racket>#lang racket |
||
(define (sieve n) |
(define (sieve n) |
||
Line 15,153: | Line 15,153: | ||
(reverse primes)) |
(reverse primes)) |
||
(sieve 100)</ |
(sieve 100)</syntaxhighlight> |
||
A little nicer, but still imperative: |
A little nicer, but still imperative: |
||
< |
<syntaxhighlight lang=Racket>#lang racket |
||
(define (sieve n) |
(define (sieve n) |
||
(define primes (make-vector (add1 n) #t)) |
(define primes (make-vector (add1 n) #t)) |
||
Line 15,166: | Line 15,166: | ||
#:when (vector-ref primes n)) |
#:when (vector-ref primes n)) |
||
n)) |
n)) |
||
(sieve 100)</ |
(sieve 100)</syntaxhighlight> |
||
Imperative version using a bit vector: |
Imperative version using a bit vector: |
||
< |
<syntaxhighlight lang=Racket>#lang racket |
||
(require data/bit-vector) |
(require data/bit-vector) |
||
;; Returns a list of prime numbers up to natural number limit |
;; Returns a list of prime numbers up to natural number limit |
||
Line 15,182: | Line 15,182: | ||
(for/list ([i (bit-vector-length bv)] #:unless (bit-vector-ref bv i)) i)) |
(for/list ([i (bit-vector-length bv)] #:unless (bit-vector-ref bv i)) i)) |
||
(eratosthenes 100) |
(eratosthenes 100) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{output}} |
{{output}} |
||
Line 15,191: | Line 15,191: | ||
These examples use infinite lists (streams) to implement the sieve of Eratosthenes in a functional way, and producing all prime numbers. The following functions are used as a prefix for pieces of code that follow: |
These examples use infinite lists (streams) to implement the sieve of Eratosthenes in a functional way, and producing all prime numbers. The following functions are used as a prefix for pieces of code that follow: |
||
< |
<syntaxhighlight lang=Racket>#lang lazy |
||
(define (ints-from i d) (cons i (ints-from (+ i d) d))) |
(define (ints-from i d) (cons i (ints-from (+ i d) d))) |
||
(define (after n l f) |
(define (after n l f) |
||
Line 15,204: | Line 15,204: | ||
(cond [(< x1 x2) (cons x1 (union (cdr l1) l2 ))] |
(cond [(< x1 x2) (cons x1 (union (cdr l1) l2 ))] |
||
[(> x1 x2) (cons x2 (union l1 (cdr l2)))] |
[(> x1 x2) (cons x2 (union l1 (cdr l2)))] |
||
[else (cons x1 (union (cdr l1) (cdr l2)))])))</ |
[else (cons x1 (union (cdr l1) (cdr l2)))])))</syntaxhighlight> |
||
==== Basic sieve ==== |
==== Basic sieve ==== |
||
< |
<syntaxhighlight lang=Racket>(define (sieve l) |
||
(define x (car l)) |
(define x (car l)) |
||
(cons x (sieve (diff (cdr l) (ints-from (+ x x) x))))) |
(cons x (sieve (diff (cdr l) (ints-from (+ x x) x))))) |
||
(define primes (sieve (ints-from 2 1))) |
(define primes (sieve (ints-from 2 1))) |
||
(!! (take 25 primes))</ |
(!! (take 25 primes))</syntaxhighlight> |
||
Runs at ~ n^2.1 [http://en.wikipedia.org/wiki/Analysis_of_algorithms#Empirical_orders_of_growth empirically], for ''n <= 1500'' primes produced. |
Runs at ~ n^2.1 [http://en.wikipedia.org/wiki/Analysis_of_algorithms#Empirical_orders_of_growth empirically], for ''n <= 1500'' primes produced. |
||
Line 15,219: | Line 15,219: | ||
Note that the first number, 2, and its multiples stream <code>(ints-from 4 2)</code> are handled separately to ensure that the non-primes list is never empty, which simplifies the code for <code>union</code> which assumes non-empty infinite lists. |
Note that the first number, 2, and its multiples stream <code>(ints-from 4 2)</code> are handled separately to ensure that the non-primes list is never empty, which simplifies the code for <code>union</code> which assumes non-empty infinite lists. |
||
< |
<syntaxhighlight lang=Racket>(define (sieve l non-primes) |
||
(let ([x (car l)] [np (car non-primes)]) |
(let ([x (car l)] [np (car non-primes)]) |
||
(cond [(= x np) (sieve (cdr l) (cdr non-primes))] ; else x < np |
(cond [(= x np) (sieve (cdr l) (cdr non-primes))] ; else x < np |
||
[else (cons x (sieve (cdr l) (union (ints-from (* x x) x) |
[else (cons x (sieve (cdr l) (union (ints-from (* x x) x) |
||
non-primes)))]))) |
non-primes)))]))) |
||
(define primes (cons 2 (sieve (ints-from 3 1) (ints-from 4 2))))</ |
(define primes (cons 2 (sieve (ints-from 3 1) (ints-from 4 2))))</syntaxhighlight> |
||
==== Basic sieve Optimized with postponed processing ==== |
==== Basic sieve Optimized with postponed processing ==== |
||
Since a prime's multiples that count start from its square, we should only start removing them when we reach that square. |
Since a prime's multiples that count start from its square, we should only start removing them when we reach that square. |
||
< |
<syntaxhighlight lang=Racket>(define (sieve l prs) |
||
(define p (car prs)) |
(define p (car prs)) |
||
(define q (* p p)) |
(define q (* p p)) |
||
(after q l (λ(t) (sieve (diff t (ints-from q p)) (cdr prs))))) |
(after q l (λ(t) (sieve (diff t (ints-from q p)) (cdr prs))))) |
||
(define primes (cons 2 (sieve (ints-from 3 1) primes)))</ |
(define primes (cons 2 (sieve (ints-from 3 1) primes)))</syntaxhighlight> |
||
Runs at ~ n^1.4 up to n=10,000. The initial 2 in the self-referential primes definition is needed to prevent a "black hole". |
Runs at ~ n^1.4 up to n=10,000. The initial 2 in the self-referential primes definition is needed to prevent a "black hole". |
||
Line 15,239: | Line 15,239: | ||
Since prime's multiples that matter start from its square, we should only add them when we reach that square. |
Since prime's multiples that matter start from its square, we should only add them when we reach that square. |
||
< |
<syntaxhighlight lang=Racket>(define (composites l q primes) |
||
(after q l |
(after q l |
||
(λ(t) |
(λ(t) |
||
Line 15,247: | Line 15,247: | ||
(define primes (cons 2 |
(define primes (cons 2 |
||
(diff (ints-from 3 1) |
(diff (ints-from 3 1) |
||
(composites (ints-from 4 2) 9 (cdr primes)))))</ |
(composites (ints-from 4 2) 9 (cdr primes)))))</syntaxhighlight> |
||
==== Implementation of Richard Bird's algorithm ==== |
==== Implementation of Richard Bird's algorithm ==== |
||
Line 15,253: | Line 15,253: | ||
Appears in [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf M.O'Neill's paper]. Achieves on its own the proper postponement that is specifically arranged for in the version above (with <code>after</code>), and is yet more efficient, because it folds to the right and so builds the right-leaning structure of merges at run time, where the more frequently-producing streams of multiples appear <i>higher</i> in that structure, so the composite numbers produced by them have less <code>merge</code> nodes to percolate through: |
Appears in [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf M.O'Neill's paper]. Achieves on its own the proper postponement that is specifically arranged for in the version above (with <code>after</code>), and is yet more efficient, because it folds to the right and so builds the right-leaning structure of merges at run time, where the more frequently-producing streams of multiples appear <i>higher</i> in that structure, so the composite numbers produced by them have less <code>merge</code> nodes to percolate through: |
||
< |
<syntaxhighlight lang=Racket>(define primes |
||
(cons 2 (diff (ints-from 3 1) |
(cons 2 (diff (ints-from 3 1) |
||
(foldr (λ(p r) (define q (* p p)) |
(foldr (λ(p r) (define q (* p p)) |
||
(cons q (union (ints-from (+ q p) p) r))) |
(cons q (union (ints-from (+ q p) p) r))) |
||
'() primes))))</ |
'() primes))))</syntaxhighlight> |
||
=== Using threads and channels === |
=== Using threads and channels === |
||
Line 15,263: | Line 15,263: | ||
Same algorithm as [[#With merged composites|"merged composites" above]] (without the postponement optimization), but now using threads and channels to produce a channel of all prime numbers (similar to newsqueak). The macro at the top is a convenient wrapper around definitions of channels using a thread that feeds them. |
Same algorithm as [[#With merged composites|"merged composites" above]] (without the postponement optimization), but now using threads and channels to produce a channel of all prime numbers (similar to newsqueak). The macro at the top is a convenient wrapper around definitions of channels using a thread that feeds them. |
||
< |
<syntaxhighlight lang=Racket>#lang racket |
||
(define-syntax (define-thread-loop stx) |
(define-syntax (define-thread-loop stx) |
||
(syntax-case stx () |
(syntax-case stx () |
||
Line 15,289: | Line 15,289: | ||
(out! x) (let loop () (out! (channel-get l)) (loop))) |
(out! x) (let loop () (out! (channel-get l)) (loop))) |
||
(define primes (cons 2 (sieve (ints-from 3 1) (ints-from 4 2)))) |
(define primes (cons 2 (sieve (ints-from 3 1) (ints-from 4 2)))) |
||
(for/list ([i 25] [x (in-producer channel-get eof primes)]) x)</ |
(for/list ([i 25] [x (in-producer channel-get eof primes)]) x)</syntaxhighlight> |
||
=== Using generators === |
=== Using generators === |
||
Line 15,295: | Line 15,295: | ||
Yet another variation of the same algorithm as above, this time using generators. |
Yet another variation of the same algorithm as above, this time using generators. |
||
< |
<syntaxhighlight lang=Racket>#lang racket |
||
(require racket/generator) |
(require racket/generator) |
||
(define (ints-from i d) |
(define (ints-from i d) |
||
Line 15,315: | Line 15,315: | ||
(define (cons x l) (generator () (yield x) (let loop () (yield (l)) (loop)))) |
(define (cons x l) (generator () (yield x) (let loop () (yield (l)) (loop)))) |
||
(define primes (cons 2 (sieve (ints-from 3 1) (ints-from 4 2)))) |
(define primes (cons 2 (sieve (ints-from 3 1) (ints-from 4 2)))) |
||
(for/list ([i 25] [x (in-producer primes)]) x)</ |
(for/list ([i 25] [x (in-producer primes)]) x)</syntaxhighlight> |
||
=={{header|Raku}}== |
=={{header|Raku}}== |
||
(formerly Perl 6) |
(formerly Perl 6) |
||
< |
<syntaxhighlight lang=perl6>sub sieve( Int $limit ) { |
||
my @is-prime = False, False, slip True xx $limit - 1; |
my @is-prime = False, False, slip True xx $limit - 1; |
||
Line 15,333: | Line 15,333: | ||
} |
} |
||
(sieve 100).join(",").say;</ |
(sieve 100).join(",").say;</syntaxhighlight> |
||
=== A set-based approach === |
=== A set-based approach === |
||
More or less the same as the first Python example: |
More or less the same as the first Python example: |
||
< |
<syntaxhighlight lang=perl6>sub eratsieve($n) { |
||
# Requires n(1 - 1/(log(n-1))) storage |
# Requires n(1 - 1/(log(n-1))) storage |
||
my $multiples = set(); |
my $multiples = set(); |
||
Line 15,349: | Line 15,349: | ||
} |
} |
||
say flat eratsieve(100);</ |
say flat eratsieve(100);</syntaxhighlight> |
||
This gives: |
This gives: |
||
Line 15,360: | Line 15,360: | ||
''Note: while this is "incorrect" by a strict interpretation of the rules, it is being left as an interesting example'' |
''Note: while this is "incorrect" by a strict interpretation of the rules, it is being left as an interesting example'' |
||
< |
<syntaxhighlight lang=perl6>sub primes ( UInt $n ) { |
||
gather { |
gather { |
||
# create an iterator from 2 to $n (inclusive) |
# create an iterator from 2 to $n (inclusive) |
||
Line 15,380: | Line 15,380: | ||
} |
} |
||
put primes( 100 );</ |
put primes( 100 );</syntaxhighlight> |
||
Which prints |
Which prints |
||
Line 15,386: | Line 15,386: | ||
=={{header|RATFOR}}== |
=={{header|RATFOR}}== |
||
< |
<syntaxhighlight lang=RATFOR> |
||
program prime |
program prime |
||
Line 15,435: | Line 15,435: | ||
end |
end |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Red}}== |
=={{header|Red}}== |
||
< |
<syntaxhighlight lang=Red> |
||
primes: function [n [integer!]][ |
primes: function [n [integer!]][ |
||
poke prim: make bitset! n 1 true |
poke prim: make bitset! n 1 true |
||
Line 15,450: | Line 15,450: | ||
primes 100 |
primes 100 |
||
== [2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97] |
== [2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97] |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
Line 15,458: | Line 15,458: | ||
As the stemmed array gets heavily populated, the number of entries ''may'' slow down the REXX interpreter substantially, |
As the stemmed array gets heavily populated, the number of entries ''may'' slow down the REXX interpreter substantially, |
||
<br>depending upon the efficacy of the hashing technique being used for REXX variables (setting/retrieving). |
<br>depending upon the efficacy of the hashing technique being used for REXX variables (setting/retrieving). |
||
< |
<syntaxhighlight lang=REXX>/*REXX program generates and displays primes via the sieve of Eratosthenes algorithm.*/ |
||
parse arg H .; if H=='' | H=="," then H= 200 /*optain optional argument from the CL.*/ |
parse arg H .; if H=='' | H=="," then H= 200 /*optain optional argument from the CL.*/ |
||
w= length(H); @prime= right('prime', 20) /*W: is used for aligning the output.*/ |
w= length(H); @prime= right('prime', 20) /*W: is used for aligning the output.*/ |
||
Line 15,469: | Line 15,469: | ||
end /*j*/ /* ─── */ |
end /*j*/ /* ─── */ |
||
say /*stick a fork in it, we're all done. */ |
say /*stick a fork in it, we're all done. */ |
||
say right(#, 1+w+length(@prime) ) 'primes found up to and including ' H</ |
say right(#, 1+w+length(@prime) ) 'primes found up to and including ' H</syntaxhighlight> |
||
'''output''' when using the input default of: <tt> 200 </tt> |
'''output''' when using the input default of: <tt> 200 </tt> |
||
<pre style="height:45ex"> |
<pre style="height:45ex"> |
||
Line 15,528: | Line 15,528: | ||
Also added is a final message indicating the number of primes found. |
Also added is a final message indicating the number of primes found. |
||
< |
<syntaxhighlight lang=rexx>/*REXX program generates primes via a wheeled sieve of Eratosthenes algorithm. */ |
||
parse arg H .; if H=='' then H=200 /*let the highest number be specified. */ |
parse arg H .; if H=='' then H=200 /*let the highest number be specified. */ |
||
tell=h>0; H=abs(H); w=length(H) /*a negative H suppresses prime listing*/ |
tell=h>0; H=abs(H); w=length(H) /*a negative H suppresses prime listing*/ |
||
Line 15,551: | Line 15,551: | ||
.: parse arg n; b=n%cw; r=n//cw+1;_=x2b(c2x(@.b));@.b=x2c(b2x(left(_,r-1)'1'substr(_,r+1)));return |
.: parse arg n; b=n%cw; r=n//cw+1;_=x2b(c2x(@.b));@.b=x2c(b2x(left(_,r-1)'1'substr(_,r+1)));return |
||
s: if arg(1)==1 then return arg(3); return word(arg(2) 's',1) /*pluralizer.*/ |
s: if arg(1)==1 then return arg(3); return word(arg(2) 's',1) /*pluralizer.*/ |
||
th: procedure; parse arg x; x=abs(x); return word('th st nd rd',1+x//10*(x//100%10\==1)*(x//10<4))</ |
th: procedure; parse arg x; x=abs(x); return word('th st nd rd',1+x//10*(x//100%10\==1)*(x//10<4))</syntaxhighlight> |
||
{{out|output|text= when using the input default of: <tt> 200 </tt>}} |
{{out|output|text= when using the input default of: <tt> 200 </tt>}} |
||
<pre style="height:45ex"> |
<pre style="height:45ex"> |
||
Line 15,629: | Line 15,629: | ||
It also uses a short-circuit test for striking out composites ≤ √{{overline| target }} |
It also uses a short-circuit test for striking out composites ≤ √{{overline| target }} |
||
< |
<syntaxhighlight lang=rexx>/*REXX pgm generates and displays primes via a wheeled sieve of Eratosthenes algorithm. */ |
||
parse arg H .; if H=='' | H=="," then H= 200 /*obtain the optional argument from CL.*/ |
parse arg H .; if H=='' | H=="," then H= 200 /*obtain the optional argument from CL.*/ |
||
w= length(H); @prime= right('prime', 20) /*w: is used for aligning the output. */ |
w= length(H); @prime= right('prime', 20) /*w: is used for aligning the output. */ |
||
Line 15,644: | Line 15,644: | ||
end /*j*/ /* ─── */ |
end /*j*/ /* ─── */ |
||
say /*stick a fork in it, we're all done. */ |
say /*stick a fork in it, we're all done. */ |
||
say right(#, 1 + w + length(@prime) ) 'primes found up to and including ' H</ |
say right(#, 1 + w + length(@prime) ) 'primes found up to and including ' H</syntaxhighlight> |
||
{{out|output|text= is identical to the first (non-wheel) version; program execution is over ''twice'' as fast.}} |
{{out|output|text= is identical to the first (non-wheel) version; program execution is over ''twice'' as fast.}} |
||
Line 15,650: | Line 15,650: | ||
===Wheel Version restructured=== |
===Wheel Version restructured=== |
||
< |
<syntaxhighlight lang=rexx>/*REXX program generates primes via sieve of Eratosthenes algorithm. |
||
* 21.07.2012 Walter Pachl derived from above Rexx version |
* 21.07.2012 Walter Pachl derived from above Rexx version |
||
* avoid symbols @ and # (not supported by ooRexx) |
* avoid symbols @ and # (not supported by ooRexx) |
||
Line 15,678: | Line 15,678: | ||
np=np+1 |
np=np+1 |
||
Say ' prime number' right(np,w) " --> " right(prime,w) |
Say ' prime number' right(np,w) " --> " right(prime,w) |
||
Return</ |
Return</syntaxhighlight> |
||
'''output''' is mostly identical to the above versions. |
'''output''' is mostly identical to the above versions. |
||
=={{header|Ring}}== |
=={{header|Ring}}== |
||
< |
<syntaxhighlight lang=ring> |
||
limit = 100 |
limit = 100 |
||
sieve = list(limit) |
sieve = list(limit) |
||
Line 15,691: | Line 15,691: | ||
if sieve[i] = 0 see "" + i + " " ok |
if sieve[i] = 0 see "" + i + " " ok |
||
next |
next |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 15,699: | Line 15,699: | ||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
''eratosthenes'' starts with <code>nums = [nil, nil, 2, 3, 4, 5, ..., n]</code>, then marks ( the nil setting ) multiples of <code>2, 3, 5, 7, ...</code> there, then returns all non-nil numbers which are the primes. |
''eratosthenes'' starts with <code>nums = [nil, nil, 2, 3, 4, 5, ..., n]</code>, then marks ( the nil setting ) multiples of <code>2, 3, 5, 7, ...</code> there, then returns all non-nil numbers which are the primes. |
||
< |
<syntaxhighlight lang=ruby>def eratosthenes(n) |
||
nums = [nil, nil, *2..n] |
nums = [nil, nil, *2..n] |
||
(2..Math.sqrt(n)).each do |i| |
(2..Math.sqrt(n)).each do |i| |
||
Line 15,707: | Line 15,707: | ||
end |
end |
||
p eratosthenes(100)</ |
p eratosthenes(100)</syntaxhighlight> |
||
<pre>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]</pre> |
<pre>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]</pre> |
||
Line 15,718: | Line 15,718: | ||
* Both inner loops skip multiples of 2 and 3. |
* Both inner loops skip multiples of 2 and 3. |
||
< |
<syntaxhighlight lang=ruby>def eratosthenes2(n) |
||
# For odd i, if i is prime, nums[i >> 1] is true. |
# For odd i, if i is prime, nums[i >> 1] is true. |
||
# Set false for all multiples of 3. |
# Set false for all multiples of 3. |
||
Line 15,760: | Line 15,760: | ||
end |
end |
||
p eratosthenes2(100)</ |
p eratosthenes2(100)</syntaxhighlight> |
||
This simple benchmark compares ''eratosthenes'' with ''eratosthenes2''. |
This simple benchmark compares ''eratosthenes'' with ''eratosthenes2''. |
||
< |
<syntaxhighlight lang=ruby>require 'benchmark' |
||
Benchmark.bmbm {|x| |
Benchmark.bmbm {|x| |
||
x.report("eratosthenes") { eratosthenes(1_000_000) } |
x.report("eratosthenes") { eratosthenes(1_000_000) } |
||
x.report("eratosthenes2") { eratosthenes2(1_000_000) } |
x.report("eratosthenes2") { eratosthenes2(1_000_000) } |
||
}</ |
}</syntaxhighlight> |
||
''eratosthenes2'' runs about 4 times faster than ''eratosthenes''. |
''eratosthenes2'' runs about 4 times faster than ''eratosthenes''. |
||
Line 15,775: | Line 15,775: | ||
[[MRI]] 1.9.x implements the sieve of Eratosthenes at file [http://redmine.ruby-lang.org/projects/ruby-19/repository/entry/lib/prime.rb prime.rb], <code>class EratosthensesSeive</code> (around [http://redmine.ruby-lang.org/projects/ruby-19/repository/entry/lib/prime.rb#L421 line 421]). This implementation optimizes for space, by packing the booleans into 16-bit integers. It also hardcodes all primes less than 256. |
[[MRI]] 1.9.x implements the sieve of Eratosthenes at file [http://redmine.ruby-lang.org/projects/ruby-19/repository/entry/lib/prime.rb prime.rb], <code>class EratosthensesSeive</code> (around [http://redmine.ruby-lang.org/projects/ruby-19/repository/entry/lib/prime.rb#L421 line 421]). This implementation optimizes for space, by packing the booleans into 16-bit integers. It also hardcodes all primes less than 256. |
||
< |
<syntaxhighlight lang=ruby>require 'prime' |
||
p Prime::EratosthenesGenerator.new.take_while {|i| i <= 100}</ |
p Prime::EratosthenesGenerator.new.take_while {|i| i <= 100}</syntaxhighlight> |
||
=={{header|Run BASIC}}== |
=={{header|Run BASIC}}== |
||
< |
<syntaxhighlight lang=runbasic>input "Gimme the limit:"; limit |
||
dim flags(limit) |
dim flags(limit) |
||
for i = 2 to limit |
for i = 2 to limit |
||
Line 15,786: | Line 15,786: | ||
next k |
next k |
||
if flags(i) = 0 then print i;", "; |
if flags(i) = 0 then print i;", "; |
||
next i</ |
next i</syntaxhighlight> |
||
<pre>Gimme the limit:?100 |
<pre>Gimme the limit:?100 |
||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, </pre> |
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, </pre> |
||
Line 15,797: | Line 15,797: | ||
A slightly more idiomatic, optimized and modern iterator output example. |
A slightly more idiomatic, optimized and modern iterator output example. |
||
< |
<syntaxhighlight lang=rust>fn primes(n: usize) -> impl Iterator<Item = usize> { |
||
const START: usize = 2; |
const START: usize = 2; |
||
if n < START { |
if n < START { |
||
Line 15,815: | Line 15,815: | ||
.enumerate() |
.enumerate() |
||
.filter_map(|(e, b)| if b { Some(e + START) } else { None }) |
.filter_map(|(e, b)| if b { Some(e + START) } else { None }) |
||
}</ |
}</syntaxhighlight> |
||
Notes: |
Notes: |
||
Line 15,825: | Line 15,825: | ||
===Sieve of Eratosthenes - No optimization=== |
===Sieve of Eratosthenes - No optimization=== |
||
< |
<syntaxhighlight lang=rust>fn simple_sieve(limit: usize) -> Vec<usize> { |
||
let mut is_prime = vec![true; limit+1]; |
let mut is_prime = vec![true; limit+1]; |
||
Line 15,848: | Line 15,848: | ||
fn main() { |
fn main() { |
||
println!("{:?}", simple_sieve(100)); |
println!("{:?}", simple_sieve(100)); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]</pre> |
<pre>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]</pre> |
||
Line 15,856: | Line 15,856: | ||
The above code doesn't even do the basic optimizing of only culling composites by primes up to the square root of the range as allowed in the task; it also outputs a vector of resulting primes, which consumes memory. The following code fixes both of those, outputting the results as an Iterator: |
The above code doesn't even do the basic optimizing of only culling composites by primes up to the square root of the range as allowed in the task; it also outputs a vector of resulting primes, which consumes memory. The following code fixes both of those, outputting the results as an Iterator: |
||
< |
<syntaxhighlight lang=rust>use std::iter::{empty, once}; |
||
use std::time::Instant; |
use std::time::Instant; |
||
Line 15,900: | Line 15,900: | ||
let dur = secs * 1000 + millis; |
let dur = secs * 1000 + millis; |
||
println!("Culling composites took {} milliseconds.", dur); |
println!("Culling composites took {} milliseconds.", dur); |
||
}</ |
}</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] |
<pre>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] |
||
Line 15,912: | Line 15,912: | ||
The following code improves the above code by sieving only odd composite numbers as 2 is the only even prime for a reduction in number of operations by a factor of about two and a half with reduction of memory use by a factor of two, and bit-packs the composite sieving array for a further reduction of memory use by a factor of eight and with some saving in time due to better CPU cache use for a given sieving range; it also demonstrates how to eliminate the redundant array bounds check: |
The following code improves the above code by sieving only odd composite numbers as 2 is the only even prime for a reduction in number of operations by a factor of about two and a half with reduction of memory use by a factor of two, and bit-packs the composite sieving array for a further reduction of memory use by a factor of eight and with some saving in time due to better CPU cache use for a given sieving range; it also demonstrates how to eliminate the redundant array bounds check: |
||
< |
<syntaxhighlight lang=rust>fn optimized_sieve(limit: usize) -> Box<Iterator<Item = usize>> { |
||
if limit < 3 { |
if limit < 3 { |
||
return if limit < 2 { Box::new(empty()) } else { Box::new(once(2)) } |
return if limit < 2 { Box::new(empty()) } else { Box::new(once(2)) } |
||
Line 15,942: | Line 15,942: | ||
Some((i + i + 3) as usize) } else { None } } |
Some((i + i + 3) as usize) } else { None } } |
||
})) |
})) |
||
}</ |
}</syntaxhighlight> |
||
The above function can be used just by substituting "optimized_sieve" for "basic_sieve" in the previous "main" function, and the outputs are the same except that the time is only 1584 milliseconds, or about three times as fast. |
The above function can be used just by substituting "optimized_sieve" for "basic_sieve" in the previous "main" function, and the outputs are the same except that the time is only 1584 milliseconds, or about three times as fast. |
||
Line 15,952: | Line 15,952: | ||
While that above code is quite fast, as the range increases above the 10's of millions it begins to lose efficiency due to loss of CPU cache associativity as the size of the one-large-array used for culling composites grows beyond the limits of the various CPU caches. Accordingly the following page-segmented code where each culling page can be limited to not larger than the L1 CPU cache is about four times faster than the above for the range of one billion: |
While that above code is quite fast, as the range increases above the 10's of millions it begins to lose efficiency due to loss of CPU cache associativity as the size of the one-large-array used for culling composites grows beyond the limits of the various CPU caches. Accordingly the following page-segmented code where each culling page can be limited to not larger than the L1 CPU cache is about four times faster than the above for the range of one billion: |
||
< |
<syntaxhighlight lang=rust>use std::iter::{empty, once}; |
||
use std::rc::Rc; |
use std::rc::Rc; |
||
use std::cell::RefCell; |
use std::cell::RefCell; |
||
Line 16,126: | Line 16,126: | ||
let dur = secs * 1000 + millis; |
let dur = secs * 1000 + millis; |
||
println!("Culling composites took {} milliseconds.", dur); |
println!("Culling composites took {} milliseconds.", dur); |
||
}</ |
}</syntaxhighlight> |
||
The output is about the same as the previous codes except much faster; as well as cache size improvements mentioned above, it has a population count primes counting function that is able to determine the number of found primes about twice as fast as using the Iterator count() method (commented out and labelled as "the slow way" in the main function). |
The output is about the same as the previous codes except much faster; as well as cache size improvements mentioned above, it has a population count primes counting function that is able to determine the number of found primes about twice as fast as using the Iterator count() method (commented out and labelled as "the slow way" in the main function). |
||
Line 16,139: | Line 16,139: | ||
=={{header|S-BASIC}}== |
=={{header|S-BASIC}}== |
||
< |
<syntaxhighlight lang=basic> |
||
comment |
comment |
||
Find primes up to the specified limit (here 1,000) using |
Find primes up to the specified limit (here 1,000) using |
||
Line 16,187: | Line 16,187: | ||
end |
end |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 16,218: | Line 16,218: | ||
append from a; |
append from a; |
||
close primes; |
close primes; |
||
quit;</ |
quit;</syntaxhighlight> |
||
=={{header|SASL}}== |
=={{header|SASL}}== |
||
{{incorrect|SASL|These use REM (division) testing and so are Trial Division algorithms, not Sieve of Eratosthenes.}} |
{{incorrect|SASL|These use REM (division) testing and so are Trial Division algorithms, not Sieve of Eratosthenes.}} |
||
Copied from SASL manual, top of page 36. This provides an infinite list. |
Copied from SASL manual, top of page 36. This provides an infinite list. |
||
< |
<syntaxhighlight lang=SASL> |
||
show primes |
show primes |
||
WHERE |
WHERE |
||
Line 16,229: | Line 16,229: | ||
sieve (p : x ) = p : sieve {a <- x; a REM p > 0} |
sieve (p : x ) = p : sieve {a <- x; a REM p > 0} |
||
? |
? |
||
</syntaxhighlight> |
|||
</lang> |
|||
The limited list for the first 1000 numbers |
The limited list for the first 1000 numbers |
||
< |
<syntaxhighlight lang=SASL> |
||
show primes |
show primes |
||
WHERE |
WHERE |
||
Line 16,238: | Line 16,238: | ||
sieve (p : x ) = p : sieve {a <- x; a REM p > 0} |
sieve (p : x ) = p : sieve {a <- x; a REM p > 0} |
||
? |
? |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Scala}}== |
=={{header|Scala}}== |
||
=== Genuine Eratosthenes sieve=== |
=== Genuine Eratosthenes sieve=== |
||
< |
<syntaxhighlight lang=Scala>import scala.annotation.tailrec |
||
import scala.collection.parallel.mutable |
import scala.collection.parallel.mutable |
||
import scala.compat.Platform |
import scala.compat.Platform |
||
Line 16,264: | Line 16,264: | ||
assert(sieveOfEratosthenes(15099480).size == 976729) |
assert(sieveOfEratosthenes(15099480).size == 976729) |
||
println(s"Successfully completed without errors. [total ${Platform.currentTime - executionStart} ms]") |
println(s"Successfully completed without errors. [total ${Platform.currentTime - executionStart} ms]") |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 16,275: | Line 16,275: | ||
The following [['''odds-only''']] code is written in a very concise functional style (no mutable state other than the contents of the composites buffer and "higher order functions" for clarity), in this case using a Scala mutable BitSet: |
The following [['''odds-only''']] code is written in a very concise functional style (no mutable state other than the contents of the composites buffer and "higher order functions" for clarity), in this case using a Scala mutable BitSet: |
||
< |
<syntaxhighlight lang=Scala>object SoEwithBitSet { |
||
def makeSoE_PrimesTo(top: Int): Iterator[Int] = { |
def makeSoE_PrimesTo(top: Int): Iterator[Int] = { |
||
val topNdx = (top - 3) / 2 //odds composite BitSet buffer offset down to 3 |
val topNdx = (top - 3) / 2 //odds composite BitSet buffer offset down to 3 |
||
Line 16,283: | Line 16,283: | ||
(0 to (Math.sqrt(top).toInt - 3) / 2).filterNot { cmpsts }.foreach { cullPrmCmpsts } |
(0 to (Math.sqrt(top).toInt - 3) / 2).filterNot { cmpsts }.foreach { cullPrmCmpsts } |
||
Iterator.single(2) ++ (0 to topNdx).filterNot { cmpsts }.map { pi => pi + pi + 3 } } |
Iterator.single(2) ++ (0 to topNdx).filterNot { cmpsts }.map { pi => pi + pi + 3 } } |
||
}</ |
}</syntaxhighlight> |
||
In spite of being very concise, it is very much faster than the above code converted to odds-only due to the use of the BitSet instead of the hash table based Set (or ParSet), taking only a few seconds to enumerate the primes to 100 million as compared to the 10's of seconds to count the primes to above 15 million above. |
In spite of being very concise, it is very much faster than the above code converted to odds-only due to the use of the BitSet instead of the hash table based Set (or ParSet), taking only a few seconds to enumerate the primes to 100 million as compared to the 10's of seconds to count the primes to above 15 million above. |
||
Line 16,290: | Line 16,290: | ||
The below [['''odds-only''']] code using a primitive array (bit packed) and tail recursion to avoid some of the enumeration delays due to nested complex "higher order" function calls is almost eight times faster than the above more functional code: |
The below [['''odds-only''']] code using a primitive array (bit packed) and tail recursion to avoid some of the enumeration delays due to nested complex "higher order" function calls is almost eight times faster than the above more functional code: |
||
< |
<syntaxhighlight lang=Scala>object SoEwithArray { |
||
def makeSoE_PrimesTo(top: Int) = { |
def makeSoE_PrimesTo(top: Int) = { |
||
import scala.annotation.tailrec |
import scala.annotation.tailrec |
||
Line 16,317: | Line 16,317: | ||
Iterator.single(2) ++ Iterator.iterate(3)(p => getNxtPrmFrom(((p + 2) - 3) >>> 1)).takeWhile(_ <= top) |
Iterator.single(2) ++ Iterator.iterate(3)(p => getNxtPrmFrom(((p + 2) - 3) >>> 1)).takeWhile(_ <= top) |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
It can be tested with the following code: |
It can be tested with the following code: |
||
< |
<syntaxhighlight lang=Scala>object Main extends App { |
||
import SoEwithArray._ |
import SoEwithArray._ |
||
val top_num = 100000000 |
val top_num = 100000000 |
||
Line 16,330: | Line 16,330: | ||
println(f"Found $count primes up to $top_num" + ".") |
println(f"Found $count primes up to $top_num" + ".") |
||
println("Using one large mutable Array and tail recursive loops.") |
println("Using one large mutable Array and tail recursive loops.") |
||
}</ |
}</syntaxhighlight> |
||
To produce the following output: |
To produce the following output: |
||
Line 16,342: | Line 16,342: | ||
The above code still uses an amount of memory proportional to the range of the sieve (although bit-packed as 8 values per byte). As well as only sieving odd candidates, the following code uses a fixed range buffer that is about the size of the CPU L2 cache plus only storage for the base primes up to the square root of the range for a large potential saving in RAM memory used as well as greatly reducing memory access times. The use of innermost tail recursive loops for critical loops where the majority of the execution time is spent rather than "higher order" functions from iterators also greatly reduces execution time, with much of the remaining time used just to enumerate the primes output: |
The above code still uses an amount of memory proportional to the range of the sieve (although bit-packed as 8 values per byte). As well as only sieving odd candidates, the following code uses a fixed range buffer that is about the size of the CPU L2 cache plus only storage for the base primes up to the square root of the range for a large potential saving in RAM memory used as well as greatly reducing memory access times. The use of innermost tail recursive loops for critical loops where the majority of the execution time is spent rather than "higher order" functions from iterators also greatly reduces execution time, with much of the remaining time used just to enumerate the primes output: |
||
< |
<syntaxhighlight lang=Scala>object APFSoEPagedOdds { |
||
import scala.annotation.tailrec |
import scala.annotation.tailrec |
||
Line 16,433: | Line 16,433: | ||
val (cnt, nlwp) = gen.next(); val nacc = acc + cnt |
val (cnt, nlwp) = gen.next(); val nacc = acc + cnt |
||
if (nlwp <= top) takeUpto(nacc) else nacc }; takeUpto(1) } |
if (nlwp <= top) takeUpto(nacc) else nacc }; takeUpto(1) } |
||
}</ |
}</syntaxhighlight> |
||
As the above and all following sieves are "infinite", they all require an extra range limiting condition to produce a finite output, such as the addition of ".takeWhile(_ <= topLimit)" where "topLimit" is the specified range as is done in the following code: |
As the above and all following sieves are "infinite", they all require an extra range limiting condition to produce a finite output, such as the addition of ".takeWhile(_ <= topLimit)" where "topLimit" is the specified range as is done in the following code: |
||
< |
<syntaxhighlight lang=Scala>object MainSoEPagedOdds extends App { |
||
import APFSoEPagedOdds._ |
import APFSoEPagedOdds._ |
||
countSoEPrimesTo(100) |
countSoEPrimesTo(100) |
||
Line 16,446: | Line 16,446: | ||
val elpsd = System.currentTimeMillis() - strt |
val elpsd = System.currentTimeMillis() - strt |
||
println(f"Found $cnt primes up to $top in $elpsd milliseconds.") |
println(f"Found $cnt primes up to $top in $elpsd milliseconds.") |
||
}</ |
}</syntaxhighlight> |
||
which outputs the following: |
which outputs the following: |
||
Line 16,463: | Line 16,463: | ||
The following code uses delayed recursion via Streams to implement the Richard Bird algorithm mentioned in the last part (the Epilogue) of [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf M.O'Neill's paper], which is '''a true incremental Sieve of Eratosthenes'''. It is nowhere near as fast as the array based solutions due to the overhead of functionally chasing the merging of the prime multiple streams; this also means that the empirical performance is not according to the usual Sieve of Eratosthenes approximations due to this overhead increasing as the log of the sieved range, but it is much better than [[Primality_by_trial_division#Odds-Only_.22infinite.22_primes_generator_using_Streams_and_Co-Inductive_Streams|the "unfaithful" sieve]]. |
The following code uses delayed recursion via Streams to implement the Richard Bird algorithm mentioned in the last part (the Epilogue) of [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf M.O'Neill's paper], which is '''a true incremental Sieve of Eratosthenes'''. It is nowhere near as fast as the array based solutions due to the overhead of functionally chasing the merging of the prime multiple streams; this also means that the empirical performance is not according to the usual Sieve of Eratosthenes approximations due to this overhead increasing as the log of the sieved range, but it is much better than [[Primality_by_trial_division#Odds-Only_.22infinite.22_primes_generator_using_Streams_and_Co-Inductive_Streams|the "unfaithful" sieve]]. |
||
< |
<syntaxhighlight lang=Scala> def birdPrimes() = { |
||
def oddPrimes: Stream[Int] = { |
def oddPrimes: Stream[Int] = { |
||
def merge(xs: Stream[Int], ys: Stream[Int]): Stream[Int] = { |
def merge(xs: Stream[Int], ys: Stream[Int]): Stream[Int] = { |
||
Line 16,484: | Line 16,484: | ||
} |
} |
||
2 #:: oddPrimes |
2 #:: oddPrimes |
||
}</ |
}</syntaxhighlight> |
||
Now this algorithm doesn't really need the memoization and full laziness as offered by Streams, so an implementation and use of a Co-Inductive Stream (CIS) class is sufficient and reduces execution time by almost a factor of two:< |
Now this algorithm doesn't really need the memoization and full laziness as offered by Streams, so an implementation and use of a Co-Inductive Stream (CIS) class is sufficient and reduces execution time by almost a factor of two:<syntaxhighlight lang=scala> class CIS[A](val start: A, val continue: () => CIS[A]) |
||
def primesBirdCIS: Iterator[Int] = { |
def primesBirdCIS: Iterator[Int] = { |
||
Line 16,518: | Line 16,518: | ||
Iterator.single(2) ++ Iterator.iterate(oddPrimes())(_.continue()).map(_.start) |
Iterator.single(2) ++ Iterator.iterate(oddPrimes())(_.continue()).map(_.start) |
||
}</ |
}</syntaxhighlight> |
||
Further gains in performance for these last two implementations can be had by using further wheel factorization and "tree folding/merging" as per [http://www.haskell.org/haskellwiki/Primes#Tree_merging_with_Wheel this Haskell implementation]. |
Further gains in performance for these last two implementations can be had by using further wheel factorization and "tree folding/merging" as per [http://www.haskell.org/haskellwiki/Primes#Tree_merging_with_Wheel this Haskell implementation]. |
||
Line 16,525: | Line 16,525: | ||
As per [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf the "unfaithful sieve" article linked above], the incremental "infinite" Sieve of Eratosthenes can be implemented using a hash table instead of a Priority Queue or Map (Binary Heap) as were used in that article. The following implementation postpones the adding of base prime representations to the hash table until necessary to keep the hash table small: |
As per [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf the "unfaithful sieve" article linked above], the incremental "infinite" Sieve of Eratosthenes can be implemented using a hash table instead of a Priority Queue or Map (Binary Heap) as were used in that article. The following implementation postpones the adding of base prime representations to the hash table until necessary to keep the hash table small: |
||
< |
<syntaxhighlight lang=scala> def SoEInc: Iterator[Int] = { |
||
val nextComposites = scala.collection.mutable.HashMap[Int, Int]() |
val nextComposites = scala.collection.mutable.HashMap[Int, Int]() |
||
def oddPrimes: Iterator[Int] = { |
def oddPrimes: Iterator[Int] = { |
||
Line 16,549: | Line 16,549: | ||
} |
} |
||
List(2, 3).toIterator ++ oddPrimes |
List(2, 3).toIterator ++ oddPrimes |
||
}</ |
}</syntaxhighlight> |
||
The above could be implemented using Streams or Co-Inductive Streams to pass the continuation parameters as passed here in a tuple but there would be no real difference in speed and there is no need to use the implied laziness. As compared to the versions of the Bird (or tree folding) Sieve of Eratosthenes, this has the expected same computational complexity as the array based versions, but is about 20 times slower due to the constant overhead of processing the key value hashing. Memory use is quite low, only being the hash table entries for each of the base prime values less than the square root of the last prime enumerated multiplied by the size of each hash entry (about 12 bytes in this case) plus a "load factor" percentage overhead in hash table size to minimize hash collisions (about twice as large as entries actually used by default on average). |
The above could be implemented using Streams or Co-Inductive Streams to pass the continuation parameters as passed here in a tuple but there would be no real difference in speed and there is no need to use the implied laziness. As compared to the versions of the Bird (or tree folding) Sieve of Eratosthenes, this has the expected same computational complexity as the array based versions, but is about 20 times slower due to the constant overhead of processing the key value hashing. Memory use is quite low, only being the hash table entries for each of the base prime values less than the square root of the last prime enumerated multiplied by the size of each hash entry (about 12 bytes in this case) plus a "load factor" percentage overhead in hash table size to minimize hash collisions (about twice as large as entries actually used by default on average). |
||
Line 16,560: | Line 16,560: | ||
===Tail-recursive solution=== |
===Tail-recursive solution=== |
||
{{Works with|Scheme|R<math>^5</math>RS}} |
{{Works with|Scheme|R<math>^5</math>RS}} |
||
< |
<syntaxhighlight lang=scheme>; Tail-recursive solution : |
||
(define (sieve n) |
(define (sieve n) |
||
(define (aux u v) |
(define (aux u v) |
||
Line 16,580: | Line 16,580: | ||
; (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97) |
; (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97) |
||
; > (length (sieve 10000000)) |
; > (length (sieve 10000000)) |
||
; 664579</ |
; 664579</syntaxhighlight> |
||
===Simpler, non-tail-recursive solution=== |
===Simpler, non-tail-recursive solution=== |
||
< |
<syntaxhighlight lang=scheme>; Simpler solution, with the penalty that none of 'iota, 'strike or 'sieve is tail-recursive : |
||
(define (iota start stop stride) |
(define (iota start stop stride) |
||
(if (> start stop) |
(if (> start stop) |
||
Line 16,605: | Line 16,605: | ||
(display (primes 100)) |
(display (primes 100)) |
||
(newline)</ |
(newline)</syntaxhighlight> |
||
Output: |
Output: |
||
<lang>(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)</ |
<lang>(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)</syntaxhighlight> |
||
===Optimised using an odds-wheel=== |
===Optimised using an odds-wheel=== |
||
Optimised using a pre-computed wheel based on 2 (i.e. odds only): |
Optimised using a pre-computed wheel based on 2 (i.e. odds only): |
||
< |
<syntaxhighlight lang=scheme>(define (primes-wheel-2 limit) |
||
(let ((stop (sqrt limit))) |
(let ((stop (sqrt limit))) |
||
(define (sieve lst) |
(define (sieve lst) |
||
Line 16,620: | Line 16,620: | ||
(display (primes-wheel-2 100)) |
(display (primes-wheel-2 100)) |
||
(newline)</ |
(newline)</syntaxhighlight> |
||
Output: |
Output: |
||
<lang>(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)</ |
<lang>(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)</syntaxhighlight> |
||
===Vector-based=== |
===Vector-based=== |
||
Vector-based (faster), works with R<math>^5</math>RS: |
Vector-based (faster), works with R<math>^5</math>RS: |
||
< |
<syntaxhighlight lang=scheme>; initialize v to vector of sequential integers |
||
(define (initialize! v) |
(define (initialize! v) |
||
(define (iter v n) (if (>= n (vector-length v)) |
(define (iter v n) (if (>= n (vector-length v)) |
||
Line 16,668: | Line 16,668: | ||
(initialize! v) |
(initialize! v) |
||
(vector-set! v 1 0) ; 1 is not a prime |
(vector-set! v 1 0) ; 1 is not a prime |
||
(remove zero? (vector->list (iter v 2)))))</ |
(remove zero? (vector->list (iter v 2)))))</syntaxhighlight> |
||
===SICP-style streams=== |
===SICP-style streams=== |
||
Using SICP-style ''head''-forced streams. Works with MIT-Scheme, Chez Scheme, – or any other Scheme, if writing out by hand the expansion of the only macro here, <code>s-cons</code>, with explicit lambda. Common functions: |
Using SICP-style ''head''-forced streams. Works with MIT-Scheme, Chez Scheme, – or any other Scheme, if writing out by hand the expansion of the only macro here, <code>s-cons</code>, with explicit lambda. Common functions: |
||
< |
<syntaxhighlight lang=scheme> ;;;; Stream Implementation |
||
(define (head s) (car s)) |
(define (head s) (car s)) |
||
(define (tail s) ((cdr s))) |
(define (tail s) ((cdr s))) |
||
Line 16,704: | Line 16,704: | ||
((< h1 h2) (s-cons h1 (s-union (tail s1) s2 ))) |
((< h1 h2) (s-cons h1 (s-union (tail s1) s2 ))) |
||
((< h2 h1) (s-cons h2 (s-union s1 (tail s2)))) |
((< h2 h1) (s-cons h2 (s-union s1 (tail s2)))) |
||
(else (s-cons h1 (s-union (tail s1) (tail s2)))))))</ |
(else (s-cons h1 (s-union (tail s1) (tail s2)))))))</syntaxhighlight> |
||
====The simplest, naive sieve==== |
====The simplest, naive sieve==== |
||
Very slow, running at ~ <i>n<sup>2.2</sup></i>, empirically, and worsening: |
Very slow, running at ~ <i>n<sup>2.2</sup></i>, empirically, and worsening: |
||
< |
<syntaxhighlight lang=scheme> (define (sieve s) |
||
(let ((p (head s))) |
(let ((p (head s))) |
||
(s-cons p |
(s-cons p |
||
(sieve (s-diff s (from-By p p)))))) |
(sieve (s-diff s (from-By p p)))))) |
||
(define primes (sieve (from-By 2 1)))</ |
(define primes (sieve (from-By 2 1)))</syntaxhighlight> |
||
====Bounded, stopping early==== |
====Bounded, stopping early==== |
||
Stops at the square root of the upper limit ''m'', running at about ~ <i>n<sup>1.4</sup></i> in ''n'' primes produced, empirically. Returns infinite stream |
Stops at the square root of the upper limit ''m'', running at about ~ <i>n<sup>1.4</sup></i> in ''n'' primes produced, empirically. Returns infinite stream |
||
of numbers which is only valid up to ''m'', includes composites above it: |
of numbers which is only valid up to ''m'', includes composites above it: |
||
< |
<syntaxhighlight lang=scheme> (define (primes-To m) |
||
(define (sieve s) |
(define (sieve s) |
||
(let ((p (head s))) |
(let ((p (head s))) |
||
Line 16,724: | Line 16,724: | ||
(sieve (s-diff (tail s) |
(sieve (s-diff (tail s) |
||
(from-By (* p p) p)))))))) |
(from-By (* p p) p)))))))) |
||
(sieve (from-By 2 1)))</ |
(sieve (from-By 2 1)))</syntaxhighlight> |
||
====Combined multiples sieve==== |
====Combined multiples sieve==== |
||
Archetypal, straightforward approach by Richard Bird, presented in [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf Melissa E. O'Neill article]. Uses <code>s-linear-join</code>, i.e. right fold, which is less efficient and of worse time complexity than the ''tree''-folding that follows. Does not attempt to conserve space by arranging for the additional inner feedback loop, as is done in the tree-folding variant below. |
Archetypal, straightforward approach by Richard Bird, presented in [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf Melissa E. O'Neill article]. Uses <code>s-linear-join</code>, i.e. right fold, which is less efficient and of worse time complexity than the ''tree''-folding that follows. Does not attempt to conserve space by arranging for the additional inner feedback loop, as is done in the tree-folding variant below. |
||
< |
<syntaxhighlight lang=scheme> (define (primes-stream-ala-Bird) |
||
(define (mults p) (from-By (* p p) p)) |
(define (mults p) (from-By (* p p) p)) |
||
(define primes ;; primes are |
(define primes ;; primes are |
||
Line 16,739: | Line 16,739: | ||
(s-cons (head (head sts)) |
(s-cons (head (head sts)) |
||
(s-union (tail (head sts)) |
(s-union (tail (head sts)) |
||
(s-linear-join (tail sts)))))</ |
(s-linear-join (tail sts)))))</syntaxhighlight> |
||
Here is a version of the same sieve, which is self contained with all the requisite functions wrapped in the overall function; optimized further. It works with odd primes only, and arranges for a separate primes feed for the base primes separate from the output stream, ''calculated recursively'' by the recursive call to "oddprms" in forming "cmpsts". It also ''"fuses"'' two functions, <code>s-diff</code> and <code>from-By</code>, into one, <code>minusstrtat</code>: |
Here is a version of the same sieve, which is self contained with all the requisite functions wrapped in the overall function; optimized further. It works with odd primes only, and arranges for a separate primes feed for the base primes separate from the output stream, ''calculated recursively'' by the recursive call to "oddprms" in forming "cmpsts". It also ''"fuses"'' two functions, <code>s-diff</code> and <code>from-By</code>, into one, <code>minusstrtat</code>: |
||
< |
<syntaxhighlight lang=scheme>(define (birdPrimes) |
||
(define (mltpls p) |
(define (mltpls p) |
||
(define pm2 (* p 2)) |
(define pm2 (* p 2)) |
||
Line 16,765: | Line 16,765: | ||
(define (cmpsts) (mrgmltpls (allmltpls (oddprms)))) ;; internal define's are mutually recursive |
(define (cmpsts) (mrgmltpls (allmltpls (oddprms)))) ;; internal define's are mutually recursive |
||
(define (oddprms) (cons 3 (lambda () (minusstrtat 5 (cmpsts))))) |
(define (oddprms) (cons 3 (lambda () (minusstrtat 5 (cmpsts))))) |
||
(cons 2 (lambda () (oddprms))))</ |
(cons 2 (lambda () (oddprms))))</syntaxhighlight> |
||
It can be tested with the following code: |
It can be tested with the following code: |
||
< |
<syntaxhighlight lang=scheme>(define (nthPrime n) |
||
(let nxtprm ((cnt 0) (ps (birdPrimes))) |
(let nxtprm ((cnt 0) (ps (birdPrimes))) |
||
(if (< cnt n) (nxtprm (+ cnt 1) ((cdr ps))) (car ps)))) |
(if (< cnt n) (nxtprm (+ cnt 1) ((cdr ps))) (car ps)))) |
||
(nthPrime 1000000)</ |
(nthPrime 1000000)</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
Line 16,782: | Line 16,782: | ||
The most efficient. Finds composites as a tree of unions of each prime's multiples. |
The most efficient. Finds composites as a tree of unions of each prime's multiples. |
||
< |
<syntaxhighlight lang=scheme> ;;;; all primes' multiples are removed, merged through a tree of unions |
||
;;;; runs in ~ n^1.15 run time in producing n = 100K .. 1M primes |
;;;; runs in ~ n^1.15 run time in producing n = 100K .. 1M primes |
||
(define (primes-stream) |
(define (primes-stream) |
||
Line 16,804: | Line 16,804: | ||
(s-union (tail (head sts)) |
(s-union (tail (head sts)) |
||
(head (tail sts)))) |
(head (tail sts)))) |
||
(pairs (tail (tail sts)))))</ |
(pairs (tail (tail sts)))))</syntaxhighlight> |
||
[http://ideone.com/Uuil5M Print 10 last primes] of the first thousand primes: |
[http://ideone.com/Uuil5M Print 10 last primes] of the first thousand primes: |
||
Line 16,814: | Line 16,814: | ||
This can be also accomplished by the following self contained code which follows the format of the <code>birdPrimes</code> code above with the added "pairs" function integrated into the "mrgmltpls" function: |
This can be also accomplished by the following self contained code which follows the format of the <code>birdPrimes</code> code above with the added "pairs" function integrated into the "mrgmltpls" function: |
||
< |
<syntaxhighlight lang=scheme>(define (treemergePrimes) |
||
(define (mltpls p) |
(define (mltpls p) |
||
(define pm2 (* p 2)) |
(define pm2 (* p 2)) |
||
Line 16,840: | Line 16,840: | ||
(define (cmpsts) (mrgmltpls (allmltpls (oddprms)))) ;; internal define's are mutually recursive |
(define (cmpsts) (mrgmltpls (allmltpls (oddprms)))) ;; internal define's are mutually recursive |
||
(define (oddprms) (cons 3 (lambda () (minusstrtat 5 (cmpsts))))) |
(define (oddprms) (cons 3 (lambda () (minusstrtat 5 (cmpsts))))) |
||
(cons 2 (lambda () (oddprms))))</ |
(cons 2 (lambda () (oddprms))))</syntaxhighlight> |
||
It can be tested with the same code as the self-contained Richard Bird sieve, just by calling <code>treemergePrimes</code> instead of <code>birdPrimes</code>. |
It can be tested with the same code as the self-contained Richard Bird sieve, just by calling <code>treemergePrimes</code> instead of <code>birdPrimes</code>. |
||
Line 16,846: | Line 16,846: | ||
===Generators=== |
===Generators=== |
||
< |
<syntaxhighlight lang=scheme>(define (integers n) |
||
(lambda () |
(lambda () |
||
(let ((ans n)) |
(let ((ans n)) |
||
Line 16,870: | Line 16,870: | ||
x))) |
x))) |
||
(define primes (sieve (integers 2))) </ |
(define primes (sieve (integers 2))) </syntaxhighlight> |
||
=={{header|Scilab}}== |
=={{header|Scilab}}== |
||
< |
<syntaxhighlight lang=scliab>function a = sieve(n) |
||
a = ~zeros(n, 1) |
a = ~zeros(n, 1) |
||
a(1) = %f |
a(1) = %f |
||
Line 16,891: | Line 16,891: | ||
sum(sieve(1000)) |
sum(sieve(1000)) |
||
// 168, the number of primes below 1000</ |
// 168, the number of primes below 1000</syntaxhighlight> |
||
=={{header|Scratch}}== |
=={{header|Scratch}}== |
||
< |
<syntaxhighlight lang=Scratch> |
||
when clicked |
when clicked |
||
broadcast: fill list with zero (0) and wait |
broadcast: fill list with zero (0) and wait |
||
Line 16,937: | Line 16,937: | ||
set k to (k + 1) |
set k to (k + 1) |
||
{end repeat} |
{end repeat} |
||
</syntaxhighlight> |
|||
</lang> |
|||
===Comments=== |
===Comments=== |
||
Line 16,953: | Line 16,953: | ||
=={{header|Seed7}}== |
=={{header|Seed7}}== |
||
The program below computes the number of primes between 1 and 10000000: |
The program below computes the number of primes between 1 and 10000000: |
||
< |
<syntaxhighlight lang=seed7>$ include "seed7_05.s7i"; |
||
const func set of integer: eratosthenes (in integer: n) is func |
const func set of integer: eratosthenes (in integer: n) is func |
||
Line 16,975: | Line 16,975: | ||
begin |
begin |
||
writeln(card(eratosthenes(10000000))); |
writeln(card(eratosthenes(10000000))); |
||
end func;</ |
end func;</syntaxhighlight> |
||
Original source: [http://seed7.sourceforge.net/algorith/math.htm#sieve_of_eratosthenes] |
Original source: [http://seed7.sourceforge.net/algorith/math.htm#sieve_of_eratosthenes] |
||
Line 16,981: | Line 16,981: | ||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
{{trans|Raku}} |
{{trans|Raku}} |
||
< |
<syntaxhighlight lang=ruby>func sieve(limit) { |
||
var sieve_arr = [false, false, (limit-1).of(true)...] |
var sieve_arr = [false, false, (limit-1).of(true)...] |
||
gather { |
gather { |
||
Line 16,995: | Line 16,995: | ||
} |
} |
||
say sieve(100).join(",")</ |
say sieve(100).join(",")</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 17,002: | Line 17,002: | ||
Alternative implementation: |
Alternative implementation: |
||
< |
<syntaxhighlight lang=ruby>func sieve(limit) { |
||
var composite = [] |
var composite = [] |
||
for n in (2 .. limit.isqrt) { |
for n in (2 .. limit.isqrt) { |
||
Line 17,012: | Line 17,012: | ||
} |
} |
||
say sieve(100).join(",")</ |
say sieve(100).join(",")</syntaxhighlight> |
||
=={{header|Simula}}== |
=={{header|Simula}}== |
||
{{works with|Simula-67}} |
{{works with|Simula-67}} |
||
< |
<syntaxhighlight lang=simula>BEGIN |
||
INTEGER ARRAY t(0:1000); |
INTEGER ARRAY t(0:1000); |
||
INTEGER i,j,k; |
INTEGER i,j,k; |
||
Line 17,043: | Line 17,043: | ||
OutInt(i,5); OutImage |
OutInt(i,5); OutImage |
||
END |
END |
||
END</ |
END</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre style="height:20ex"> 2 |
<pre style="height:20ex"> 2 |
||
Line 17,067: | Line 17,067: | ||
997</pre> |
997</pre> |
||
===A Concurrent Prime Sieve=== |
===A Concurrent Prime Sieve=== |
||
< |
<syntaxhighlight lang=simula> |
||
! A CONCURRENT PRIME SIEVE ; |
! A CONCURRENT PRIME SIEVE ; |
||
Line 17,175: | Line 17,175: | ||
END; |
END; |
||
END; |
END; |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 17,224: | Line 17,224: | ||
=={{header|Smalltalk}}== |
=={{header|Smalltalk}}== |
||
A simple implementation that you can run in a workspace. It finds all the prime numbers up to and including <i>limit</i>—for the sake of example, up to and including 100. |
A simple implementation that you can run in a workspace. It finds all the prime numbers up to and including <i>limit</i>—for the sake of example, up to and including 100. |
||
< |
<syntaxhighlight lang=smalltalk>| potentialPrimes limit | |
||
limit := 100. |
limit := 100. |
||
potentialPrimes := Array new: limit. |
potentialPrimes := Array new: limit. |
||
Line 17,239: | Line 17,239: | ||
Transcript show: testNumber asString; cr |
Transcript show: testNumber asString; cr |
||
] |
] |
||
]</ |
]</syntaxhighlight> |
||
=={{header|SNOBOL4}}== |
=={{header|SNOBOL4}}== |
||
Line 17,245: | Line 17,245: | ||
Using strings instead of arrays, and the square/sqrt optimizations. |
Using strings instead of arrays, and the square/sqrt optimizations. |
||
< |
<syntaxhighlight lang=SNOBOL4> define('sieve(n)i,j,k,p,str,res') :(sieve_end) |
||
sieve i = lt(i,n - 1) i + 1 :f(sv1) |
sieve i = lt(i,n - 1) i + 1 :f(sv1) |
||
str = str (i + 1) ' ' :(sieve) |
str = str (i + 1) ' ' :(sieve) |
||
Line 17,261: | Line 17,261: | ||
* # Test and display |
* # Test and display |
||
output = sieve(100) |
output = sieve(100) |
||
end</ |
end</syntaxhighlight> |
||
Output: |
Output: |
||
Line 17,268: | Line 17,268: | ||
=={{header|Standard ML}}== |
=={{header|Standard ML}}== |
||
Works with SML/NJ. This uses BitArrays which are available in SML/NJ. The algorithm is the one on wikipedia, referred to above. Limit: Memory, normally. When more than 20 petabyte of memory available, this code will have its limitation at a maximum integer around 1.44*10E17, due to the maximum list length in SMLNJ. Using two extra loops, however, bit arrays can simply be stored to disk and processed in multiple lists. With a tail recursive wrapper function as well, the upper limit will be determined by available disk space only. |
Works with SML/NJ. This uses BitArrays which are available in SML/NJ. The algorithm is the one on wikipedia, referred to above. Limit: Memory, normally. When more than 20 petabyte of memory available, this code will have its limitation at a maximum integer around 1.44*10E17, due to the maximum list length in SMLNJ. Using two extra loops, however, bit arrays can simply be stored to disk and processed in multiple lists. With a tail recursive wrapper function as well, the upper limit will be determined by available disk space only. |
||
< |
<syntaxhighlight lang=Standard ML> |
||
val segmentedSieve = fn N => |
val segmentedSieve = fn N => |
||
(* output : list of {segment=bit segment, start=number at startposition segment} *) |
(* output : list of {segment=bit segment, start=number at startposition segment} *) |
||
Line 17,377: | Line 17,377: | ||
end; |
end; |
||
</syntaxhighlight> |
|||
</lang> |
|||
Example, segment size 120 million, prime numbers up to 2.5 billion: |
Example, segment size 120 million, prime numbers up to 2.5 billion: |
||
< |
<syntaxhighlight lang=Standard ML> |
||
-val writeSegment = fn L : {segment:BitArray.array, start:IntInf.int} list => fn NthSegment => |
-val writeSegment = fn L : {segment:BitArray.array, start:IntInf.int} list => fn NthSegment => |
||
let |
let |
||
Line 17,401: | Line 17,401: | ||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Stata}}== |
=={{header|Stata}}== |
||
A program to create a dataset with a variable p containing primes up to a given number. |
A program to create a dataset with a variable p containing primes up to a given number. |
||
< |
<syntaxhighlight lang=stata>prog def sieve |
||
args n |
args n |
||
clear |
clear |
||
Line 17,424: | Line 17,424: | ||
qui keep if a |
qui keep if a |
||
drop a |
drop a |
||
end</ |
end</syntaxhighlight> |
||
Example call |
Example call |
||
< |
<syntaxhighlight lang=stata>sieve 100 |
||
list in 1/10 // show only the first ten primes |
list in 1/10 // show only the first ten primes |
||
Line 17,444: | Line 17,444: | ||
9. | 23 | |
9. | 23 | |
||
10. | 29 | |
10. | 29 | |
||
+----+</ |
+----+</syntaxhighlight> |
||
=== Mata === |
=== Mata === |
||
< |
<syntaxhighlight lang=stata>mata |
||
real colvector sieve(real scalar n) { |
real colvector sieve(real scalar n) { |
||
real colvector a |
real colvector a |
||
Line 17,472: | Line 17,472: | ||
4 | 7 | |
4 | 7 | |
||
+-----+ |
+-----+ |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Swift}}== |
=={{header|Swift}}== |
||
< |
<syntaxhighlight lang=swift>import Foundation // for sqrt() and Date() |
||
let max = 1_000_000 |
let max = 1_000_000 |
||
Line 17,499: | Line 17,499: | ||
print("\(count) primes found under \(max)") |
print("\(count) primes found under \(max)") |
||
print("\(startingPoint.timeIntervalSinceNow * -1) seconds")</ |
print("\(startingPoint.timeIntervalSinceNow * -1) seconds")</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>78498 primes found under 1000000 |
<pre>78498 primes found under 1000000 |
||
Line 17,509: | Line 17,509: | ||
The most obvious two improvements are to sieve for only odds as two is the only even prime and to make the sieving array bit-packed so that instead of a whole 8-bit byte per number representation there, each is represented by just one bit; these two changes improved memory use by a factor of 16 and the better CPU cache locality more than compensates for the extra code required to implement bit packing as per the following code: |
The most obvious two improvements are to sieve for only odds as two is the only even prime and to make the sieving array bit-packed so that instead of a whole 8-bit byte per number representation there, each is represented by just one bit; these two changes improved memory use by a factor of 16 and the better CPU cache locality more than compensates for the extra code required to implement bit packing as per the following code: |
||
< |
<syntaxhighlight lang=swift>func soePackedOdds(_ n: Int) -> |
||
LazyMapSequence<UnfoldSequence<Int, (Int?, Bool)>, Int> { |
LazyMapSequence<UnfoldSequence<Int, (Int?, Bool)>, Int> { |
||
Line 17,531: | Line 17,531: | ||
return ni > lmti ? nil : ni |
return ni > lmti ? nil : ni |
||
}).lazy.map { $0 < 0 ? 2 : $0 + $0 + 3 } |
}).lazy.map { $0 < 0 ? 2 : $0 + $0 + 3 } |
||
}</ |
}</syntaxhighlight> |
||
the output for the same testing (with `soePackedOdds` substituted for `primes`) is the same except that it is about 1.5 times faster or only 1200 cycles per prime. |
the output for the same testing (with `soePackedOdds` substituted for `primes`) is the same except that it is about 1.5 times faster or only 1200 cycles per prime. |
||
Line 17,540: | Line 17,540: | ||
To use Swift's "higher order functions" on the generated `Sequence`'s effectively, one needs unbounded (or only by the numeric range chosen for the implementation) sieves. Many of these are incremental sieves that, instead of buffering a series of culled arrays, records the culling structure of the culling base primes (which should be a secondary stream of primes for efficiency) and produces the primes incrementally through reference and update of that structure. Various structures may be chosen for this, as in a MinHeap Priority Queue, a Hash Dictionary, or a simple List tree structure as used in the following code: |
To use Swift's "higher order functions" on the generated `Sequence`'s effectively, one needs unbounded (or only by the numeric range chosen for the implementation) sieves. Many of these are incremental sieves that, instead of buffering a series of culled arrays, records the culling structure of the culling base primes (which should be a secondary stream of primes for efficiency) and produces the primes incrementally through reference and update of that structure. Various structures may be chosen for this, as in a MinHeap Priority Queue, a Hash Dictionary, or a simple List tree structure as used in the following code: |
||
< |
<syntaxhighlight lang=swift>import Foundation |
||
func soeTreeFoldingOdds() -> UnfoldSequence<Int, (Int?, Bool)> { |
func soeTreeFoldingOdds() -> UnfoldSequence<Int, (Int?, Bool)> { |
||
Line 17,614: | Line 17,614: | ||
print("Found \(answr) primes to \(range).") |
print("Found \(answr) primes to \(range).") |
||
print(String(format: "This test took %.3f milliseconds.", elpsd * 1000))</ |
print(String(format: "This test took %.3f milliseconds.", elpsd * 1000))</syntaxhighlight> |
||
The output is the same as for the above except that it is much slower at about 56,000 CPU clock cycles per prime even just sieving to ten million due to the many memory allocations/de-allocations. It also has a O(n (log n) (log (log n))) asymptotic computational complexity (with the extra "log n" factor) that makes it slower with increasing range. This makes this algorithm only useful up to ranges of a few million although it is adequate to solve trivial problems such as Euler Problem 10 of summing all the primes to two million. |
The output is the same as for the above except that it is much slower at about 56,000 CPU clock cycles per prime even just sieving to ten million due to the many memory allocations/de-allocations. It also has a O(n (log n) (log (log n))) asymptotic computational complexity (with the extra "log n" factor) that makes it slower with increasing range. This makes this algorithm only useful up to ranges of a few million although it is adequate to solve trivial problems such as Euler Problem 10 of summing all the primes to two million. |
||
Line 17,623: | Line 17,623: | ||
As the above code is slow due to memory allocations/de-allocations and the inherent extra "log n" term in the complexity, the following code uses a Hash Dictionary which has an average of O(1) access time (without the "log n" and uses mutability for increased seed so is in no way purely functional: |
As the above code is slow due to memory allocations/de-allocations and the inherent extra "log n" term in the complexity, the following code uses a Hash Dictionary which has an average of O(1) access time (without the "log n" and uses mutability for increased seed so is in no way purely functional: |
||
< |
<syntaxhighlight lang=swift>func soeDictOdds() -> UnfoldSequence<Int, Int> { |
||
var bp = 5; var q = 25 |
var bp = 5; var q = 25 |
||
var bps: UnfoldSequence<Int, Int>.Iterator? = nil |
var bps: UnfoldSequence<Int, Int>.Iterator? = nil |
||
Line 17,649: | Line 17,649: | ||
defer { n += 2 }; return n |
defer { n += 2 }; return n |
||
}) |
}) |
||
}</ |
}</syntaxhighlight> |
||
It can be substituted in the above code just by substituting the `soeDictOdds` in three places in the testing code with the same output other than it is over four times faster or about 12,500 CPU clock cycles per prime. |
It can be substituted in the above code just by substituting the `soeDictOdds` in three places in the testing code with the same output other than it is over four times faster or about 12,500 CPU clock cycles per prime. |
||
Line 17,656: | Line 17,656: | ||
An unbounded array-based algorithm can be written that combines the excellent cache locality of the second bounded version above but is unbounded by producing a sequence of sieved bit-packed arrays that are CPU cache size as required with a secondary stream of base primes used in culling produced in the same fashion, as in the following code: |
An unbounded array-based algorithm can be written that combines the excellent cache locality of the second bounded version above but is unbounded by producing a sequence of sieved bit-packed arrays that are CPU cache size as required with a secondary stream of base primes used in culling produced in the same fashion, as in the following code: |
||
< |
<syntaxhighlight lang=swift>import Foundation |
||
typealias Prime = UInt64 |
typealias Prime = UInt64 |
||
Line 17,970: | Line 17,970: | ||
print("Found \(answr) primes up to \(range).") |
print("Found \(answr) primes up to \(range).") |
||
print(String(format: "This test took %.3f milliseconds.", elpsd * 1000))</ |
print(String(format: "This test took %.3f milliseconds.", elpsd * 1000))</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>The first 25 primes are: |
<pre>The first 25 primes are: |
||
Line 17,982: | Line 17,982: | ||
=={{header|Tailspin}}== |
=={{header|Tailspin}}== |
||
< |
<syntaxhighlight lang=tailspin> |
||
templates sieve |
templates sieve |
||
def limit: $; |
def limit: $; |
||
Line 18,006: | Line 18,006: | ||
1000 -> sieve ...-> '$; ' -> !OUT::write |
1000 -> sieve ...-> '$; ' -> !OUT::write |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 18,013: | Line 18,013: | ||
Better version using the mutability of the @-state to just update a primality flag |
Better version using the mutability of the @-state to just update a primality flag |
||
< |
<syntaxhighlight lang=tailspin> |
||
templates sieve |
templates sieve |
||
def limit: $; |
def limit: $; |
||
Line 18,027: | Line 18,027: | ||
1000 -> sieve... -> '$; ' -> !OUT::write |
1000 -> sieve... -> '$; ' -> !OUT::write |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 18,034: | Line 18,034: | ||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
< |
<syntaxhighlight lang=tcl>package require Tcl 8.5 |
||
proc sieve n { |
proc sieve n { |
||
Line 18,059: | Line 18,059: | ||
} |
} |
||
puts [sieve 100] ;# 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97</ |
puts [sieve 100] ;# 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97</syntaxhighlight> |
||
Line 18,065: | Line 18,065: | ||
=={{header|TI-83 BASIC}}== |
=={{header|TI-83 BASIC}}== |
||
< |
<syntaxhighlight lang=ti83b>Input "Limit:",N |
||
N→Dim(L1) |
N→Dim(L1) |
||
For(I,2,N) |
For(I,2,N) |
||
Line 18,084: | Line 18,084: | ||
End |
End |
||
End |
End |
||
ClrList L1</ |
ClrList L1</syntaxhighlight> |
||
=={{header|UNIX Shell}}== |
=={{header|UNIX Shell}}== |
||
Line 18,091: | Line 18,091: | ||
{{works with|Korn Shell}} |
{{works with|Korn Shell}} |
||
{{works with|Zsh}} |
{{works with|Zsh}} |
||
< |
<syntaxhighlight lang=bash>function primes { |
||
typeset -a a |
typeset -a a |
||
typeset i j |
typeset i j |
||
Line 18,110: | Line 18,110: | ||
} |
} |
||
primes 1000</ |
primes 1000</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
Line 18,120: | Line 18,120: | ||
{{works with|Bourne Shell}} |
{{works with|Bourne Shell}} |
||
< |
<syntaxhighlight lang=bash>#! /bin/sh |
||
LIMIT=1000 |
LIMIT=1000 |
||
Line 18,162: | Line 18,162: | ||
eval \\$p$i && echo $i |
eval \\$p$i && echo $i |
||
i=\`expr $i + 1\` |
i=\`expr $i + 1\` |
||
done`</ |
done`</syntaxhighlight> |
||
===With piping=== |
===With piping=== |
||
Line 18,174: | Line 18,174: | ||
{{works with|Bourne Shell}} |
{{works with|Bourne Shell}} |
||
< |
<syntaxhighlight lang=bash>sourc() { |
||
seq 2 1000 |
seq 2 1000 |
||
} |
} |
||
Line 18,192: | Line 18,192: | ||
} |
} |
||
sourc | sink</ |
sourc | sink</syntaxhighlight> |
||
This version works by piping 1s and 0s through ''sed''. The string of 1s and 0s represents the array of primes. |
This version works by piping 1s and 0s through ''sed''. The string of 1s and 0s represents the array of primes. |
||
{{works with|Bourne Shell}} |
{{works with|Bourne Shell}} |
||
< |
<syntaxhighlight lang=bash># Fill $1 characters with $2. |
||
fill () { |
fill () { |
||
# This pipeline would begin |
# This pipeline would begin |
||
Line 18,229: | Line 18,229: | ||
} |
} |
||
prime 1000</ |
prime 1000</syntaxhighlight> |
||
==={{header|C Shell}}=== |
==={{header|C Shell}}=== |
||
{{trans|CMake}} |
{{trans|CMake}} |
||
< |
<syntaxhighlight lang=csh># Sieve of Eratosthenes: Echoes all prime numbers through $limit. |
||
@ limit = 80 |
@ limit = 80 |
||
Line 18,260: | Line 18,260: | ||
endif |
endif |
||
@ i += 1 |
@ i += 1 |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Ursala}}== |
=={{header|Ursala}}== |
||
{{incorrect|Ursala|It probably (remainder) uses rem testing and so is a trial division algorithm, not a sieve of Eratosthenes.}} |
{{incorrect|Ursala|It probably (remainder) uses rem testing and so is a trial division algorithm, not a sieve of Eratosthenes.}} |
||
with no optimizations |
with no optimizations |
||
< |
<syntaxhighlight lang=Ursala>#import nat |
||
sieve = ~<{0,1}&& iota; @NttPX ~&r->lx ^/~&rhPlC remainder@rlX~|@r</ |
sieve = ~<{0,1}&& iota; @NttPX ~&r->lx ^/~&rhPlC remainder@rlX~|@r</syntaxhighlight> |
||
test program: |
test program: |
||
< |
<syntaxhighlight lang=Ursala>#cast %nL |
||
example = sieve 50</ |
example = sieve 50</syntaxhighlight>{{out}} |
||
<2,3,5,7,11,13,17,19,23,29,31,37,41,43,47> |
<2,3,5,7,11,13,17,19,23,29,31,37,41,43,47> |
||
=={{header|Vala}}== |
=={{header|Vala}}== |
||
{{libheader|Gee}}Without any optimizations: |
{{libheader|Gee}}Without any optimizations: |
||
< |
<syntaxhighlight lang=vala>using Gee; |
||
ArrayList<int> primes(int limit){ |
ArrayList<int> primes(int limit){ |
||
Line 18,313: | Line 18,313: | ||
stdout.printf("\n"); |
stdout.printf("\n"); |
||
}</ |
}</syntaxhighlight>{{out} |
||
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 |
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 |
||
=={{header|VAX Assembly}}== |
=={{header|VAX Assembly}}== |
||
< |
<syntaxhighlight lang=VAX Assembly> 000F4240 0000 1 n=1000*1000 |
||
0000 0000 2 .entry main,0 |
0000 0000 2 .entry main,0 |
||
7E 7CFD 0002 3 clro -(sp) ;result buffer |
7E 7CFD 0002 3 clro -(sp) ;result buffer |
||
Line 18,345: | Line 18,345: | ||
0046 27 |
0046 27 |
||
0001E892 0046 28 bits: .blkl <n+2+31>/32 |
0001E892 0046 28 bits: .blkl <n+2+31>/32 |
||
E892 29 .end main</ |
E892 29 .end main</syntaxhighlight> |
||
=={{header|VBA}}== |
=={{header|VBA}}== |
||
Using Excel< |
Using Excel<syntaxhighlight lang=vb> Sub primes() |
||
'BRRJPA |
'BRRJPA |
||
'Prime calculation for VBA_Excel |
'Prime calculation for VBA_Excel |
||
Line 18,378: | Line 18,378: | ||
Next a |
Next a |
||
End Sub </ |
End Sub </syntaxhighlight> |
||
=={{header|VBScript}}== |
=={{header|VBScript}}== |
||
To run in console mode with cscript. |
To run in console mode with cscript. |
||
<syntaxhighlight lang=vb> |
|||
<lang vb> |
|||
Dim sieve() |
Dim sieve() |
||
If WScript.Arguments.Count>=1 Then |
If WScript.Arguments.Count>=1 Then |
||
Line 18,403: | Line 18,403: | ||
If sieve(i) Then WScript.Echo i |
If sieve(i) Then WScript.Echo i |
||
Next |
Next |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Vedit macro language}}== |
=={{header|Vedit macro language}}== |
||
Line 18,443: | Line 18,443: | ||
=={{header|Visual Basic}}== |
=={{header|Visual Basic}}== |
||
'''Works with:''' VB6 |
'''Works with:''' VB6 |
||
< |
<syntaxhighlight lang=vb>Sub Eratost() |
||
Dim sieve() As Boolean |
Dim sieve() As Boolean |
||
Dim n As Integer, i As Integer, j As Integer |
Dim n As Integer, i As Integer, j As Integer |
||
Line 18,461: | Line 18,461: | ||
If sieve(i) Then Debug.Print i |
If sieve(i) Then Debug.Print i |
||
Next i |
Next i |
||
End Sub 'Eratost</ |
End Sub 'Eratost</syntaxhighlight> |
||
=={{header|Visual Basic .NET}}== |
=={{header|Visual Basic .NET}}== |
||
< |
<syntaxhighlight lang=vbnet>Dim n As Integer, k As Integer, limit As Integer |
||
Console.WriteLine("Enter number to search to: ") |
Console.WriteLine("Enter number to search to: ") |
||
limit = Console.ReadLine |
limit = Console.ReadLine |
||
Line 18,481: | Line 18,481: | ||
Console.WriteLine(n) |
Console.WriteLine(n) |
||
End If |
End If |
||
Next n</ |
Next n</syntaxhighlight> |
||
===Alternate=== |
===Alternate=== |
||
Since the sieves are being removed only above the current iteration, the separate loop for display is unnecessary. And no '''Math.Sqrt()''' needed. Also, input is from command line parameter instead of Console.ReadLine(). Consolidated ''If'' block with ''For'' statement into two ''Do'' loops. |
Since the sieves are being removed only above the current iteration, the separate loop for display is unnecessary. And no '''Math.Sqrt()''' needed. Also, input is from command line parameter instead of Console.ReadLine(). Consolidated ''If'' block with ''For'' statement into two ''Do'' loops. |
||
< |
<syntaxhighlight lang=vbnet>Module Module1 |
||
Sub Main(args() As String) |
Sub Main(args() As String) |
||
Dim lmt As Integer = 500, n As Integer = 2, k As Integer |
Dim lmt As Integer = 500, n As Integer = 2, k As Integer |
||
Line 18,499: | Line 18,499: | ||
Loop while n <= lmt |
Loop while n <= lmt |
||
End Sub |
End Sub |
||
End Module</ |
End Module</syntaxhighlight>{{out}}<pre>2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 </pre> |
||
=={{header|Vlang}}== |
=={{header|Vlang}}== |
||
{{trans|go}} |
{{trans|go}} |
||
===Basic sieve of array of booleans=== |
===Basic sieve of array of booleans=== |
||
< |
<syntaxhighlight lang=vlang>fn main() { |
||
limit := 201 // means sieve numbers < 201 |
limit := 201 // means sieve numbers < 201 |
||
Line 18,541: | Line 18,541: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 18,557: | Line 18,557: | ||
=={{header|Vorpal}}== |
=={{header|Vorpal}}== |
||
< |
<syntaxhighlight lang=vorpal>self.print_primes = method(m){ |
||
p = new() |
p = new() |
||
p.fill(0, m, 1, true) |
p.fill(0, m, 1, true) |
||
Line 18,579: | Line 18,579: | ||
} |
} |
||
self.print_primes(100)</ |
self.print_primes(100)</syntaxhighlight>{{out|Result}} |
||
primes: 25 in 100 |
primes: 25 in 100 |
||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, |
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, |
||
Line 18,629: | Line 18,629: | ||
=={{header|Xojo}}== |
=={{header|Xojo}}== |
||
Place the following in the '''Run''' event handler of a Console application: |
Place the following in the '''Run''' event handler of a Console application: |
||
< |
<syntaxhighlight lang=Xojo>Dim limit, prime, i As Integer |
||
Dim s As String |
Dim s As String |
||
Dim t As Double |
Dim t As Double |
||
Line 18,661: | Line 18,661: | ||
If Not sieve(i) Then Print(Str(i)) |
If Not sieve(i) Then Print(Str(i)) |
||
Next |
Next |
||
s = Input</ |
s = Input</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 18,690: | Line 18,690: | ||
This version uses a dynamic array and can use (a lot) less memory. It's (a lot) slower too. |
This version uses a dynamic array and can use (a lot) less memory. It's (a lot) slower too. |
||
Since Booleans are manually set to True, the algorithm makes more sense. |
Since Booleans are manually set to True, the algorithm makes more sense. |
||
< |
<syntaxhighlight lang=Xojo>Dim limit, prime, i As Integer |
||
Dim s As String |
Dim s As String |
||
Dim t As Double |
Dim t As Double |
||
Line 18,728: | Line 18,728: | ||
If sieve(i) Then Print(Str(i)) |
If sieve(i) Then Print(Str(i)) |
||
Next |
Next |
||
s = Input</ |
s = Input</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 18,758: | Line 18,758: | ||
=={{header|Woma}}== |
=={{header|Woma}}== |
||
< |
<syntaxhighlight lang=woma>(sieve(n = /0 -> int; limit = /0 -> int; is_prime = [/0] -> *)) * |
||
i<@>range(n*n, limit+1, n) |
i<@>range(n*n, limit+1, n) |
||
is_prime = is_prime[$]i,False |
is_prime = is_prime[$]i,False |
||
Line 18,778: | Line 18,778: | ||
i,prime<@>enumerate(is_prime) |
i,prime<@>enumerate(is_prime) |
||
prime<?>primes = primes[^]i |
prime<?>primes = primes[^]i |
||
<*>primes</ |
<*>primes</syntaxhighlight> |
||
=={{header|Wren}}== |
=={{header|Wren}}== |
||
< |
<syntaxhighlight lang=ecmascript>var sieveOfE = Fn.new { |n| |
||
if (n < 2) return [] |
if (n < 2) return [] |
||
var comp = List.filled(n-1, false) |
var comp = List.filled(n-1, false) |
||
Line 18,805: | Line 18,805: | ||
} |
} |
||
System.print(sieveOfE.call(100))</ |
System.print(sieveOfE.call(100))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 18,813: | Line 18,813: | ||
=={{header|XPL0}}== |
=={{header|XPL0}}== |
||
< |
<syntaxhighlight lang=XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations |
||
int Size, Prime, I, Kill; |
int Size, Prime, I, Kill; |
||
char Flag; |
char Flag; |
||
Line 18,829: | Line 18,829: | ||
]; |
]; |
||
]; |
]; |
||
]</ |
]</syntaxhighlight>{{out|Example output}}<pre>20 |
||
2 |
2 |
||
3 |
3 |
||
Line 18,840: | Line 18,840: | ||
=={{header|Yabasic}}== |
=={{header|Yabasic}}== |
||
< |
<syntaxhighlight lang=Yabasic>#!/usr/bin/yabasic |
||
// --------------------------- |
// --------------------------- |
||
Line 18,892: | Line 18,892: | ||
print "time: ", t, "\n" |
print "time: ", t, "\n" |
||
print peek("millisrunning")</ |
print peek("millisrunning")</syntaxhighlight> |
||
=={{header|Zig}}== |
=={{header|Zig}}== |
||
< |
<syntaxhighlight lang=Zig> |
||
const std = @import("std"); |
const std = @import("std"); |
||
const stdout = std.io.getStdOut().outStream(); |
const stdout = std.io.getStdOut().outStream(); |
||
Line 18,926: | Line 18,926: | ||
try stdout.print("\n", .{}); |
try stdout.print("\n", .{}); |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 18,951: | Line 18,951: | ||
{{trans|BCPL}} |
{{trans|BCPL}} |
||
Includes the iterator, as with the BCPL Odds-only bit packed sieve. Since it's not much extra code, the sieve object also includes methods for getting the size and testing for membership. |
Includes the iterator, as with the BCPL Odds-only bit packed sieve. Since it's not much extra code, the sieve object also includes methods for getting the size and testing for membership. |
||
< |
<syntaxhighlight lang=Zig> |
||
const std = @import("std"); |
const std = @import("std"); |
||
const heap = std.heap; |
const heap = std.heap; |
||
Line 19,112: | Line 19,112: | ||
} |
} |
||
}; |
}; |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Out}} |
{{Out}} |
||
<pre> |
<pre> |
||
Line 19,135: | Line 19,135: | ||
</pre> |
</pre> |
||
===Optimized version=== |
===Optimized version=== |
||
< |
<syntaxhighlight lang=Zig> |
||
const stdout = @import("std").io.getStdOut().writer(); |
const stdout = @import("std").io.getStdOut().writer(); |
||
Line 19,166: | Line 19,166: | ||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Out}} |
{{Out}} |
||
<pre> |
<pre> |
||
Line 19,190: | Line 19,190: | ||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
< |
<syntaxhighlight lang=zkl>fcn sieve(limit){ |
||
composite:=Data(limit+1).fill(1); // bucket of bytes set to 1 (prime) |
composite:=Data(limit+1).fill(1); // bucket of bytes set to 1 (prime) |
||
(2).pump(limit.toFloat().sqrt()+1, Void, // Void==no results, just loop |
(2).pump(limit.toFloat().sqrt()+1, Void, // Void==no results, just loop |
||
Line 19,197: | Line 19,197: | ||
(2).filter(limit-1,composite.get); // bytes still 1 are prime |
(2).filter(limit-1,composite.get); // bytes still 1 are prime |
||
} |
} |
||
sieve(53).println();</ |
sieve(53).println();</syntaxhighlight> |
||
The pump method is just a loop, passing results from action to action |
The pump method is just a loop, passing results from action to action |
||
and collecting the results (ie a minimal state machine). Pumping to Void |
and collecting the results (ie a minimal state machine). Pumping to Void |