我是Haskell的新手。
如何生成一个包含下一个整数的质因数的列表?
目前,我只知道如何生成质数:
primes = map head $ iterate (\(x:xs) -> [y | y<-xs, y `mod` x /= 0 ]) [2..]
我是Haskell的新手。
如何生成一个包含下一个整数的质因数的列表?
目前,我只知道如何生成质数:
primes = map head $ iterate (\(x:xs) -> [y | y<-xs, y `mod` x /= 0 ]) [2..]
确定一个正整数 n
的质因数的简单方法是:
[2..n-1]
中查找第一个除数 d
d
:返回 d : primeFactors(div n d)
n
(因为 n
是质数)代码:
prime_factors :: Int -> [Int]
prime_factors 1 = []
prime_factors n
| factors == [] = [n]
| otherwise = factors ++ prime_factors (n `div` (head factors))
where factors = take 1 $ filter (\x -> (n `mod` x) == 0) [2 .. n-1]
显然,这可以进行大量优化(仅从2到sqrt(N)搜索,缓存迄今为止找到的质数,并仅针对这些计算除法等)。
更新
稍微修改后的版本使用了case(如@user5402所建议的):
prime_factors n =
case factors of
[] -> [n]
_ -> factors ++ prime_factors (n `div` (head factors))
where factors = take 1 $ filter (\x -> (n `mod` x) == 0) [2 .. n-1]
foo == []
在 foo
的类型中引入了一个 Eq
约束(实际上在这里不需要),而 case foo of [] -> ...
则没有引入约束。 - d8d0d65b3f7cf42null factors
,而不是 factors == []
。 - bheklilr在除数 m
小于 2 之前,
n
。n
除以 m
。n
,并回到第二步。 实际使用的所有除数列表是原始 m
的质因数。
代码:
-- | prime factors
--
-- >>> factors 13
-- [13]
-- >>> factors 16
-- [2,2,2,2]
-- >>> factors 60
-- [2,2,3,5]
--
factors :: Int -> [Int]
factors m = f m (head primes) (tail primes) where
f m n ns
| m < 2 = []
| m `mod` n == 0 = n : f (m `div` n) n ns
| otherwise = f m (head ns) (tail ns)
-- | primes
--
-- >>> take 10 primes
-- [2,3,5,7,11,13,17,19,23,29]
--
primes :: [Int]
primes = f [2..] where f (p : ns) = p : f [n | n <- ns, n `mod` p /= 0]
更新:
这段替换代码通过避免不必要的评估来提高性能:
factors m = f m (head primes) (tail primes) where
f m n ns
| m < 2 = []
| m < n ^ 2 = [m] -- stop early
| m `mod` n == 0 = n : f (m `div` n) n ns
| otherwise = f m (head ns) (tail ns)
primes
也可以大大加速,如Will Ness的评论中所述:
primes = 2 : filter (\n-> head (factors n) == n) [3,5..]
factors
但是 primes
的速度仍然太慢了。将你的定义速度与 2:filter (\n-> head (factors n) == ......
进行比较(完成定义)。 :) 你能找到速度差异的原因吗?另请参见 "empirical orders of growth"。 - Will Nessprimes = 2:filter(\ n-> head(factors n)== n)[3,5 ..]
。 :) - Will Ness这是一个表现优异且易于理解的实现,其中 isPrime
和 primes
递归地定义,并且默认情况下会进行缓存。 primeFactors
的定义只是对 primes
的合理使用,结果将包含连续重复的数字,这个特性使得可以通过 (map (head &&& length) . group)
计算每个因子的数量,并且还能够通过 (map head . group)
进行去重:
isPrime :: Int -> Bool
primes :: [Int]
isPrime n | n < 2 = False
isPrime n = all (\p -> n `mod` p /= 0) . takeWhile ((<= n) . (^ 2)) $ primes
primes = 2 : filter isPrime [3..]
primeFactors :: Int -> [Int]
primeFactors n = iter n primes where
iter n (p:_) | n < p^2 = [n | n > 1]
iter n ps@(p:ps') =
let (d, r) = n `divMod` p
in if r == 0 then p : iter d ps else iter n ps'
使用方法:
> import Data.List
> import Control.Arrow
> primeFactors 12312
[2,2,2,3,3,3,3,19]
> (map (head &&& length) . group) (primeFactors 12312)
[(2,3),(3,4),(19,1)]
> (map head . group) (primeFactors 12312)
[2,3,19]
factors n = [x | x <- [1..n], mod n x == 0]
isPrime n = factors n == [1,n]
prime_factors num = [(last $ takeWhile (\n -> (x^n) `elem` (factors num)) [1..], x) | x <- filter isPrime $ factors num]
在哪里
x <- filter isPrime $ factors num
last $ takeWhile (\n -> (x^n) `elem` (factors num)) [1..]
> prime_factors 36 -- 36 = 4 * 9
[(2,2),(2,3)]
> prime_factors 1800 -- 1800 = 8 * 9 * 25
[(3,2),(2,3),(2,5)]
首先,让我们创建一个帮助函数,它可以尽可能地将一个数字除以另一个数字。一旦我们找到一个因子,我们将需要它来完全从数字中消除它。
import Data.Maybe (mapMaybe)
-- Divide the first argument as many times as possible by the second one.
divFully :: Integer -> Integer -> Integer
divFully n q | n `mod` q == 0 = divFully (n `div` q) q
| otherwise = n
-- | A lazy infinite list of non-trivial factors of all numbers.
factors :: [(Integer, [Integer])]
factors = (1, []) : (2, [2]) : map (\n -> (n, divisors primes n)) [3..]
where
divisors :: [Integer] -> Integer -> [Integer]
divisors _ 1 = [] -- no more divisors
divisors (p:ps) n
| p^2 > n = [n] -- no more divisors, `n` must be prime
| n' < n = p : divisors ps n' -- divides
| otherwise = divisors ps n' -- doesn't divide
where
n' = divFully n p
相反地,当我们拥有所有数字因子的列表时,很容易找到质数:它们恰好是那些唯一的质数因子是自身的数字。
-- | A lazy infinite list of primes.
primes :: [Integer]
primes = mapMaybe isPrime factors
where
-- | A number is prime if it's only prime factor is the number itself.
isPrime (n, [p]) | n == p = Just p
isPrime _ = Nothing
[3]
。由此,我们可以计算出3是另一个质数。等等。factors' :: Integral t => t -> [t]
factors' n
| n < 0 = factors' (-n)
| n > 0 = if 1 == n
then []
else let fac = mfac n 2 in fac : factors' (n `div` fac)
where mfac m x
| rem m x == 0 = x
| x * x > m = m
| otherwise = mfac m (if odd x then x + 2 else x + 1)
let fac = mfac n 2 in fac : factors' (n `div` fac)
这种写法不够优化,总是从2开始,可以从之前的 fac
开始。 - Will Nessimport Data.List
factor :: Int -> [Int]
factor n
| n <= 1 = []
| even n = 2 : factor(div n 2)
| otherwise =
let root = floor $ sqrt $ fromIntegral n
in
case find ((==) 0 . mod n) [3, 5.. root] of
Nothing -> [n]
Just fac -> fac : factor(div n fac)
我相信这段代码足够丑陋,足以让真正的 Haskell 程序员流泪,但它在 GHCI 9.0.1 中可以提供每个质因数的计数的质因数。
import Data.List
factors n = [x | x <- [2..(n`div` 2)], mod n x == 0] ++ [n]
factormap n = fmap factors $ factors n
isPrime n = case factormap n of [a] -> True; _ -> False
primeList (x:xs) = filter (isPrime) (x:xs)
numPrimes n a = length $ (factors n) `intersect` (takeWhile ( <=n) $ iterate (a*) a)
primeFactors n = primeList $ factors n
result1 n = fmap (numPrimes n) (primeFactors n)
answer n = ((primeFactors n),(result1 n))
([2,3,7],[3,2,1])