Why is my Ruby code for Project Euler #10 so slow? - ruby

I am relatively new to Ruby but it seems simple enough as far as a language goes. I am working through the Euler Project with Ruby and I'm having a huge issue with speed on the following:
The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
Find the sum of all the primes below two million.
My code:
beginning_time = Time.now
(1..10000).each { |i| i }
def isPrime(num)
factors = 0
primecount = 1
while primecount <= num
if (num%primecount == 0)
factors += 1
end
if (factors > 2)
return false
end
primecount += 1
end
return true
end
def make_sieve(num)
sieve = Array.new(num)
summation = 0
for i in 1..num
if(isPrime(i) == true)
summation += i
puts i
for x in i..num
if x%i == 0
# Go through entire array and make all multiples of i False
sieve[x] = false
else
sieve[i] = true
end
end
else
# If i is NOT prime, move to the next number. in the For Loop
next
end
end
puts summation
end
make_sieve(2000000)
end_time = Time.now
puts "Time elapsed #{(end_time - beginning_time)*1000} milliseconds"
I think I have the right idea with the sieve but I really have no clue what's going on that makes this program run so slow. I run it with 20,000 and it takes about 15 seconds, which seems slow even still, although the output comes out MUCH faster than when I put 2,000,000.
Am I going about this the wrong way logically or syntactically or both?

Your isPrime() test is very slow on primes; but you don't even need it. The key to sieve is, initially all the numbers are marked as prime; then for each prime we mark off all its multiples. So when we get to a certain entry in the sieve, we already know whether it is a prime or not - whether it is marked true for being prime, or it is marked false for being composite (a multiple of some smaller prime).
There is no need to test it being prime, at all.
And to find the multiples, we just count: for 5, it's each 5th entry after it; for 7 - each 7th. No need to test them with % operator, just set to false right away. No need to set any of them to true, because all numbers were set to true at the start.

You seem to be writing JavaScript code in Ruby, and are missing the subtleties that makes Ruby so elegant. You should take a look at something like Ruby Best Practices, which is quite a light read but deals with using Ruby idioms instead of imposing the concepts of another language.
As has been said, the whole point of an Eratosthenes sieve is that you just remove all compound numbers from a list, leaving just the primes. There is no need to check each element for primeness.
This is a Rubyish solution. It runs in about 1.5 seconds. It is a little complicated by the representing number N by array element N-1, so (i+i+1 .. num).step(i+1) is equivalent to (n * 2 .. num).step(n)
def make_sieve(num)
sieve = Array.new(num, true)
sieve.each_with_index do |is_prime, i|
next if i == 0 or not is_prime
(i+i+1 .. num).step(i+1) { |i| sieve[i] = false }
end
puts sieve.each_index.select { |i| sieve[i] }.map { |i| i+1 }.inject(:+)
end
make_sieve(2_000_000)
output
142913828923

Related

Code Optimization - Generating Prime Numbers

