【问题标题】:Exception: divide by zero [closed]例外:除以零[关闭]
【发布时间】:2016-03-24 16:34:31
【问题描述】:

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

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

完整的问题是获得函数 maximum_Power 使得 maximum_Power :: Int -> Int -> Int 最大功率 n p 是 p 除以 n 的最大幂! (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)

现在当我为最大功率 10 2 运行这个时,我遇到了异常。

【问题讨论】:

  • 你对factorial的定义是什么? (就此而言,尚不清楚您为什么要使用 factorial,或者您的实际问题是什么。只有 1、2、4 和 8 有机会除以 10,而实际上只有 2。)如果您想要能被 10 整除的 2 的幂,没有; 10 = 2 * 5,2 的幂不能被 5 整除。
  • 我同意@chepner 所说的一切,并想补充一点,如果您确实填写了一个阶乘函数并运行它,甚至不会出现除以零错误......跨度>
  • 该错误很可能是因为您使用Int 而不是Integer 来定义您的factorial 或者您在某处有Int 类型注释
  • 这应该得到你的名单let m = product [1..10] in filter (\n -&gt; m `mod` n == 0) $ takeWhile (&lt;= m) [2^i | i &lt;- [1..]] - 应该给你[2,4,8,16,32,64,128,256]
  • 当然,只要稍微算一下就很容易了:10! = 1*2*3*...*10 - 你想在那里收集所有 prim-factor 2 - 它是 2,2*2,2*3,2*2*2,2*5 - 所以你可以取 1 到 8 个 2`s 正好是 [2^1,...,2^8] 这就是脚本给你的结果

标签: list haskell


【解决方案1】:

Int 出了什么问题?

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

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

您可以轻松检查:

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 &gt; factorial(10) 并且永远不会再分割它。

这就是为什么我建议拉出mod 的过滤器并首先将列表限制为这个硬限制:

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

  • let m = product [1..10]factorial 10 的定义
  • [2^i | i &lt;- [1..]]2^i 形式的所有数字列表
  • 只有那些较小的m 是有趣的,所以我们只选择那些:takeWhile (&lt;= m) [2^i | i &lt;- [1..]]
  • 现在列表是有限的,使用filter没有问题:filter (\n -&gt; m `mod` n == 0) $ takeWhile (&lt;= m) [5^i | i &lt;- [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 -&gt; Int -&gt; Intlargest_Power n p 是最大的 p 的幂除以factorial n

我现在假设您必须在那里处理Ints,因此您必须使用一些fromIntegral 来处理转换。

基于您的想法和上述 sn-p 的解决方案可能是:

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]

如果您确实只对来自p^ii 感兴趣,那么您可以将其推入一个元组并稍微调整算法:

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 然后在我们需要的只是将这个数字除以另一个数字或次数时测试可分性似乎是没有意义的(没有休息)当我们知道这个巨大的数字只是非常小的数字的一个因素时 - 因为我们可以检查较小的数字然后加起来。

因此,如果您只对来自p^ii 再次感兴趣,那么也可以这样做:

factorCount :: Integral a => a -> a -> a
factorCount n p =
  let (n',r) = n `divMod` p
  in if r == 0 then 1 + factorCount n' p else 0

largest_Power :: Integral a => a -> a -> a
largest_Power n p = sum [ factorCount i p | i <- [1..n] ]

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

请注意,如果你记住factorCount,你可以更快地得到这个,如果这是一个在线比赛的问题,你可能应该这样做......我怀疑这是^^

【讨论】:

  • 非常感谢.....你彻底解开了我所有的疑惑
猜你喜欢
  • 1970-01-01
  • 2011-07-29
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 1970-01-01
  • 2021-02-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多