Faster Sieve of EratosthenesPrime Number Generator in SwiftSieve of Eratosthenes optimizationSieve of Eratosthenes - PythonThreshing: Sieve of EratosthenesSieve of Erathosthenes speedupSieve of Eratosthenes - segmented to increase speed and rangeSieve32Fast - A very fast, memory efficient, multi-threaded Sieve of EratosthenesSieve of Eratosthenes Primes EfficiencyUnbounded Sieve of Eratosthenes in SwiftCustom Sieve of EratosthenesSieve of Eratosthenes in Rust
Is expanding the research of a group into machine learning as a PhD student risky?
Fastening aluminum fascia to wooden subfascia
How can I get through very long and very dry, but also very useful technical documents when learning a new tool?
Sequence of Tenses: Translating the subjunctive
Are student evaluations of teaching assistants read by others in the faculty?
Is there a good way to store credentials outside of a password manager?
What Brexit proposals are on the table in the indicative votes on the 27th of March 2019?
Closest Prime Number
Why Were Madagascar and New Zealand Discovered So Late?
Do sorcerers' subtle spells require a skill check to be unseen?
Unreliable Magic - Is it worth it?
Lay out the Carpet
Integer addition + constant, is it a group?
Why are there no referendums in the US?
Pole-zeros of a real-valued causal FIR system
What is paid subscription needed for in Mortal Kombat 11?
How to Reset Passwords on Multiple Websites Easily?
How to draw lines on a tikz-cd diagram
What does "I’d sit this one out, Cap," imply or mean in the context?
Customer Requests (Sometimes) Drive Me Bonkers!
How does buying out courses with grant money work?
Why escape if the_content isnt?
Term for the "extreme-extension" version of a straw man fallacy?
How do I go from 300 unfinished/half written blog posts, to published posts?
Faster Sieve of Eratosthenes
Prime Number Generator in SwiftSieve of Eratosthenes optimizationSieve of Eratosthenes - PythonThreshing: Sieve of EratosthenesSieve of Erathosthenes speedupSieve of Eratosthenes - segmented to increase speed and rangeSieve32Fast - A very fast, memory efficient, multi-threaded Sieve of EratosthenesSieve of Eratosthenes Primes EfficiencyUnbounded Sieve of Eratosthenes in SwiftCustom Sieve of EratosthenesSieve of Eratosthenes in Rust
$begingroup$
This is an implementation of the Sieve of Eratosthenes :
It takes advantages of the fact that all primes from 5 and above can be written as
6X-1
or6X+1
,For better space complexity, it uses a pretty accurate
upperbound
. Better estimations of the upper bound can be found here. I've observed a very slight increase in performance with this.
func eratosthenesSieve(to n: Int) -> [Int]
guard 2 <= n else return []
var composites = Array(repeating: false, count: n + 1)
var primes: [Int] = []
let d = Double(n)
let upperBound = Int((d / log(d)) * (1.0 + 1.2762/log(d)))
primes.reserveCapacity(upperBound)
let squareRootN = Int(d.squareRoot())
//2 and 3
var p = 2
let twoOrThree = min(n, 3)
while p <= twoOrThree
primes.append(p)
var q = p * p
let step = p * (p - 1)
while q <= n
composites[q] = true
q += step
p += 1
//5 and above
p += 1
while p <= squareRootN
for i in 0..<2
let nbr = p + 2 * i
if !composites[nbr]
primes.append(nbr)
var q = nbr * nbr
var coef = 2 * (i + 1)
while q <= n
composites[q] = true
q += coef * nbr
coef = 6 - coef
p += 6
while p <= n
for i in 0..<2
let nbr = p + 2 * i
if nbr <= n && !composites[nbr]
primes.append(nbr)
p += 6
return primes
It was inspired by this code by Mr Martin.
Using the same benchmarking code in that answer, adding a fourth fractional digit in the timing results, plus some formatting, here are the results :
---------------------------------------------------------------
| | Nbr | Time (sec) |
| Up to | of |------------------------------|
| | Primes | Martin's | This |
|----------------|-------------|------------------------------|
| 100_000 | 9592 | 0.0008 | 0.0004 |
|----------------|-------------|--------------|---------------|
| 1_000_000 | 78_498 | 0.0056 | 0.0026 |
|----------------|-------------|--------------|---------------|
| 10_000_000 | 664_579 | 0.1233 | 0.0426 |
|----------------|-------------|--------------|---------------|
| 100_000_000 | 5_761_455 | 1.0976 | 0.5089 |
|----------------|-------------|--------------|---------------|
| 1_000_000_000 | 50_847_534 | 12.1328 | 5.9759 |
|----------------|-------------|--------------|---------------|
| 10_000_000_000 | 455_052_511 | 165.5658 | 84.5477 |
|----------------|-------------|--------------|---------------|
Using Attabench, here is a visual representation of the performance of both codes while n
is less than 2^16
:
One thing I observe is some elements in the composites
array are marked with true
multiple times. This is expected (but unwanted) behavior since 6X-1
or 6X+1
aren't all primes.
What I'm looking for is making this Sieve of Eratosthenes quicker. I'm well aware of faster methods of finding primes.
Naming, code clarity, conciseness, consistency, etc, are welcome but are not the main point here.
performance primes swift sieve-of-eratosthenes
$endgroup$
add a comment |
$begingroup$
This is an implementation of the Sieve of Eratosthenes :
It takes advantages of the fact that all primes from 5 and above can be written as
6X-1
or6X+1
,For better space complexity, it uses a pretty accurate
upperbound
. Better estimations of the upper bound can be found here. I've observed a very slight increase in performance with this.
func eratosthenesSieve(to n: Int) -> [Int]
guard 2 <= n else return []
var composites = Array(repeating: false, count: n + 1)
var primes: [Int] = []
let d = Double(n)
let upperBound = Int((d / log(d)) * (1.0 + 1.2762/log(d)))
primes.reserveCapacity(upperBound)
let squareRootN = Int(d.squareRoot())
//2 and 3
var p = 2
let twoOrThree = min(n, 3)
while p <= twoOrThree
primes.append(p)
var q = p * p
let step = p * (p - 1)
while q <= n
composites[q] = true
q += step
p += 1
//5 and above
p += 1
while p <= squareRootN
for i in 0..<2
let nbr = p + 2 * i
if !composites[nbr]
primes.append(nbr)
var q = nbr * nbr
var coef = 2 * (i + 1)
while q <= n
composites[q] = true
q += coef * nbr
coef = 6 - coef
p += 6
while p <= n
for i in 0..<2
let nbr = p + 2 * i
if nbr <= n && !composites[nbr]
primes.append(nbr)
p += 6
return primes
It was inspired by this code by Mr Martin.
Using the same benchmarking code in that answer, adding a fourth fractional digit in the timing results, plus some formatting, here are the results :
---------------------------------------------------------------
| | Nbr | Time (sec) |
| Up to | of |------------------------------|
| | Primes | Martin's | This |
|----------------|-------------|------------------------------|
| 100_000 | 9592 | 0.0008 | 0.0004 |
|----------------|-------------|--------------|---------------|
| 1_000_000 | 78_498 | 0.0056 | 0.0026 |
|----------------|-------------|--------------|---------------|
| 10_000_000 | 664_579 | 0.1233 | 0.0426 |
|----------------|-------------|--------------|---------------|
| 100_000_000 | 5_761_455 | 1.0976 | 0.5089 |
|----------------|-------------|--------------|---------------|
| 1_000_000_000 | 50_847_534 | 12.1328 | 5.9759 |
|----------------|-------------|--------------|---------------|
| 10_000_000_000 | 455_052_511 | 165.5658 | 84.5477 |
|----------------|-------------|--------------|---------------|
Using Attabench, here is a visual representation of the performance of both codes while n
is less than 2^16
:
One thing I observe is some elements in the composites
array are marked with true
multiple times. This is expected (but unwanted) behavior since 6X-1
or 6X+1
aren't all primes.
What I'm looking for is making this Sieve of Eratosthenes quicker. I'm well aware of faster methods of finding primes.
Naming, code clarity, conciseness, consistency, etc, are welcome but are not the main point here.
performance primes swift sieve-of-eratosthenes
$endgroup$
add a comment |
$begingroup$
This is an implementation of the Sieve of Eratosthenes :
It takes advantages of the fact that all primes from 5 and above can be written as
6X-1
or6X+1
,For better space complexity, it uses a pretty accurate
upperbound
. Better estimations of the upper bound can be found here. I've observed a very slight increase in performance with this.
func eratosthenesSieve(to n: Int) -> [Int]
guard 2 <= n else return []
var composites = Array(repeating: false, count: n + 1)
var primes: [Int] = []
let d = Double(n)
let upperBound = Int((d / log(d)) * (1.0 + 1.2762/log(d)))
primes.reserveCapacity(upperBound)
let squareRootN = Int(d.squareRoot())
//2 and 3
var p = 2
let twoOrThree = min(n, 3)
while p <= twoOrThree
primes.append(p)
var q = p * p
let step = p * (p - 1)
while q <= n
composites[q] = true
q += step
p += 1
//5 and above
p += 1
while p <= squareRootN
for i in 0..<2
let nbr = p + 2 * i
if !composites[nbr]
primes.append(nbr)
var q = nbr * nbr
var coef = 2 * (i + 1)
while q <= n
composites[q] = true
q += coef * nbr
coef = 6 - coef
p += 6
while p <= n
for i in 0..<2
let nbr = p + 2 * i
if nbr <= n && !composites[nbr]
primes.append(nbr)
p += 6
return primes
It was inspired by this code by Mr Martin.
Using the same benchmarking code in that answer, adding a fourth fractional digit in the timing results, plus some formatting, here are the results :
---------------------------------------------------------------
| | Nbr | Time (sec) |
| Up to | of |------------------------------|
| | Primes | Martin's | This |
|----------------|-------------|------------------------------|
| 100_000 | 9592 | 0.0008 | 0.0004 |
|----------------|-------------|--------------|---------------|
| 1_000_000 | 78_498 | 0.0056 | 0.0026 |
|----------------|-------------|--------------|---------------|
| 10_000_000 | 664_579 | 0.1233 | 0.0426 |
|----------------|-------------|--------------|---------------|
| 100_000_000 | 5_761_455 | 1.0976 | 0.5089 |
|----------------|-------------|--------------|---------------|
| 1_000_000_000 | 50_847_534 | 12.1328 | 5.9759 |
|----------------|-------------|--------------|---------------|
| 10_000_000_000 | 455_052_511 | 165.5658 | 84.5477 |
|----------------|-------------|--------------|---------------|
Using Attabench, here is a visual representation of the performance of both codes while n
is less than 2^16
:
One thing I observe is some elements in the composites
array are marked with true
multiple times. This is expected (but unwanted) behavior since 6X-1
or 6X+1
aren't all primes.
What I'm looking for is making this Sieve of Eratosthenes quicker. I'm well aware of faster methods of finding primes.
Naming, code clarity, conciseness, consistency, etc, are welcome but are not the main point here.
performance primes swift sieve-of-eratosthenes
$endgroup$
This is an implementation of the Sieve of Eratosthenes :
It takes advantages of the fact that all primes from 5 and above can be written as
6X-1
or6X+1
,For better space complexity, it uses a pretty accurate
upperbound
. Better estimations of the upper bound can be found here. I've observed a very slight increase in performance with this.
func eratosthenesSieve(to n: Int) -> [Int]
guard 2 <= n else return []
var composites = Array(repeating: false, count: n + 1)
var primes: [Int] = []
let d = Double(n)
let upperBound = Int((d / log(d)) * (1.0 + 1.2762/log(d)))
primes.reserveCapacity(upperBound)
let squareRootN = Int(d.squareRoot())
//2 and 3
var p = 2
let twoOrThree = min(n, 3)
while p <= twoOrThree
primes.append(p)
var q = p * p
let step = p * (p - 1)
while q <= n
composites[q] = true
q += step
p += 1
//5 and above
p += 1
while p <= squareRootN
for i in 0..<2
let nbr = p + 2 * i
if !composites[nbr]
primes.append(nbr)
var q = nbr * nbr
var coef = 2 * (i + 1)
while q <= n
composites[q] = true
q += coef * nbr
coef = 6 - coef
p += 6
while p <= n
for i in 0..<2
let nbr = p + 2 * i
if nbr <= n && !composites[nbr]
primes.append(nbr)
p += 6
return primes
It was inspired by this code by Mr Martin.
Using the same benchmarking code in that answer, adding a fourth fractional digit in the timing results, plus some formatting, here are the results :
---------------------------------------------------------------
| | Nbr | Time (sec) |
| Up to | of |------------------------------|
| | Primes | Martin's | This |
|----------------|-------------|------------------------------|
| 100_000 | 9592 | 0.0008 | 0.0004 |
|----------------|-------------|--------------|---------------|
| 1_000_000 | 78_498 | 0.0056 | 0.0026 |
|----------------|-------------|--------------|---------------|
| 10_000_000 | 664_579 | 0.1233 | 0.0426 |
|----------------|-------------|--------------|---------------|
| 100_000_000 | 5_761_455 | 1.0976 | 0.5089 |
|----------------|-------------|--------------|---------------|
| 1_000_000_000 | 50_847_534 | 12.1328 | 5.9759 |
|----------------|-------------|--------------|---------------|
| 10_000_000_000 | 455_052_511 | 165.5658 | 84.5477 |
|----------------|-------------|--------------|---------------|
Using Attabench, here is a visual representation of the performance of both codes while n
is less than 2^16
:
One thing I observe is some elements in the composites
array are marked with true
multiple times. This is expected (but unwanted) behavior since 6X-1
or 6X+1
aren't all primes.
What I'm looking for is making this Sieve of Eratosthenes quicker. I'm well aware of faster methods of finding primes.
Naming, code clarity, conciseness, consistency, etc, are welcome but are not the main point here.
performance primes swift sieve-of-eratosthenes
performance primes swift sieve-of-eratosthenes
edited 1 min ago
ielyamani
asked Jan 13 at 21:33
ielyamaniielyamani
355213
355213
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
It takes advantages of the fact that all primes from 5 and above can be written as 6X-1 or 6X+1,
I don't think it does, really. It structures the code around that fact, but to take advantage of it, at a minimum you should replace
while p <= twoOrThree
primes.append(p)
var q = p * p
let step = p * (p - 1)
while q <= n
composites[q] = true
q += step
p += 1
with
while p <= twoOrThree
primes.append(p)
p += 1
which in my testing gives a significant speedup.
To maximise the advantage, you could reduce composites
to only store flags for $6X pm 1$. Proof of concept code (could be tidier):
var pidx = 1
p = 5
while p <= squareRootN
if !composites[pidx]
primes.append(p)
var qidx = 3 * pidx * (pidx + 2) + 1 + (pidx & 1)
let delta = p << 1
let off = (4 - 2 * (pidx & 1)) * pidx + 1
while qidx < composites.count
composites[qidx - off] = true
composites[qidx] = true
qidx += delta
if qidx - off < composites.count
composites[qidx - off] = true
pidx += 1
p += 2 + 2 * (pidx & 1)
while p <= n
if !composites[pidx] primes.append(p)
pidx += 1
p += 2 + 2 * (pidx & 1)
This gives a moderate speedup in my testing.
$endgroup$
$begingroup$
Thank you for the answer. Here are the benchmarks, and they favor the code in the question (original
being Martin's, anderatosthenes2
is the code in your answer). Attabench confirms the benchmarks.
$endgroup$
– ielyamani
Jan 14 at 13:06
$begingroup$
@Carpsen90, I don't know Swift and there seem to be some subtleties around imports which both this question and the answer you reference brush under the table, but I compared a tweaked version of your code with my code on tio.run . Full tested code. I see user time: 12.470 s for your code and 7.002 s for mine. tio.run isn't ideal for benchmarking, but that's a significant improvement.
$endgroup$
– Peter Taylor
Jan 14 at 14:02
$begingroup$
(I suspect the problem is that you've benchmarked my code sieving three times as far as your code).
$endgroup$
– Peter Taylor
Jan 14 at 14:04
$begingroup$
The benchmarks were correct and can still be reproduced. You didn't mention in your answer this linevar composites = Array(repeating: false, count: n / 3 + 1)
, which makes all the difference. Here are the new benchmarks which favor your code.
$endgroup$
– ielyamani
Jan 14 at 15:03
$begingroup$
The answer is intended to be a code review, not a patch.
$endgroup$
– Peter Taylor
Jan 14 at 15:27
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211437%2ffaster-sieve-of-eratosthenes%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
It takes advantages of the fact that all primes from 5 and above can be written as 6X-1 or 6X+1,
I don't think it does, really. It structures the code around that fact, but to take advantage of it, at a minimum you should replace
while p <= twoOrThree
primes.append(p)
var q = p * p
let step = p * (p - 1)
while q <= n
composites[q] = true
q += step
p += 1
with
while p <= twoOrThree
primes.append(p)
p += 1
which in my testing gives a significant speedup.
To maximise the advantage, you could reduce composites
to only store flags for $6X pm 1$. Proof of concept code (could be tidier):
var pidx = 1
p = 5
while p <= squareRootN
if !composites[pidx]
primes.append(p)
var qidx = 3 * pidx * (pidx + 2) + 1 + (pidx & 1)
let delta = p << 1
let off = (4 - 2 * (pidx & 1)) * pidx + 1
while qidx < composites.count
composites[qidx - off] = true
composites[qidx] = true
qidx += delta
if qidx - off < composites.count
composites[qidx - off] = true
pidx += 1
p += 2 + 2 * (pidx & 1)
while p <= n
if !composites[pidx] primes.append(p)
pidx += 1
p += 2 + 2 * (pidx & 1)
This gives a moderate speedup in my testing.
$endgroup$
$begingroup$
Thank you for the answer. Here are the benchmarks, and they favor the code in the question (original
being Martin's, anderatosthenes2
is the code in your answer). Attabench confirms the benchmarks.
$endgroup$
– ielyamani
Jan 14 at 13:06
$begingroup$
@Carpsen90, I don't know Swift and there seem to be some subtleties around imports which both this question and the answer you reference brush under the table, but I compared a tweaked version of your code with my code on tio.run . Full tested code. I see user time: 12.470 s for your code and 7.002 s for mine. tio.run isn't ideal for benchmarking, but that's a significant improvement.
$endgroup$
– Peter Taylor
Jan 14 at 14:02
$begingroup$
(I suspect the problem is that you've benchmarked my code sieving three times as far as your code).
$endgroup$
– Peter Taylor
Jan 14 at 14:04
$begingroup$
The benchmarks were correct and can still be reproduced. You didn't mention in your answer this linevar composites = Array(repeating: false, count: n / 3 + 1)
, which makes all the difference. Here are the new benchmarks which favor your code.
$endgroup$
– ielyamani
Jan 14 at 15:03
$begingroup$
The answer is intended to be a code review, not a patch.
$endgroup$
– Peter Taylor
Jan 14 at 15:27
add a comment |
$begingroup$
It takes advantages of the fact that all primes from 5 and above can be written as 6X-1 or 6X+1,
I don't think it does, really. It structures the code around that fact, but to take advantage of it, at a minimum you should replace
while p <= twoOrThree
primes.append(p)
var q = p * p
let step = p * (p - 1)
while q <= n
composites[q] = true
q += step
p += 1
with
while p <= twoOrThree
primes.append(p)
p += 1
which in my testing gives a significant speedup.
To maximise the advantage, you could reduce composites
to only store flags for $6X pm 1$. Proof of concept code (could be tidier):
var pidx = 1
p = 5
while p <= squareRootN
if !composites[pidx]
primes.append(p)
var qidx = 3 * pidx * (pidx + 2) + 1 + (pidx & 1)
let delta = p << 1
let off = (4 - 2 * (pidx & 1)) * pidx + 1
while qidx < composites.count
composites[qidx - off] = true
composites[qidx] = true
qidx += delta
if qidx - off < composites.count
composites[qidx - off] = true
pidx += 1
p += 2 + 2 * (pidx & 1)
while p <= n
if !composites[pidx] primes.append(p)
pidx += 1
p += 2 + 2 * (pidx & 1)
This gives a moderate speedup in my testing.
$endgroup$
$begingroup$
Thank you for the answer. Here are the benchmarks, and they favor the code in the question (original
being Martin's, anderatosthenes2
is the code in your answer). Attabench confirms the benchmarks.
$endgroup$
– ielyamani
Jan 14 at 13:06
$begingroup$
@Carpsen90, I don't know Swift and there seem to be some subtleties around imports which both this question and the answer you reference brush under the table, but I compared a tweaked version of your code with my code on tio.run . Full tested code. I see user time: 12.470 s for your code and 7.002 s for mine. tio.run isn't ideal for benchmarking, but that's a significant improvement.
$endgroup$
– Peter Taylor
Jan 14 at 14:02
$begingroup$
(I suspect the problem is that you've benchmarked my code sieving three times as far as your code).
$endgroup$
– Peter Taylor
Jan 14 at 14:04
$begingroup$
The benchmarks were correct and can still be reproduced. You didn't mention in your answer this linevar composites = Array(repeating: false, count: n / 3 + 1)
, which makes all the difference. Here are the new benchmarks which favor your code.
$endgroup$
– ielyamani
Jan 14 at 15:03
$begingroup$
The answer is intended to be a code review, not a patch.
$endgroup$
– Peter Taylor
Jan 14 at 15:27
add a comment |
$begingroup$
It takes advantages of the fact that all primes from 5 and above can be written as 6X-1 or 6X+1,
I don't think it does, really. It structures the code around that fact, but to take advantage of it, at a minimum you should replace
while p <= twoOrThree
primes.append(p)
var q = p * p
let step = p * (p - 1)
while q <= n
composites[q] = true
q += step
p += 1
with
while p <= twoOrThree
primes.append(p)
p += 1
which in my testing gives a significant speedup.
To maximise the advantage, you could reduce composites
to only store flags for $6X pm 1$. Proof of concept code (could be tidier):
var pidx = 1
p = 5
while p <= squareRootN
if !composites[pidx]
primes.append(p)
var qidx = 3 * pidx * (pidx + 2) + 1 + (pidx & 1)
let delta = p << 1
let off = (4 - 2 * (pidx & 1)) * pidx + 1
while qidx < composites.count
composites[qidx - off] = true
composites[qidx] = true
qidx += delta
if qidx - off < composites.count
composites[qidx - off] = true
pidx += 1
p += 2 + 2 * (pidx & 1)
while p <= n
if !composites[pidx] primes.append(p)
pidx += 1
p += 2 + 2 * (pidx & 1)
This gives a moderate speedup in my testing.
$endgroup$
It takes advantages of the fact that all primes from 5 and above can be written as 6X-1 or 6X+1,
I don't think it does, really. It structures the code around that fact, but to take advantage of it, at a minimum you should replace
while p <= twoOrThree
primes.append(p)
var q = p * p
let step = p * (p - 1)
while q <= n
composites[q] = true
q += step
p += 1
with
while p <= twoOrThree
primes.append(p)
p += 1
which in my testing gives a significant speedup.
To maximise the advantage, you could reduce composites
to only store flags for $6X pm 1$. Proof of concept code (could be tidier):
var pidx = 1
p = 5
while p <= squareRootN
if !composites[pidx]
primes.append(p)
var qidx = 3 * pidx * (pidx + 2) + 1 + (pidx & 1)
let delta = p << 1
let off = (4 - 2 * (pidx & 1)) * pidx + 1
while qidx < composites.count
composites[qidx - off] = true
composites[qidx] = true
qidx += delta
if qidx - off < composites.count
composites[qidx - off] = true
pidx += 1
p += 2 + 2 * (pidx & 1)
while p <= n
if !composites[pidx] primes.append(p)
pidx += 1
p += 2 + 2 * (pidx & 1)
This gives a moderate speedup in my testing.
answered Jan 14 at 11:23
Peter TaylorPeter Taylor
18.2k2963
18.2k2963
$begingroup$
Thank you for the answer. Here are the benchmarks, and they favor the code in the question (original
being Martin's, anderatosthenes2
is the code in your answer). Attabench confirms the benchmarks.
$endgroup$
– ielyamani
Jan 14 at 13:06
$begingroup$
@Carpsen90, I don't know Swift and there seem to be some subtleties around imports which both this question and the answer you reference brush under the table, but I compared a tweaked version of your code with my code on tio.run . Full tested code. I see user time: 12.470 s for your code and 7.002 s for mine. tio.run isn't ideal for benchmarking, but that's a significant improvement.
$endgroup$
– Peter Taylor
Jan 14 at 14:02
$begingroup$
(I suspect the problem is that you've benchmarked my code sieving three times as far as your code).
$endgroup$
– Peter Taylor
Jan 14 at 14:04
$begingroup$
The benchmarks were correct and can still be reproduced. You didn't mention in your answer this linevar composites = Array(repeating: false, count: n / 3 + 1)
, which makes all the difference. Here are the new benchmarks which favor your code.
$endgroup$
– ielyamani
Jan 14 at 15:03
$begingroup$
The answer is intended to be a code review, not a patch.
$endgroup$
– Peter Taylor
Jan 14 at 15:27
add a comment |
$begingroup$
Thank you for the answer. Here are the benchmarks, and they favor the code in the question (original
being Martin's, anderatosthenes2
is the code in your answer). Attabench confirms the benchmarks.
$endgroup$
– ielyamani
Jan 14 at 13:06
$begingroup$
@Carpsen90, I don't know Swift and there seem to be some subtleties around imports which both this question and the answer you reference brush under the table, but I compared a tweaked version of your code with my code on tio.run . Full tested code. I see user time: 12.470 s for your code and 7.002 s for mine. tio.run isn't ideal for benchmarking, but that's a significant improvement.
$endgroup$
– Peter Taylor
Jan 14 at 14:02
$begingroup$
(I suspect the problem is that you've benchmarked my code sieving three times as far as your code).
$endgroup$
– Peter Taylor
Jan 14 at 14:04
$begingroup$
The benchmarks were correct and can still be reproduced. You didn't mention in your answer this linevar composites = Array(repeating: false, count: n / 3 + 1)
, which makes all the difference. Here are the new benchmarks which favor your code.
$endgroup$
– ielyamani
Jan 14 at 15:03
$begingroup$
The answer is intended to be a code review, not a patch.
$endgroup$
– Peter Taylor
Jan 14 at 15:27
$begingroup$
Thank you for the answer. Here are the benchmarks, and they favor the code in the question (
original
being Martin's, and eratosthenes2
is the code in your answer). Attabench confirms the benchmarks.$endgroup$
– ielyamani
Jan 14 at 13:06
$begingroup$
Thank you for the answer. Here are the benchmarks, and they favor the code in the question (
original
being Martin's, and eratosthenes2
is the code in your answer). Attabench confirms the benchmarks.$endgroup$
– ielyamani
Jan 14 at 13:06
$begingroup$
@Carpsen90, I don't know Swift and there seem to be some subtleties around imports which both this question and the answer you reference brush under the table, but I compared a tweaked version of your code with my code on tio.run . Full tested code. I see user time: 12.470 s for your code and 7.002 s for mine. tio.run isn't ideal for benchmarking, but that's a significant improvement.
$endgroup$
– Peter Taylor
Jan 14 at 14:02
$begingroup$
@Carpsen90, I don't know Swift and there seem to be some subtleties around imports which both this question and the answer you reference brush under the table, but I compared a tweaked version of your code with my code on tio.run . Full tested code. I see user time: 12.470 s for your code and 7.002 s for mine. tio.run isn't ideal for benchmarking, but that's a significant improvement.
$endgroup$
– Peter Taylor
Jan 14 at 14:02
$begingroup$
(I suspect the problem is that you've benchmarked my code sieving three times as far as your code).
$endgroup$
– Peter Taylor
Jan 14 at 14:04
$begingroup$
(I suspect the problem is that you've benchmarked my code sieving three times as far as your code).
$endgroup$
– Peter Taylor
Jan 14 at 14:04
$begingroup$
The benchmarks were correct and can still be reproduced. You didn't mention in your answer this line
var composites = Array(repeating: false, count: n / 3 + 1)
, which makes all the difference. Here are the new benchmarks which favor your code.$endgroup$
– ielyamani
Jan 14 at 15:03
$begingroup$
The benchmarks were correct and can still be reproduced. You didn't mention in your answer this line
var composites = Array(repeating: false, count: n / 3 + 1)
, which makes all the difference. Here are the new benchmarks which favor your code.$endgroup$
– ielyamani
Jan 14 at 15:03
$begingroup$
The answer is intended to be a code review, not a patch.
$endgroup$
– Peter Taylor
Jan 14 at 15:27
$begingroup$
The answer is intended to be a code review, not a patch.
$endgroup$
– Peter Taylor
Jan 14 at 15:27
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211437%2ffaster-sieve-of-eratosthenes%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown