例外:除以零

时间:2016-03-24 16:34:32

标签: list haskell

我想找出所有2的幂除以10的列表!它显示异常,即除以零

[2^i | i<-[1..],(factorial(10) `mod` (2^i))==0]

完整的问题是获得函数largest_Power largest_Power :: Int - &gt; Int - &gt;诠释 maximum_Power n p 是除了n的最大p的幂! (n的阶乘)

我试着做这个

largest_Power :: Int->Int->Int
largest_Power 0 _ =1  
largest_Power _ 0 =1
largest_Power n p = floor (logBase (fromIntegral p) (fromIntegral (last([p^i | i<-[1..],(factorial(n) `mod` (p^i))==0]))))

factorial::Int->Int
factorial 0=1
factorial 1=1
factorial x=x*factorial(x-1)

现在当我为maxowerPower 10 2运行时。我正在异常。

1 个答案:

答案 0 :(得分:1)

Int出了什么问题?

Int有一个有限的范围 - 在大多数系统上-(2^63)2^63-1

现在你从1(也是二进制的1)开始,然后在二进制中添加零(与乘以2相同) - 你总是只有一个{{1} }后跟1 s。在某些时候你隐藏了下限的表示(最高位将表示正值或负值的标记),然后你将添加另一个0,它会溢出0结束你只有Int s。

您可以轻松查看:

0

这就是原始答案中Prelude> take 64 $ [2^i | i <- [1..]] :: [Int] [2,4,8,16,32,64,128, ... ,4611686018427387904,-9223372036854775808,0] 的来源。

为什么列出理解结果在底部

你遇到的下一个问题是,列表理解

division by zero

挂起并且不再生成任何值。

原因很简单:足够大[2^i | i<-[1..],(factorial(10) `mod` (2^i))==0] i并且永远不会再划分它。

这就是我建议为2^i > factorial(10)拉出过滤器并首先将列表限制为此硬限制的原因:

我不想一遍又一遍地写mod所以我先定义

  • factorial 10这是let m = product [1..10]
  • 的定义
  • factorial 10[2^i | i <- [1..]]
  • 形式的所有号码列表
  • 只有那些较小的2^i才有趣,所以我们只考虑那些:m
  • 现在列表是有限的,使用takeWhile (<= m) [2^i | i <- [1..]]没问题:filter

产生:

filter (\n -> m `mod` n == 0) $ takeWhile (<= m) [5^i | i <- [1..]]

解决您的问题

当然事实证明你的问题是:

  

问题是要定义一个函数λ> let m = product [1..10] in filter (\n -> m `mod` n == 0) $ takeWhile (<= m) [2^i | i <- [1..]] [2,4,8,16,32,64,128,256]   largest_Power largest_Power :: Int -> Int -> Int是最大的largest_Power n p   分割p

factorial n的力量

我现在假设你必须处理那里的Int,所以你必须在某些fromIntegral处理这些转换。

基于您的想法和上述代码段的解决方案可能是:

largest_Power :: Int -> Int -> Int
largest_Power n p = fromIntegral . last $ factorList n p

factorList :: Int -> Int -> [Integer]
factorList n p =
  filter (\n -> m `mod` n == 0)
  $ takeWhile (<= m) [p'^i | i <- [1..]]
  where m = fromIntegral $ factorial n
        p' = fromIntegral p

factorial :: Int -> Integer
factorial n = product [1..fromIntegral n]

如果您确实只对来自i的{​​{1}}感兴趣,那么您可以将其推入元组并稍微调整算法:

p^i

程序的其余部分可以保持不变

重新思考算法

现在,如果你想一想它发生了什么,老实说似乎没有意义,首先创建一个庞大的数字factorList :: Int -> Int -> [Integer] factorList n p = map fst . filter (\(_,n) -> m `mod` n == 0) $ takeWhile ((<= m) . snd) [(i,p'^i) | i <- [1..]] where m = fromIntegral $ factorial n p' = fromIntegral p 然后测试可分性,当我们需要的是我们可以划分这个数字的次数另一个(没有休息)当我们知道这个巨大的数字只是一个非常小的数字 - 因为我们可以检查较小的数字,然后加起来。

因此,如果您只对来自factorial n的{​​{1}}感兴趣,那么也会这样做:

i

但对于更大的数字应该快得多。

请注意,如果您记住p^i,如果这是在线竞赛的问题,您可以更快地获得这个...我怀疑^^