Haskell Eratosthenes 筛法和复合物列表
Haskell Sieve of Eratosthenes with list of composites
我要为一个项目实现Haskell中埃拉托色尼筛法的经典问题。我不必计算每个素数,而只需比较列表之间的数字。例如,我传递了一个潜在素数列表(参数 1)和一个复合素数列表(列表 2)。 sieve [2..10] []
结果与列表 [2,3,5,7]
.
我认为我非常接近并且它编译了,但是它将每个项目附加到主要列表而不是丢弃组合。我的想法是,它将采用所有数字 2..10
或其他任何数字的列表 x 和复合材料的列表 y 使用 elem
来查看列表 x 的头部是否在列表 y 中找到,如果是,则追加到列出 z 并打印。提前致谢!
目前我的代码 returns 第一个列表中的所有内容并且拒绝排序。 sieve [2..10] []
结果为 [2,3,4,5,6,7,8,9,10]
sieve ::[Int]->[Int]->[Int]
z = []
sieve [] [] = []
sieve x [] = x
sieve [] y = y
sieve xs ys = if ((elem (head xs)) ys) then (sieve (tail xs) ys)
else ((head xs):z)
你显示的程序没有多大意义,首先 sieve x []
将始终被使用,此外你应该检查一个元素是否可以被另一个列表整除。最后你应该使调用递归,这是你不使用 head xs : z
做的事情,因为 z
被定义为空列表。
让我们从基本情况开始:如果左边的列表是空的,不管第二个列表的内容如何,一个returns空列表。因为什么都不筛选就什么也得不到:
sieve [] _ = []
接下来我们寻找归纳案例,其模式为:
sieve (x:xs) ds = ...
现在我们需要枚举已找到元素的列表。从找到的元素any
可以整除x
的那一刻起,我们就知道这个数不是(相对)素数。此条件形式化为:
(==) 0 . mod x :: Integral b => b -> Bool
或遍历 ds
的列表:
any ((==) 0 . mod x) ds
如果存在这样的元素,我们就直接跳过这个元素,调用sieve xs ds
的归纳情况。
如果没有这样的元素,我们将它添加到 ds
的列表中并发出它。结果是:x : sieve xs (x:ds)
。因此,归纳情况是:
sieve (x:xs) ds | any ((==) 0 . mod x) ds = sieve xs ds
| otherwise = x : sieve xs (x:ds)
我们可以通过为 sieve xs
:
创建一个特定的变量来缩短它
sieve (x:xs) ds | any ((==) 0 . mod x) ds = rec ds
| otherwise = x : rec (x:ds)
where rec = sieve xs
完整的函数是:
sieve [] _ = []
sieve (x:xs) ds | any ((==) 0 . mod x) ds = rec ds
| otherwise = x : rec (x:ds)
where rec = sieve xs
您可以通过两种方式提高性能:
在ds
的末尾添加x
。这确实是一个更昂贵的操作。但是一段时间后,您不会经常添加数字。这很有趣,因为在那种情况下 ys
看起来像 [2,3,5,7,11]
而不是 [11,7,5,3,2]
。现在,一个数被 2
整除的几率 (50%) 大于一个数被 11
整除的几率 (9.9%)。最好先尝试最有可能成功的测试。
此外,您可以在除数达到要测试的数字的平方根后结束检查:如果一个数字不能被小于该数字的数字整除,则肯定不是能被大于平方根的数整除。
一种更有效的方法是:
sieve [] _ = []
sieve (x:xs) ds | any ((==) 0 . mod x) $ takeWhile (\y -> y*y <= x) ds = rec ds
| otherwise = x : rec (ds++[x])
where rec = sieve xs
你所说的sieve
通常被称为minus
,从第一个列表中减去第二个列表,假设两者都是有序的,增加数字列表.那么只比较两个 head 元素就足够了,不需要任何 elem
调用。
但如果您为 z
提供了正确的定义,它仍然可以工作。 z=[]
只是一个占位符,让它编译(对吧?);这不是正确的定义。应该是:
sieve :: [Int] -> [Int] -> [Int]
-- z = []
sieve [] [] = []
sieve x [] = x
sieve [] y = y
sieve xs ys = if ((elem (head xs)) ys) then (sieve (tail xs) z)
else ((head xs) : sieve (tail xs) ys )
where
z = ... -- need to remove (head xs) from ys
对于最后一条评论的任务,您可以使用例如delete
函数。
如果没有复合列表,这仍然不会为您生成素数列表,因此初始调用可以不会第二个列表为空(否则,您由于 sieve x [] = x
等式,d 得到与您相同的第一个参数:
primesAmong input = sieve input composites
但是 composites
是什么? Eratosthenes 的回答是,为什么,它们是质数的倍数!(试验部门说:复合物有其他质数作为它们的约数)。
给定一个质数,比如 2,我们只数:2,4,6,...;对于 3,比如说,它是 3,6,9,12,...;求它的倍数。让我们记下来:
composites = mutliplesOf primes
mutliplesOf primes = [ mult | p <- primes, mult <- [...] ]
这不太合适:这个 multiplesOf
需要一个参数:
primes = primesAmong input
primesAmong input = sieve input (mutliplesOf primes)
我们好像在追自己的尾巴;我们还没有 primes
;我们可以用什么代替?求 non-primes 的倍数和质数有什么坏处吗?
当你有了运行代码后,还是想办法使用primes
。
我要为一个项目实现Haskell中埃拉托色尼筛法的经典问题。我不必计算每个素数,而只需比较列表之间的数字。例如,我传递了一个潜在素数列表(参数 1)和一个复合素数列表(列表 2)。 sieve [2..10] []
结果与列表 [2,3,5,7]
.
我认为我非常接近并且它编译了,但是它将每个项目附加到主要列表而不是丢弃组合。我的想法是,它将采用所有数字 2..10
或其他任何数字的列表 x 和复合材料的列表 y 使用 elem
来查看列表 x 的头部是否在列表 y 中找到,如果是,则追加到列出 z 并打印。提前致谢!
目前我的代码 returns 第一个列表中的所有内容并且拒绝排序。 sieve [2..10] []
结果为 [2,3,4,5,6,7,8,9,10]
sieve ::[Int]->[Int]->[Int]
z = []
sieve [] [] = []
sieve x [] = x
sieve [] y = y
sieve xs ys = if ((elem (head xs)) ys) then (sieve (tail xs) ys)
else ((head xs):z)
你显示的程序没有多大意义,首先 sieve x []
将始终被使用,此外你应该检查一个元素是否可以被另一个列表整除。最后你应该使调用递归,这是你不使用 head xs : z
做的事情,因为 z
被定义为空列表。
让我们从基本情况开始:如果左边的列表是空的,不管第二个列表的内容如何,一个returns空列表。因为什么都不筛选就什么也得不到:
sieve [] _ = []
接下来我们寻找归纳案例,其模式为:
sieve (x:xs) ds = ...
现在我们需要枚举已找到元素的列表。从找到的元素any
可以整除x
的那一刻起,我们就知道这个数不是(相对)素数。此条件形式化为:
(==) 0 . mod x :: Integral b => b -> Bool
或遍历 ds
的列表:
any ((==) 0 . mod x) ds
如果存在这样的元素,我们就直接跳过这个元素,调用sieve xs ds
的归纳情况。
如果没有这样的元素,我们将它添加到 ds
的列表中并发出它。结果是:x : sieve xs (x:ds)
。因此,归纳情况是:
sieve (x:xs) ds | any ((==) 0 . mod x) ds = sieve xs ds
| otherwise = x : sieve xs (x:ds)
我们可以通过为 sieve xs
:
sieve (x:xs) ds | any ((==) 0 . mod x) ds = rec ds
| otherwise = x : rec (x:ds)
where rec = sieve xs
完整的函数是:
sieve [] _ = []
sieve (x:xs) ds | any ((==) 0 . mod x) ds = rec ds
| otherwise = x : rec (x:ds)
where rec = sieve xs
您可以通过两种方式提高性能:
在
ds
的末尾添加x
。这确实是一个更昂贵的操作。但是一段时间后,您不会经常添加数字。这很有趣,因为在那种情况下ys
看起来像[2,3,5,7,11]
而不是[11,7,5,3,2]
。现在,一个数被2
整除的几率 (50%) 大于一个数被11
整除的几率 (9.9%)。最好先尝试最有可能成功的测试。此外,您可以在除数达到要测试的数字的平方根后结束检查:如果一个数字不能被小于该数字的数字整除,则肯定不是能被大于平方根的数整除。
一种更有效的方法是:
sieve [] _ = []
sieve (x:xs) ds | any ((==) 0 . mod x) $ takeWhile (\y -> y*y <= x) ds = rec ds
| otherwise = x : rec (ds++[x])
where rec = sieve xs
你所说的sieve
通常被称为minus
,从第一个列表中减去第二个列表,假设两者都是有序的,增加数字列表.那么只比较两个 head 元素就足够了,不需要任何 elem
调用。
但如果您为 z
提供了正确的定义,它仍然可以工作。 z=[]
只是一个占位符,让它编译(对吧?);这不是正确的定义。应该是:
sieve :: [Int] -> [Int] -> [Int]
-- z = []
sieve [] [] = []
sieve x [] = x
sieve [] y = y
sieve xs ys = if ((elem (head xs)) ys) then (sieve (tail xs) z)
else ((head xs) : sieve (tail xs) ys )
where
z = ... -- need to remove (head xs) from ys
对于最后一条评论的任务,您可以使用例如delete
函数。
如果没有复合列表,这仍然不会为您生成素数列表,因此初始调用可以不会第二个列表为空(否则,您由于 sieve x [] = x
等式,d 得到与您相同的第一个参数:
primesAmong input = sieve input composites
但是 composites
是什么? Eratosthenes 的回答是,为什么,它们是质数的倍数!(试验部门说:复合物有其他质数作为它们的约数)。
给定一个质数,比如 2,我们只数:2,4,6,...;对于 3,比如说,它是 3,6,9,12,...;求它的倍数。让我们记下来:
composites = mutliplesOf primes
mutliplesOf primes = [ mult | p <- primes, mult <- [...] ]
这不太合适:这个 multiplesOf
需要一个参数:
primes = primesAmong input
primesAmong input = sieve input (mutliplesOf primes)
我们好像在追自己的尾巴;我们还没有 primes
;我们可以用什么代替?求 non-primes 的倍数和质数有什么坏处吗?
当你有了运行代码后,还是想办法使用primes
。