Faster Sieve of EratosthenesPrime Number Generator in SwiftSieve of Eratosthenes - PythonSieve 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 SwiftPostponed Prime Sieve in SwiftMaximum performance for Pollard's P-1 functionFunctional Sieve of Eratosthenes in ClojureSieve of Eratosthenes in Rust

Hostile work environment after whistle-blowing on coworker and our boss. What do I do?

How to draw lines on a tikz-cd diagram

Anatomically Correct Strange Women In Ponds Distributing Swords

Is there a problem with hiding "forgot password" until it's needed?

What happens if you roll doubles 3 times then land on "Go to jail?"

Integer addition + constant, is it a group?

Why didn't Theresa May consult with Parliament before negotiating a deal with the EU?

Why Were Madagascar and New Zealand Discovered So Late?

Why escape if the_content isnt?

Balance Issues for a Custom Sorcerer Variant

Did Dumbledore lie to Harry about how long he had James Potter's invisibility cloak when he was examining it? If so, why?

Purchasing a ticket for someone else in another country?

How did Arya survive the stabbing?

Where does the Z80 processor start executing from?

What can we do to stop prior company from asking us questions?

Go Pregnant or Go Home

Why are there no referendums in the US?

CREATE opcode: what does it really do?

What does the word "Atten" mean?

Term for the "extreme-extension" version of a straw man fallacy?

Gears on left are inverse to gears on right?

Is `x >> pure y` equivalent to `liftM (const y) x`

How does Loki do this?

Short story about space worker geeks who zone out by 'listening' to radiation from stars



Faster Sieve of Eratosthenes


Prime Number Generator in SwiftSieve of Eratosthenes - PythonSieve 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 SwiftPostponed Prime Sieve in SwiftMaximum performance for Pollard's P-1 functionFunctional Sieve of Eratosthenes in ClojureSieve of Eratosthenes in Rust













2












$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 or 6X+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:



Attabench results




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.










share|improve this question











$endgroup$
















    2












    $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 or 6X+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:



    Attabench results




    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.










    share|improve this question











    $endgroup$














      2












      2








      2


      1



      $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 or 6X+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:



      Attabench results




      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.










      share|improve this question











      $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 or 6X+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:



      Attabench results




      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 3 mins ago







      ielyamani

















      asked Jan 13 at 21:33









      ielyamaniielyamani

      355213




      355213




















          1 Answer
          1






          active

          oldest

          votes


















          1












          $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.






          share|improve this answer









          $endgroup$












          • $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$
            (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 answer is intended to be a code review, not a patch.
            $endgroup$
            – Peter Taylor
            Jan 14 at 15:27










          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
          );



          );













          draft saved

          draft discarded


















          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









          1












          $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.






          share|improve this answer









          $endgroup$












          • $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$
            (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 answer is intended to be a code review, not a patch.
            $endgroup$
            – Peter Taylor
            Jan 14 at 15:27















          1












          $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.






          share|improve this answer









          $endgroup$












          • $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$
            (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 answer is intended to be a code review, not a patch.
            $endgroup$
            – Peter Taylor
            Jan 14 at 15:27













          1












          1








          1





          $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.






          share|improve this answer









          $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.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          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, 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$
            (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 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$
            @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 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$
          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

















          draft saved

          draft discarded
















































          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.




          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          बाताम इन्हें भी देखें सन्दर्भ दिक्चालन सूची1°05′00″N 104°02′0″E / 1.08333°N 104.03333°E / 1.08333; 104.033331°05′00″N 104°02′0″E / 1.08333°N 104.03333°E / 1.08333; 104.03333

          Why is the 'in' operator throwing an error with a string literal instead of logging false?Why can't I use switch statement on a String?Python join: why is it string.join(list) instead of list.join(string)?Multiline String Literal in C#Why does comparing strings using either '==' or 'is' sometimes produce a different result?How to initialize an array's length in javascript?How can I print literal curly-brace characters in python string and also use .format on it?Why does ++[[]][+[]]+[+[]] return the string “10”?Why is char[] preferred over String for passwords?Why does this code using random strings print “hello world”?jQuery.inArray(), how to use it right?

          How can we generalize the fact of finite dimensional vector space to an infinte dimensional case?$k[x]$-module and cyclic module over a finite dimensional vector spaceSubspace of a finite dimensional space is finite dimensionalIf V is an infinite-dimensional vector space, and S is an infinite-dimensional subspace of V, must the dimension of V/S be finite? ExplainWhy is an infinite dimensional space so different than a finite dimensional one?base for finite dimensional vector space is not infinite dimensional vector space?Any finite-dimensional vector space is the dual space of anotherHaving Trouble Understanding Meaning Of A Finite-Dimensional Vector SpaceProve that “Every subspaces of a finite-dimensional vector space is finite-dimensional”Ring as a finite dimensional Vector space over a field KQuestion regarding basis and dimension