Haskell中的主要因素

时间:2014-01-22 07:35:33

标签: haskell primes factorization prime-factoring

我是Haskell的新人。

如何生成包含下一个整数的素因子的列表列表?

现在我只知道如何生成素数:

primes = map head $ iterate (\(x:xs) -> [y | y<-xs, y `mod` x /= 0 ]) [2..]

8 个答案:

答案 0 :(得分:16)

确定n的素因子的简单方法是

  • d
  • 中搜索第一个除数[2..n-1]
  • 如果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),缓存到目前为止找到的素数并仅为这些等计算除法。)

<强>更新

使用案例的略微修改版本(由@ 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]

答案 1 :(得分:5)

直到红利m&lt; 2,

  1. 从素数中取第一个除数n
  2. 重复m除以n,同时可分割。
  3. 从素数中取下一个除数n,然后转到2.
  4. 实际使用的所有除数列表是原始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)
    
    Will Ness's comment中所述,

    primes也可以大幅加速:

    primes = 2 : filter (\n-> head (factors n) == n) [3,5..]
    

答案 2 :(得分:4)

这是一个性能良好且易于理解的实现,其中isPrimeprimes是递归定义的,默认情况下会缓存primesprimeFactors定义只是对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]

答案 3 :(得分:2)

Haskell允许您创建相互递归的无限列表。让我们利用这一点。

首先让我们创建一个辅助函数,尽可能地将数字除以另一个数字。一旦我们找到一个因素,我们就需要它来完全消除它。

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的因子列表。我们正在使用素数列表,取2(可以从我们手动给出的数据中计算出来) )。我们看到它不会划分3,因为它大于3的平方根,所以没有可能的除数为3.因此,3的因子列表是[3]。由此,我们可以计算出3是另一个素数。等

答案 4 :(得分:2)

我刚刚解决了这个问题。这是我的解决方案。

有两个帮助功能

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)]

答案 5 :(得分:1)

更优雅的代码,使用2和奇数除以数字。

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)

答案 6 :(得分:0)

这是我的版本。不像其他的那么简洁,但是我认为它非常易读并且易于理解。

import 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)

答案 7 :(得分:0)

我确信这段代码丑陋到足以让真正的 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))

示例: ghci> 答案 504

([2,3,7],[3,2,1])

答案是一个质因数列表和一个显示每个质因数多少次的第二个列表 质因数在提交的数字中。