这个素数分解代码适用于较小的数字,但是对于大数字而言失败并出现OutOfMemoryException?

时间:2014-12-31 15:48:19

标签: f# primes ml

我试图获得大量的主要因素..

let factors (x:int64) =
  [1L..x]
  |> Seq.filter(fun n ->  x%n = 0L)

let isPrime (x:int64) = 
 factors x
 |> Seq.length = 2

let primeFactors (x:int64)= 
 factors x 
 |> Seq.filter isPrime

这适用于13195,但600851475143的OutOfMemoryException失败了?

很抱歉,如果我错过了一些明显的东西,那只是我在F#上的第三天,而且直到今天早上我还不知道最重要的因素是什么。

2 个答案:

答案 0 :(得分:5)

expresion [1L..x]会创建一个列表,在您的示例中,该列表太大而无法存储在内存中。

相反的序列是懒惰的,因此如果小心使用,您可以避免计算整个中间列表。您的代码已经使用了序列,但正如它在列表开头之前所说的那样,为了避免从列表转换,您可以使用大括号:{1L..x}

使用序列表达式是另一种选择:

let factors (x:int64) = seq {
    for i = 1L to x do
        if x%i = 0L then yield i}

解决了OutOfMemoryException问题后,你的素数函数非常慢,你可以按照评论中的建议优化它,在找到1和它的平方根之间的除数后立即返回false。进一步的优化可以通过将数字除以找到它们的素数因子并使用筛子作为素数来实现,您还可以查看一些有效的算法here

答案 1 :(得分:2)

表达式[...]创建指定项目的列表。在F#中,List可以这样定义:

type List<'t> = 
    | empty
    | item of 't * List<'t>

举个例子,`[1..5]'会变成这样的结构:

item(1, item(2, item(3, item(4, item(5, empty)))))

正如您所看到的,这对于少量项目来说不会有问题,但对于大量项目,这最终会耗尽所有可用内存并导致OutOfMemoryExcepion。正如Gustavo所提到的,为了避免这种情况,你可以使用一个序列,它将按需创建每个项目而不是一开始就创建所有项目。这样可以减少内存中的内容数量,从而避免使用OutOfMemoryException

由于您已经在使用Seq模块而不是List模块(即Seq.filter vs List.filter等),因此您只需使用序列而不是列表如下所示:{1L..x}