I am trying to write a code for the following problem:
Input
The input begins with the number t of test cases in a single line (t<=10). In each of the next t lines there are two numbers m and n (1 <= m <= n <= 1000000000, n-m<=100000) separated by a space.
Output
For every test case print all prime numbers p such that m <= p <= n, one number per line, test cases separated by an empty line.
Sample Input:
2
1 10
3 5
Sample Output:
2
3
5
7
3
5
My code:
def prime?(number)
return false if number == 1
(2..number-1).each do |n|
return false if number % n == 0
end
true
end
t = gets.strip.to_i
for i in 1..t
mi, ni = gets.strip.split(' ')
mi = mi.to_i
ni = ni.to_i
i = mi
while i <= ni
puts i if prime?(i)
i += 1
end
puts "\n"
end
The code is running fine, only problem I am having is that it is taking a lot of time when run against big input ranges as compared to other programming languages.
Am I doing something wrong here? Can this code be further optimized for faster runtime?
I have tried using a for loop, normal loop, creating an array and then printing it.
Any suggestions.
Ruby is slower than some other languages, depending on what language you compare it to; certainly slower than C/C++. But your problem is not the language (although it influences the run-time behavior), but your way of finding primes. There are many better algorithms for finding primes, such as the Sieve of Eratosthenes or the Sieve of Atkin. You might also read the “Generating Primes” page on Wikipedia and follow the links there.
By the way, for the Sieve of Eratosthenes, there is even a ready-to-use piece of code on Stackoverflow. I'm sure a little bit of googling will turn up implementations for other algorithms, too.
Since your problem is finding primes within a certain range, this is the Sieve of Eratosthenes code found at the above link modified to suit your particular problem:
def better_sieve_upto(first, last)
sieve = [nil, nil] + (2..last).to_a
sieve.each do |i|
next unless i
break if i*i > last
(i*i).step(last, i) {|j| sieve[j] = nil }
end
sieve.reject {|i| !i || i < first}
end
Note the change from "sieve.compact" to a complexer "sieve.reject" with a corresponding condition.
Return true if the number is 2, false if the number is evenly divisible by 2.
Start iterating at 3, instead of 2. Use a step of two.
Iterate up to the square root of the number, instead of the number minus one.
def prime?(number)
return true if number == 2
return false if number <= 1 or number % 2 == 0
(3..Math.sqrt(number)).step(2) do |n|
return false if number % n == 0
end
true
end
This will be much faster, but still not very fast, as #Technation explains.
Here's how to do it using the Sieve of Eratosthenes built into Ruby. You'll need to precompute all the primes up to the maximum maximum, which will be very quick, and then select the primes that fall within each range.
require 'prime'
ranges = Array.new(gets.strip.to_i) do
min, max = gets.strip.split.map(&:to_i)
Range.new(min, max)
end
primes = Prime.each(ranges.map(&:max).max, Prime::EratosthenesGenerator.new)
ranges.each do |range|
primes.each do |prime|
next if prime < range.min
break if prime > range.max
puts prime
end
primes.rewind
puts "\n"
end
Here's how the various solutions perform with the range 50000 200000:
Your original prime? function: 1m49.639s
My modified prime? function: 0m0.687s
Prime::EratosthenesGenerator: 0m0.221s
The more ranges being processed, the faster the Prime::EratosthenesGenerator method should be.

Why is my ruby script execution too long?

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.

How to create a method that returns the nth prime number?

I'm trying to write a method that returns the nth prime number.
I've worked out a solution but the problem is in my method. I create a large array of numbers that seems to process super slow. (1..104729).to_a to be exact. I chose 104729 because the max n can be is 10000 and the 10000th integer is 104729. I'm looking for a way to optimize my method.
Is 104729 is too large a value? Is there a way to write this so that I'm not creating a large array?
Here's the method:
def PrimeMover(num)
def is_prime(x)
i = 0
nums = (2..x).to_a
while nums[i] < nums.max
if x % nums[i] != 0
i += 1
else
return false
end
end
return true
end
primes_arr = (3..104729).to_a.select {|y| is_prime(y)}
primes_arr[num]
end
require "prime"
def find_prime(nth)
Prime.take(nth).last
end
Combine Ruby's built-in prime library, and a lazy enumerator for performance:
require 'prime'
(1...100_000).lazy.select(&:prime?).take(100).to_a
Or simply, as highlighted by Arturo:
Prime.take(100)
You can use Ruby's built in #prime? method, which seems pretty efficient.
The code:
require 'prime'
primes_arr = (3..104729).to_a.select &:prime?
runs in 2-3 seconds on my machine, which I find somewhat acceptable.
If you need even better performance or if you really need to write your own method, try implementing the Sieve of Erathostenes. Here are some Ruby samples of that: http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Ruby
Here's an optimal a trial division implementation of is_prime without relying on the Prime class:
A prime number is a whole number divisible only by 1 and itself, and 1 is not prime. So we want to know if x divides into anything less than x and greater than 1. So we start the count at 2, and we end at x - 1.
def prime?(x)
return false if x < 2
2.upto(x - 1) do |n|
return false if (x % n).zero?
end
true
end
As soon as x % n has a remainder, we can break the loop and say this number is not prime. This saves you from looping over the entire range. If all the possible numbers were exhausted, we know the number is prime.
This is still not optimal. For that you would need a sieve, or a different detection algorithm to trial division. But it's a big improvement on your code. Taking the nth up to you.

Slow Ruby computation? Project Euler #5

