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
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
Related
I am solving the Permutational Primes Kata using Ruby. I manage to find out Brute-force solution but it exceeds the time limits. I need to optimize my code but I don't have any idea how to do this. The Kata.
require 'prime'
def permutational_primes(n_max, k_perms)
result_h = {}
result_keys = []
Prime.each(n_max) do |prime|
perms = prime.digits.permutation.to_a.map(&:join).map(&:to_i).uniq
prime_no_length = prime.to_s.length
perms = perms.delete_if { |el| el.to_s.length < prime_no_length }
# elimianate number greater than n_max
perms = perms.delete_if { |el| el > n_max }
next if (perms & result_keys).any?
perms = perms.delete_if { |el| !Prime.prime?(el) }
# minus one because we include
if perms.count - 1 == k_perms
result_h[prime] = perms
result_keys.append(prime)
end
end
return [0, 0, 0] if result_keys.empty?
[result_h.count, result_keys[0], result_keys[result_keys.count-1]]
end
Some low-hanging fruit:
Benchmarking is one way to understand what parts are more computationally expensive than others (likely Prime.prime?)
Find work that you're doing repeatedly or checks for information that you already know every Prime.each loop and cache it, trading memory for computation, e.g. Prime.prime?
All the common Enumerable methods create new Arrays. Instead, reuse existing arrays, e.g. map!
I have not yet thoroughly tested the following, but this general approach should speed things up considerably. There are two main elements that improved efficiency: use of the method Prime::each and maintaining a set of prime permutations already tested, to avoid unnecessary testing of duplicates.
require 'prime'
require 'set'
def permutational_primes(nMax, permutes)
skips = Set.new
enum = Prime.each
arr = []
while (prime = enum.next) < nMax
next if skips.include?(prime)
a = prime.digits.permutation.with_object([]) do |perm,a|
next if perm[-1].zero?
n = perm.reverse.join.to_i
if n < nMax && !skips.include?(n) && Prime.prime?(n)
skips << n
a << n
end
end
a.each { |n| skips << n }
next if a.size != permutes + 1
arr << a.min
end
[arr.size, arr.size.zero? ? 0 : arr.min, arr.size.zero? ? 0 : arr.max]
end
permutational_primes(1000, 3)
#=> [3, 149, 379]
This passes all tests but times out. I'm working on another optimization.
Explanation is under construction...
I am trying to solve a problem from http://www.beatmycode.com/challenge/5/take, and I wrote a script:
def is_prime?(num)
(2...num).each do |divisor|
return false if num % divisor == 0
end
true
end
def circular_prime(num)
circular_primes = []
if num < 2
return false
end
(2..num-1).each do |number|
is_prime?(number)
result = [number.to_s]
(0..number.to_s.size-2).each do |x|
var = result.last.split('')
result << var.unshift(var.pop).join if var.uniq.size != 1
end
circular_primes << result if result.all?{ |x| is_prime? x.to_i }
end
end
When I tested it with 10,100,1000, and 10_000, the script executed very fast, but when I tested with 100_000, the shell displayed an Interrupt error. Where is the weak point, and how can I fix it?
Your is_prime? method is too slow. Some minor improvement could be:
You don't have to test divisor all the way upto num, the square root of
num is enough.
You can skip all even numbers since 2 is the only even prime
number.
However, this is still not good enough because the algorithm is slow. Since you need to generate prime numbers among consecutive integers, consider using Sieve of Eratosthenes.
Of course there's prime standard library but I assume you want to do this manually.
This script's time complexity is O(n^2), so it's expected that it will take long time to finish for big input. Try using https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes to find primes and remembering which number is a prime in some array.
I came across a website called Project Euler and everything was going well until I hit the 3rd problem - The Largest Prime Factor. I don't want to use recursion to solve it. I saw solutions online where they use Math.sqrt and I don't want to use that either. Stubborn, I know.
I'd like to solve it with just loops and if statements. I assumed the input is an odd number. Here is my code. The output keeps coming out as [3] if num = 99 and I can't figure out why. I tried putting a puts statement everywhere to see what was being outputted at each step. One issue I realized was that that the array#p was not resetting after each loop. I tried array.clear but that wasn't much help. Could someone point me in the right direction? Is there some fundamental aspect about arrays, loops, and if-statements that I'm not getting?
def prime(num)
arr = []
p = []
not_p = []
# first I find all the numbers that num is divisible by
for i in (2..num/2)
if num % i == 0
arr << i
end
end # this should output [3, 9, 11, 33]
arr.each do |x| # I loop through each element in the above array
for i in (2..(x/2)) # I divide each element - x - by 2 because it cannot be divisble by anything greater than its half
if x % i == 0 # if x is divisble by i
not_p << i # I push the i into array#not_p
end # keep looping until i reaches x/2
end
if not_p.length == 0 # if there are no values in array#not_p, then I know x is a prime factor
p << x # so I push x into array#p
end
end
return p[-1] # returns the last element of the array, which is the largest
end
puts prime(99)
I'm not going to give you the full answer, as that would defeat the object of the practice with Project Euler.
However, you're almost on the right track with sorting out your problem. You don't want to look at the array p not being emptied, that should be collecting your primes. You do want to look at not_p though, since that is the array of divisors of each of your factors.
I hope this helps. Let me know if I can help any more.
Ah ok! Thanks for the suggestion philnash! In fact, I knew about that problem and tried to clear the array with Array.clear but that did not work. Instead, I just moved not_p = [] below the iteration arr.each do |x| and it worked! It makes sense because the not_p resets to [] when it moves on to the next element. Thanks so much for your help and for not providing the answer first! Here is my final, working solution =D
def prime(num)
arr = []
p = []
for i in (2..num / 2)
if num % i == 0
arr << i
end
end # this should output [3, 9, 11, 33]
arr.each do |x|
not_p = []
for i in (2..(x / 2))
if x % i == 0
not_p << i
end
end
if not_p.length == 0
p << x
end
end
return p[-1]
end
puts prime(99) # => 29
I am learning Ruby and doing some math stuff. One of the things I want to do is generate prime numbers.
I want to generate the first ten prime numbers and the first ten only. I have no problem testing a number to see if it is a prime number or not, but was wondering what the best way is to do generate these numbers?
I am using the following method to determine if the number is prime:
class Integer < Numeric
def is_prime?
return false if self <= 1
2.upto(Math.sqrt(self).to_i) do |x|
return false if self%x == 0
end
true
end
end
In Ruby 1.9 there is a Prime class you can use to generate prime numbers, or to test if a number is prime:
require 'prime'
Prime.take(10) #=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Prime.take_while {|p| p < 10 } #=> [2, 3, 5, 7]
Prime.prime?(19) #=> true
Prime implements the each method and includes the Enumerable module, so you can do all sorts of fun stuff like filtering, mapping, and so on.
If you'd like to do it yourself, then something like this could work:
class Integer < Numeric
def is_prime?
return false if self <= 1
2.upto(Math.sqrt(self).to_i) do |x|
return false if self%x == 0
end
true
end
def next_prime
n = self+1
n = n + 1 until n.is_prime?
n
end
end
Now to get the first 10 primes:
e = Enumerator.new do |y|
n = 2
loop do
y << n
n = n.next_prime
end
end
primes = e.take 10
require 'prime'
Prime.first(10) # => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Check out Sieve of Eratosthenes. This is not Ruby specific but it is an algorithm to generate prime numbers. The idea behind this algorithm is that you have a list/array of numbers say
2..1000
You grab the first number, 2. Go through the list and eliminate everything that is divisible by 2. You will be left with everything that is not divisible by 2 other than 2 itself (e.g. [2,3,5,7,9,11...999]
Go to the next number, 3. And again, eliminate everything that you can divide by 3. Keep going until you reach the last number and you will get an array of prime numbers. Hope that helps.
http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
People already mentioned the Prime class, which definitely would be the way to go. Someone also showed you how to use an Enumerator and I wanted to contribute a version using a Fiber (it uses your Integer#is_prime? method):
primes = Fiber.new do
Fiber.yield 2
value = 3
loop do
Fiber.yield value if value.is_prime?
value += 2
end
end
10.times { p primes.resume }
# First 10 Prime Numbers
number = 2
count = 1
while count < 10
j = 2
while j <= number
break if number%j == 0
j += 1
end
if j == number
puts number
count += 1
end
number += 1
end
Implemented the Sieve of Eratosthene (more or less)
def primes(size)
arr=(0..size).to_a
arr[0]=nil
arr[1]=nil
max=size
(size/2+1).times do |n|
if(arr[n]!=nil) then
cnt=2*n
while cnt <= max do
arr[cnt]=nil
cnt+=n
end
end
end
arr.compact!
end
Moreover here is a one-liner I like a lot
def primes_c a
p=[];(2..a).each{|n| p.any?{|l|n%l==0}?nil:p.push(n)};p
end
Of course those will find the primes in the first n numbers, not the first n primes, but I think an adaptation won't require much effort.
Here is a way to generate the prime numbers up to a "max" argument from scratch, without using Prime or Math. Let me know what you think.
def prime_test max
primes = []
(1..max).each {|num|
if
(2..num-1).all? {|denom| num%denom >0}
then
primes.push(num)
end
}
puts primes
end
prime_test #enter max
I think this may be an expensive solution for very large max numbers but seems to work well otherwise:
def multiples array
target = array.shift
array.map{|item| item if target % item == 0}.compact
end
def prime? number
reversed_range_array = *(2..number).reverse_each
multiples_of_number = multiples(reversed_range_array)
multiples_of_number.size == 0 ? true : false
end
def primes_in_range max_number
range_array = *(2..max_number)
range_array.map{|number| number if prime?(number)}.compact
end
class Numeric
def prime?
return self == 2 if self % 2 == 0
(3..Math.sqrt(self)).step(2) do |x|
return false if self % x == 0
end
true
end
end
With this, now 3.prime? returns true, and 6.prime? returns false.
Without going to the efforts to implement the sieve algorithm, time can still be saved quickly by only verifying divisibility until the square root, and skipping the odd numbers. Then, iterate through the numbers, checking for primeness.
Remember: human time > machine time.
I did this for a coding kata and used the Sieve of Eratosthenes.
puts "Up to which number should I look for prime numbers?"
number = $stdin.gets.chomp
n = number.to_i
array = (1..n).to_a
i = 0
while array[i]**2 < n
i = i + 1
array = array.select do |element|
element % array[i] != 0 || element / array[i] == 1
end
end
puts array.drop(1)
Ruby: Print N prime Numbers
http://mishra-vishal.blogspot.in/2013/07/include-math-def-printnprimenumbernoofp.html
include Math
def print_n_prime_number(no_of_primes=nil)
no_of_primes = 100 if no_of_primes.nil?
puts "1 \n2"
count = 1
number = 3
while count < no_of_primes
sq_rt_of_num = Math.sqrt(number)
number_divisible_by = 2
while number_divisible_by <= sq_rt_of_num
break if(number % number_divisible_by == 0)
number_divisible_by = number_divisible_by + 1
end
if number_divisible_by > sq_rt_of_num
puts number
count = count+1
end
number = number + 2
end
end
print_n_prime_number
Not related at all with the question itself, but FYI:
if someone doesn't want to keep generating prime numbers again and again (a.k.a. greedy resource saver)
or maybe you already know that you must to work with subsequent prime numbers in some way
other unknown and wonderful cases
Try with this snippet:
require 'prime'
for p in Prime::Generator23.new
# `p` brings subsequent prime numbers until the end of the days (or until your computer explodes)
# so here put your fabulous code
break if #.. I don't know, I suppose in some moment it should stop the loop
end
fp
If you need it, you also could use another more complex generators as Prime::TrialDivisionGenerator or Prime::EratosthenesGenerator. More info
Here's a super compact method that generates an array of primes with a single line of code.
def get_prime(up_to)
(2..up_to).select { |num| (2...num).all? { |div| (num % div).positive? } }
end
def get_prime(number)
(2..number).each do |no|
if (2..no-1).all? {|num| no % num > 0}
puts no
end
end
end
get_prime(100)
So this code will count the total number of pairs of numbers whose difference is K. it is naive method and I need to optimize it. suggestions?
test = $stdin.readlines
input = test[0].split(" ")
numbers = test[1].split(" ")
N = input[0]
K = input[1]
count = 0
for i in numbers
current = i.to_i
numbers.shift
for j in numbers
difference = (j.to_i - current).abs
if (difference == K)
count += 1
end
end
end
puts count
Would have been nice for you to give some examples of input and output, but I think this is correct.
require 'set'
def count_diff(numbers, difference)
set = Set.new numbers
set.inject 0 do |count, num|
set.include?(num+difference) ? count+1 : count
end
end
difference = gets.split[1].to_i
numbers = gets.split.map { |num| num.to_i }
puts count_diff(numbers, difference)
Untested, hopefully actual Ruby code
Documentation for Set: http://www.ruby-doc.org/stdlib/libdoc/set/rdoc/classes/Set.html
require 'set'
numbers_set = Set.new
npairs = 0
numbers.each do |number|
if numbers_set.include?(number + K)
npairs += 1
end
if numbers_set.include?(number - K)
npairs += 1
end
numbers_set.add(number)
end
Someone deleted his post, or his post was deleted... He had the best solution, here it is :
test = $stdin.readlines
input = test[0].split(" ")
numbers = test[1].split(" ")
K = input[1]
count = 0
numbers.combination(2){|couple| couple.inject(:-).abs == K ? count++}
puts count
You don't even need N.
I do not know Ruby so I'll just give you the big idea:
Get the list
Keep a boolean array (call it arr), marking off numbers as true if the number exists in the list
Loop through the list and see if arr[num-K] and/or arr[num+K] is true where num is a number in your list
This uses up quite a bit of memory though so another method is to do the following:
Keep a hash map from an integer n to an integer count
Go through your list, adding num+K and num-K to the hash map, incrementing count accordingly
Go through your list and see if num is in the hash map. If it is, increment your counter by count