我需要写一个模数函数(使用重复减法而不使用原始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
有什么问题?
答案 0 :(得分:4)
otherwise = y
这是错误的:x < y
,x 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
div
和mod
来自等式
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
好的,主要是因为它是一个余数,y
应该介于7 `mod` 3
和零之间,而不等于mod (-3)
,所以我们可以计算{{1}像这样:
那么如果我们看一下y
的话呢?现在“在(-7) `mod` (-3)
和零之间”意味着余数应为负值,因此我们可以通过这种方式计算(-x) `mod` (-y) = -(x `mod` y)
:
当然,减去三是与增加三个相同,但重点是我们得到相同的计算和答案,只需改变符号:
x
在这两种情况下,y
和y
的符号都匹配。怎么会有所不同?首先,我们可以有积极的y
:
其次我们可能会有负(-x) `mod` (-y) = -(x `mod` y)
:
正如我们所看到的,方法不同,但符号规则的变化
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}}
表明我们的逻辑是正确的。