This question references Project Euler Problem 5, so beware of spoilers!
Problem 5:
2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder. What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
I wrote the following code in Ruby as a solution to Problem 5.
num = 2520
until (1..20).all?{|x| num % x == 0}
num += 1
end
puts "#{num}"
However, whenever I run the script, it just hangs. Note that I tested the same method on the base case 2520 for the range 1 to 10 and it worked just fine.
Why does it work for the simpler case but not for the more advanced case? What can I do to fix what I have?
It's slow because the answer is more than 200 million, and you're counting up to it in steps of 1. That's going to take a while. You need a better algorithm.
You won't be able to brute force this problem as you have with others. You're going to need to find a more efficient solution for it.
SPOILER BELOW
This is a significantly more efficient way to do it (apologies if this isn't very Ruby-like):
def find_multiple
lcm = 1
(2..20).each do |i|
lcm *= i / gcd(lcm, i)
end
lcm
end
def gcd(a, b)
while b > 0
a %= b
return b if a == 0
b %= a
end
a
end
puts find_multiple
If you're looking for a more Ruby-like way to solve it, you can use the following (as suggested by steenslag in the comments):
(1..20).inject(:lcm)
A little late to the game but here's my input. If you like your code - which is succinct and pretty clear - you can make a couple of small adjustments to make it run faster. This worked for me without timing out:
num = 20
until (11..20).all?{ |i| num % i == 0 }
num +=20
end
puts num
Essentially you just increment by 20s since you know it needs to be divisible by 20, and you can skip iterating through anything in the lower 1/2 of the set.
Simplest and clean solution in ruby language.
(1..20).inject(:lcm) # output will be 232792560
Try this.
Code:
i=2520
max_product = (4..19).inject(1){|j,k| j*k}
puts max_product
while i < max_product
if( [3, 7].inject(true) do |memo, p|
memo && i%p==0
end)
if(
(4..20).inject(true) do |memo, p|
memo && i%p==0
end
)
puts i
end
end
i+=10
end

How can I test if a value is a prime number in Ruby? Both the easy and the hard way?

I am trying to create a program that will test whether a value is prime, but I don't know how. This is my code:
class DetermineIfPrime
def initialize (nth_value)
#nth_value = nth_value
primetest
end
def primetest
if Prime.prime?(#nth_value)
puts ("#{#nth_value} is prime")
else
puts ("This is not a prime number.")
end
rescue Exception
puts ("#{$!.class}")
puts ("#{$!}")
end
end
And every time I run that it returns this.
NameError
uninitialized constant DetermineIfPrime::Prime
I tried other ways to do the job, but I think this is the closest I can get.
I also tried this:
class DetermineIfPrime
def initialize (nth_value)
#nth_value = nth_value
primetest
end
def primetest
for test_value in [2, 3, 5, 7, 9, 11, 13] do
if (#nth_value % test_value) == 0
puts ("#{#nth_value} is not divisible by #{test_value}")
else
puts ("This is not a prime number since this is divisible by #{test_value}")
break
end
end
end
end
Or am I just doing something wrong?
Ruby has built in method to check if number is prime or not.
require 'prime'
Prime.prime?(2) #=> true
Prime.prime?(4) #=> false
def is_prime?(num)
return false if num <= 1
Math.sqrt(num).to_i.downto(2).each {|i| return false if num % i == 0}
true
end
First, we check for 0 and 1, as they're not prime. Then we basically just check every number less than num to see if it divides. However, as explained here, for every factor greater than the square root of num, there's one that's less, so we only look between 2 and the square root.
Update
def is_prime?(num)
return if num <= 1
(2..Math.sqrt(num)).none? { |i| (num % i).zero? }
end
The error you are getting is because you haven't required Primein your code, You need to do require Prime in your file.
One cool way I found here, to check whether a number is prime or not is following:
class Fixnum
def prime?
('1' * self) !~ /^1?$|^(11+?)\1+$/
end
end
10.prime?
From an algorithmic standpoint, checking if a number is prime can be done by checking all numbers up to and including (rounding down to previous integer) said number's square root.
For example, checking if 100 is prime involves checking everything up to 10.
Checking 99 means only going to 9.
** Another way to think about it **
Each factor has a pair (3 is a factor of 36, and 3's pair is 12).
The pair is on the other side of the square root (square root of 6 is 36, 3 < 6, 12 > 6).
So by checking everything until the square root (and not going over) ensures you check all possible factors.
You can make it quicker by having a list of prime numbers to compare, as you are doing. If you have a maximum limit that's reasonably small, you could just have a list of primes and do a direct lookup to see if that number is prime.
def is_prime?(num)
Math.sqrt(num).floor.downto(2).each {|i| return false if num % i == 0}
true
end
lol sorry for resurrecting a super old questions, but it's the first one that came up in google.
Basically, it loops through possible divisors, using the square root as the max number to check to save time on very large numbers.
In response to your question, while you can approach the problem by using Ruby's Prime I am going to write code to answer it on its own.
Consider that all you need to do is determine a factor that is smaller than the integer's square root. Any number larger than the integer's square root as a factor requires a second factor to render the number as the product. (e.g. square root of 15 is approx 3.8 so if you find 5 as a factor it is only a factor with the factor pair 3 and 5!!)
def isPrime?(num)
(2..Math.sqrt(num)).each { |i| return false if num % i == 0}
true
end
Hope that helps!!
(To first answer the question: yes, you are doing something wrong. As BLUEPIXY mentions, you need to put require 'prime' somewhere above the line that calls Prime.prime?. Typically on line 1.)
Now, a lot of answers have been given that don't use Prime.prime?, and I thought it might be interesting to benchmark some of them, along with a possible improvement of my own that I had in mind.
###TL;DR
I benchmarked several solutions, including a couple of my own; using a while loop and skipping even numbers performs best.
Methods tested
Here are the methods I used from the answers:
require 'prime'
def prime1?(num)
return if num <= 1
(2..Math.sqrt(num)).none? { |i| (num % i).zero? }
end
def prime2?(num)
return false if num <= 1
Math.sqrt(num).to_i.downto(2) {|i| return false if num % i == 0}
true
end
def prime3?(num)
Prime.prime?(num)
end
def prime4?(num)
('1' * num) !~ /^1?$|^(11+?)\1+$/
end
prime1? is AndreiMotinga's updated version. prime2? is his original version (with the superfluous each method removed). prime3? is Reboot's, using prime library. prime4? is Saurabh's regex version (minus the Fixnum monkey-patch).
A couple more methods to test
The improvement I had in mind was to leverage the fact that even numbers can't be prime, and leave them out of the iteration loop. So, this method uses the #step method to iterate over only odd numbers, starting with 3:
def prime5?(num)
return true if num == 2
return false if num <= 1 || num.even?
3.step(Math.sqrt(num).floor, 2) { |i| return false if (num % i).zero? }
true
end
I thought as well that it might be interesting to see how a "primitive" implementation of the same algorithm, using a while loop, might perform. So, here's one:
def prime6?(num)
return true if num == 2
return false if num <= 1 || num.even?
i = 3
top = Math.sqrt(num).floor
loop do
return false if (num % i).zero?
i += 2
break if i > top
end
true
end
Benchmarks
I did a simple benchmark on each of these, timing a call to each method with the prime number 67,280,421,310,721. For example:
start = Time.now
prime1? 67280421310721
puts "prime1? #{Time.now - start}"
start = Time.now
prime2? 67280421310721
puts "prime2? #{Time.now - start}"
# etc.
As I suspected I would have to do, I canceled prime4? after about 60 seconds. Presumably, it takes quite a bit longer than 60 seconds to assign north of 6.7 trillion '1''s to memory, and then apply a regex filter to the result — assuming it's possible on a given machine to allocate the necessary memory in the first place. (On mine, it would seem that there isn't: I went into irb, put in '1' * 67280421310721, made and ate dinner, came back to the computer, and found Killed: 9 as the response. That looks like a SignalException raised when the process got killed.)
The other results are:
prime1? 3.085434
prime2? 1.149405
prime3? 1.236517
prime5? 0.748564
prime6? 0.377235
Some (tentative) conclusions
I suppose that isn't really surprising that the primitive solution with the while loop is fastest, since it's probably closer than the others to what's going on under the hood. It is a bit surprising that it's three times faster than Prime.prime?, though. (After looking at the source code in the doc it is less so. There are lots of bells and whistles in the Prime object.)
AndreiMotinga's updated version is nearly three times as slow as his original, which suggests that the #none? method isn't much of a performer, at least in this context.
Finally, the regex version might be cool, but it certainly doesn't appear to have much practical value, and using it in a monkey-patch of a core class looks like something to avoid entirely.
If you are going to use any Prime functions you must include the Prime library. This problem can be solved without the use of the prime library however.
def isPrime?(num)
(2..Math.sqrt(num)).each { |i|
if num % i == 0 && i < num
return false
end
}
true
end
Something like this would work.
Try this
def prime?(num)
2.upto(Math.sqrt(num).ceil) do |i|
break if num%i==0
return true if i==Math.sqrt(num).ceil
end
return false
end
So most of the answers here are doing the same thing in slightly different ways which is one of the cool things about Ruby, but I'm a pretty new student (which is why I was looking this up in the first place) and so here's my version with comment explanations in the code:
def isprime n # starting with 2 because testing for a prime means you don't want to test division by 1
2.upto(Math.sqrt(n)) do |x| # testing up to the square root of the number because going past there is excessive
if n % x == 0
# n is the number being called from the program
# x is the number we're dividing by, counting from 2 up to the square root of the number
return false # this means the number is not prime
else
return true # this means the number is prime
end
end
end

Resources