This is the first thing I'd look at:
while (i < num/2)
You only need to go up to the square root of a number to work out all its factors. Pseudo-code would be something like:
factors = []
i = 1
while i * i <= num:
if num % i == 0:
factors.push(i)
factors.push(num/i)
i++
(assuming you still want to do it that way - see below).
However, there's absolutely no need to store all these factors then look for the highest prime.
Since you're finding the factors in ascending order, you can also find them at the same time in descending order, using the "trick" in that second factors.push()
call above - if i
is a factor of num
, then so is num / i
.
So you can use the same loop to exit early if the prime factor is above the square root (because those are being found in descending order, the first one found is the highest).
Otherwise keep going until you reach the square root and get the highest found to date (you need the last one in that case since you're searching in ascending order).
The code for this would be something like:
require 'prime'
def highestprime num
i = 1
large = -1
while (i * i <= num)
if (num % i == 0)
if ((num / i).prime?)
return num / i
end
if (i.prime?)
large = i
end
end
i = i + 1
end
return large
end
puts highestprime 999999999
which returns the result 333667
in well under a second:
pax$ time ruby testprog.rb
333667
real 0m0.160s
user 0m0.031s
sys 0m0.124s
That's about 350 times faster than your original 55-second solution, hopefully that'll be fast enough for you :-)
Or even faster if you take out the process startup/shutdown costs with:
require 'benchmark'
Benchmark.bm do |xyzzy|
xyzzy.report {highestprime 999999999}
end
which gives:
user system total real
0.000000 0.000000 0.000000 ( 0.000316)