Largest Prime Factor Ruby using Fermat's factorization method - ruby

I have this code that seems to be working for number 6-8 digits, in a normal time period.
When I enter bigger values the amount get ridiculously bug. It takes more than 4 hours to complete.
Here is my code.
#Fermat's factorization method
def get_largest_prime n
t=(Math.sqrt(n)+1).floor
k=0
prime_numbers=[]
while (t+k)<n
element = (t+k)**2-n
if is_integer? Math.sqrt(element)
#store prime numbers
prime_numbers << t+k+Math.sqrt(element)
prime_numbers << t+k-Math.sqrt(element)
#puts "Prime Factors of #{n} are: #{t+k+Math.sqrt(element)} and #{t+k-Math.sqrt(element)}"
end
k+=1
end
puts "Prime Factors: "+prime_numbers.to_s
end
#making sure 450.0 is 450, for example.
def is_integer? number
number.to_i == number ? true : false
end
get_largest_prime 600851475143
Running this will take more than 4 hours.
But running it for value ' 600851' for example or ' 60085167' does not take a lot of time. Any help ?

First note that Fermat factorisation doesn't give you prime factors in general.
Then, you run it until t+k >= n, that means you run the while loop n - t times, since t is roughly sqrt(n), that is an O(n) algorithm. For a largish n like 600851475143 (about 6*10^11), that is bound to take long.
You need to change the algorithm. When you have found a pair of divisors (both larger than 1), factorise them both recursively. If the smaller of the found factors is 1, that is a prime factor.
Doing that (forgive the bad style, I barely know ruby):
#Fermat's factorization method
def get_largest_prime n
t=(Math.sqrt(n)+1).floor
k=0
prime_numbers=[]
while (t+k)<n
element = (t+k)**2-n
if is_integer? Math.sqrt(element)
#store prime numbers
a = t+k+Math.sqrt(element)
b = t+k-Math.sqrt(element)
if b == 1
prime_numbers << a
break
end
prime_numbers += get_largest_prime a
prime_numbers += get_largest_prime b
break
#puts "Prime Factors of #{n} are: #{t+k+Math.sqrt(element)} and #{t+k-Math.sqrt(element)}"
end
k+=1
end
return prime_numbers
end
#making sure 450.0 is 450, for example.
def is_integer? number
number.to_i == number ? true : false
end
a = get_largest_prime 600851475143
puts "Prime Factors: "+a.to_s
solves the given problem quickly.
However, it will still take a long time for numbers that have no divisors close to the square root.
The standard factorisation by trial division has much better worst-case behaviour (O(sqrt(n) worst case). A mixed approach can be slightly faster than pure trial division, though.

Two effects here:
1) When an integer gets larger than 2**31 in Ruby, it uses a different, and slower, representation
2) There are no known factorisation algorithms that don't eventually perform badly once the number gets large enough - technically they all get slower worse than any polynomial of the (number of digits of) the number you want to factorise.
You could speed things up by using
Math.sqrt(element)
less. Assign result of it to a variable, before all the tests. Note this will not "fix" your problem. Ultimately it won't run fast enough above a certain number - even if you transferred everything to C (although you might squeeze out a couple of extra digits before C got slow)

Possibly, you can try the code below.
def prime_factor limit
(2..Math.sqrt(limit).to_i).inject([]) do |memo, var|
memo << var if limit % var == 0 and !memo.any? {|d| var % d == 0}
memo
end
end
prime_result = prime_factor 600851475143
puts prime_result.max

The less loops you use, the faster your code will run ;-) (less cpu cycles). Try to do everything recursively like here on this program that finds the largest prime factor

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.

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

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

Why does this code take 8 minutes to finish?

This is a (pretty bad) solution to one of the project Euler problems. The problem was to find the 10_001st prime number. The code below does it, but it takes 8 minutes to run. Can you explain why that is the case and how to optimize it?
primes = []
number = 2.0
until primes[10000] != nil
if (2..(number - 1)).any? do |n|
number % n == 0
end == false
primes << number
end
number = number + 1.0
end
puts primes[10000]
Some simple optimizations to prime finding:
Start by pushing 2 onto your primes list, and start by checking if 3 is a prime. (This eliminates needing to write special case code for the numbers 0 to 2)
You only have to check numbers that are odd for prime candidacy. (Or, if you start by adding 2/3/5 and checking 7, you only need to check numbers that are 1 or 5 after doing % 6. Or... You get the idea)
You only have to see if your current candidate x is divisible by factors up to sqrt(x)—because any factor above sqrt(x) divides x into a number below sqrt(x), and you've already checked all of those.
You only have to check numbers in your prime list, instead of all numbers, for divisors of x - since all composite numbers are divisible by primes. For example, 81 is 9*9 - but 9*9 is 3*3*9, 9 being composite, so you'll discover it's a prime when you check it against 3. Therefore you never need to test if 9 is a factor, and so on for every composite factor.
There are very optimized, sped up prime finding functions (see the Sieve of Atkin for a start), but these are the common optimizations that are easy to come up with.
Do you really have to check if the number divides with all previous numbers? Check only with the smaller primes you already discovered. Also, why using floats where integers are perfectly fine?
EDIT:
Some possible changes (not best algorithm, can be improved):
primes = [2, 3, 5]
num = 7
until primes[10000]
is_prime = true
i = 0
sqrtnum = Math.sqrt(num).ceil
while (n=primes[i+=1]) <= sqrtnum
if num % n == 0
is_prime = false
break
end
end
if is_prime
primes << num
end
num += 2
end
puts primes[10000]
On my computer (for 1000 primes):
Yours:
real 0m3.300s
user 0m3.284s
sys 0m0.000s
Mine:
real 0m0.045s
user 0m0.040s
sys 0m0.004s

Resources