1

I want to do a sieve that doesn't take advantage of the obvious math hacks. I want to brute force it. My algorithm is conceived with the notion that the sieve does a lot of checking for what are not prime numbers and just returning the result of the operations to check those rather than to figure out what are prime numbers. I think some Carmichael Numbers prove it to be invalid for something very large. I could be wrong on that. I went on to check numbers from a range, and followed the basic algorithm given from Wikipedia.

def primes(n)
  nums = (2..n)
  not_prime = []
  primes = []
  nums.to_a.each_with_index do |it, idx|
      primes << it unless not_prime.include?(it)
      p primes.last
      p nums.step(primes.last).to_a
      nums.step(primes.last).each_with_index do |num, idx|
        next if idx == 0
        not_prime << num
      end
  end

  primes
end

When my range does the line:

nums.step(primes.last).each_with_index

for numbers other than the first one (2), I get an off-by-x error (compounding on the list I believe). For example, all the non prime two multiples are found, but for the multiples of three, the step on the range returns 2, 5, 8, 11, etc., which are off by one.

I'm trying to figure out a solution using Range objects or converting to an Array, but I like the conciseness of my (wrong) solution. Anyone think they can help me solve this?

EDIT:

I fixed it! The solution was creating an entirely new range to iterate over rather than taking the original range. See below. Shout out to Jörg W Mittag for the inspiration to just create a new range instead of trying to fiddle with the original immutable object which is what I was trying to do. Square peg in round hole sounds so much better sometimes.

def primes(n)
  nums = (2..n)
  not_prime = []
  primes = []
  nums.to_a.each_with_index do |it, idx|
      next if not_prime.include?(it)
      primes << it 
      ((primes.last)..n).step(primes.last).each_with_index do |num, idx|
        next if idx == 0 || num == primes.last
        not_prime << num
      end
  end

  primes
end
nobody
  • 7,803
  • 11
  • 56
  • 91
  • Another solution would be to just create my own custom data structure to house my Range object and perform operations on that but I like the artificial challenge of using stdlib items and primitives... – nobody Feb 19 '16 at 05:52
  • 1
    You iterate over the range `2..n` in steps of `3`, what else *could* that be other than `2, 5, 8, …`? – Jörg W Mittag Feb 19 '16 at 09:36
  • I get that is wrong. How can I fix the bug? – nobody Feb 19 '16 at 14:02
  • And I mean not that the implementation is wrong but that what I am stepping is wrong. Although, your comment inspired me! I fixed the algorithm by doing ``` ((primes.last)..n).step(primes.last).each_with_index ``` I edited my original answer with the solution. Thanks for the inspiration! – nobody Feb 19 '16 at 15:21
  • 2
    That was kind of the point ;-) I figured that prime numbers are not your company's core business but that you are rather doing this to learn, and what better way to learn than be inspired to figure out the solution yourself? – Jörg W Mittag Feb 19 '16 at 18:25

1 Answers1

0
def primes(n)
  nums = (2..n)
  not_prime = []
  primes = []
  nums.to_a.each_with_index do |it, idx|
      next if not_prime.include?(it)
      primes << it 
      ((primes.last)..n).step(primes.last).each_with_index do |num, idx|
        next if idx == 0 || num == primes.last
        not_prime << num
      end
  end

  primes
end
nobody
  • 7,803
  • 11
  • 56
  • 91