使用重复减法的haskell模数函数

时间:2013-05-19 16:21:13

标签: haskell

我需要写一个模数函数(使用重复减法而不使用原始mod函数)。

mod' :: Int -> Int -> Int
mod' x 0 = 0
mod' 0 x = x
mod' x y | x >= y =  (mod' (x-y) y)
         | otherwise = y

我这样做但是这不起作用。它编译,但我得到这样的错误答案:

*Main> 7 `mod'` 4
4
*Main> 3 `mod'` 5
5

有什么问题?

2 个答案:

答案 0 :(得分:4)

otherwise = y

这是错误的:x < yx mod y == x

另外,x `mod` 0不应该出错?

编辑:而且,mod' 0 x = 0,而不是x。

答案 1 :(得分:4)

除了完成工作的行mod' x y | x >= y = (mod' (x-y) y)之外,你还有两个参数的角色转换; mod' x y表示“x mod' y , the remainder on dividing x by y`。

mod' :: Int -> Int -> Int
mod' x 0 = x
mod' 0 x = 0
mod' x y | x >= y =  (mod' (x-y) y)
         | otherwise = x

divmod来自等式

x = (x `div` y) * y + (x `mod` y)

你可以说,如果y==0,那么_ * 0 0 x `mod` 0 x *应该是x `div` y,以使等式有效。 但是,这假定为非严格error "divide by zero",因为*mod' _ 0 = error "division by zero" 。在Haskell中,x `mod` y是严格的,所以方程式无论如何都要分解。也许最好警告用户他们做了一个涉及除零的计算,而不是默默地继续前进,给予

y

mod怎么能用于负数呢?

好的,主要是因为它是一个余数,y应该介于7 `mod` 3和零之间,而不等于mod (-3),所以我们可以计算{{1}像这样:

repeatedly take 3 until answer is under 3

那么如果我们看一下y的话呢?现在“在(-7) `mod` (-3)和零之间”意味着余数应为负值,因此我们可以通过这种方式计算(-x) `mod` (-y) = -(x `mod` y)

repeatedly take minus three until answer is above -3

当然,减去三是与增加三个相同,但重点是我们得到相同的计算和答案,只需改变符号:

x

在这两种情况下,yy的符号都匹配。怎么会有所不同?首先,我们可以有积极的y

repeatedly add three until answer is above zero

其次我们可能会有负(-x) `mod` (-y) = -(x `mod` y)

repeatedly add minus three until answer is below zero

正如我们所看到的,方法不同,但符号规则的变化

y

仍然有效。

那么我们应该对该功能做些什么呢?

步骤0:检查零 第1步:检查否定x。如果是,请使用更改符号规则 第2步:检查肯定y。如果是,请在y之前取y 第3步:否则添加mod' :: Int -> Int -> Int mod' x 0 = error "mod by zero" mod' 0 x = 0 mod' x y | y < 0 = - (mod' (-x) (-y)) | x > 0 = modpos x | otherwise = modneg x where modpos x | x < y = x | otherwise = modpos (x-y) modneg x | x >= 0 = x | otherwise = modneg (x+y) 直到你超过零。

在代码中,那是

ghci> all id [x `mod` y == x `mod'` y | x <- [-10 .. 10], y<- [-10 .. 10],y/=0]
True

快速检查:

{{1}}

表明我们的逻辑是正确的。