使用费马分解方法的最大素数因子Ruby

时间:2013-04-05 14:11:28

标签: ruby algorithm

我有这个代码似乎适用于正常时间段内的6-8位数字。 当我输入更大的值时,数量会变得非常糟糕。完成需要4个多小时。 这是我的代码。

#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 

运行此操作需要4个多小时。

但是将它作为值'600851'或'60085167'运行并不需要花费很多时间。有什么帮助吗?

4 个答案:

答案 0 :(得分:2)

首先请注意,费马因子分解通常不会给出主要因素。

然后,您运行它直到t+k >= n,这意味着您运行while循环n - t次,因为t大致是sqrt(n),这是一个O(n)算法。对于较大的n如600851475143(约6 * 10 ^ 11),这必然需要很长时间。

您需要更改算法。当你找到一对除数(都大于1)时,将它们递归分解。如果找到的因子中较小的一个是1,那么这是一个主要因素。

这样做(原谅不好的风格,我几乎不知道红宝石):

#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

快速解决问题。

但是,对于没有除数接近平方根的数字,仍需要很长时间。

通过试验划分的标准因子分解具有更好的最坏情况行为(O(sqrt(n)最坏情况)。不过,混合方法可能比纯试验分区略快。

答案 1 :(得分:1)

这里有两个效果:

1)当Ruby中的整数大于2 ** 31时,它会使用不同且速度较慢的表示

2)一旦数量变得足够大,就没有已知的因子分解算法最终表现不佳 - 从技术上讲,它们都比你想要分解的数字(数字的位数)的任何多项式都慢得多。 / p>

您可以使用

加快速度
Math.sqrt(element)

以下。在所有测试之前,将结果分配给变量。请注意,这不会“修复”您的问题。最终它的运行速度不会超过一定数量 - 即使你将所有内容都转移到了C(尽管在C变慢之前你可能会挤出几个额外的数字)

答案 2 :(得分:0)

可能您可以尝试下面的代码。

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

答案 3 :(得分:0)

您使用的循环越少,代码运行的速度就越快;-)(减少cpu周期)。尝试像on this program that finds the largest prime factor

那样递归地完成所有事情