2013-05-19 2 views
1

modulus 함수를 작성해야합니다 (반복 subtraction 및 primitive mod 함수 사용하지 않음).반복 감산을 사용하는 haskell 모듈러스 함수

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 

무엇이 잘못 되었나요?

+3

다음 번에 질문 할 때 예제를 제공하여 어떤 부분이 작동하지 않는지 기억하십시오 (어떤 입력을 전달했는지, 어떤 결과가 있고 무엇을 기대했는지). – hugomg

답변

4

otherwise = y

이것은 잘못된 것입니다 : 때 x < y, x mod y == x가.

또한 x `mod` 0은 (는) 오류가 있습니까?

편집 : 및 mod' 0 x = 0, x 없음.

+0

@AndrewC 네, 바로 그 뜻입니다. 중급 연산자로 mod를 사용하려했지만 "코드 샘플"마크 업으로 항상 엉망이됩니다. 편집 됨. –

+0

아, 예 -이 트릭을 발견 할 때까지 나를 괴롭히는 데 사용되었습니다. 처음부터 끝까지 사용하고'내부에서 잘 사용할 수 있습니다. – AndrewC

+0

@ 앤드류 C 하, 대단한 속임수. 감사! –

4

작업을 수행 한 행 외에도 mod' x y | x >= y = (mod' (x-y) y) 외에도 두 개의 인수가 바뀌 었습니다. mod' x y은 "x mod'y , the remainder on dividingxy"를 의미합니다.

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을해야한다고 주장 할 수 있습니다에서 왔습니다. 그러나 이것은 이 error "divide by zero"이므로 0이 아닌 *으로 가정합니다. 하스켈에서는 *이 엄격하므로 방정식은 어쨌든 고장났습니다. 아마도 모드 어쨌든 음수 작동하도록되어 어떻게

mod' _ 0 = error "division by zero" 

주고, 그들이 제로보다는 조용히 앞으로 이동하여 부문을 포함하는 계산을 한 사용자에게 경고하는 것이 좋습니다? 잘

repeatedly take 3 until answer is under 3

:

확인, 중요한 것은 그것이 나머지 이후, x `mod` yy 동일 y 제로, 그리고 사이에 있어야하는데, 그래서 우리는이 같은 7 `mod` 3을 계산할 수 있다는 것입니다 우리가 무언가를 보면 무엇 mod (-3)?이제 "y 제로 사이에"나머지는 부정적인해야 의미, 그래서 우리는 (-7) `mod` (-3) 이런 식으로 계산할 수 있습니다 세 마이너스 복용 세를 추가하는 것과 동일 물론

repeatedly take minus three until answer is above -3

을하지만, 주요 포인트는 것입니다 우리는 단지 기호의 변화와 같은 계산 및 답변을 얻을 : 이러한 경우 모두에서

(-x) `mod` (-y) = -(x `mod` y) 

, 일치 xy의 부호를. 그들이 다르다면? 첫째, 우리는 긍정적 인 y 수 :

repeatedly add three until answer is above zero

가 두 번째로 우리가 가질 수 부정적인 y :

repeatedly add minus three until answer is below zero

우리가 볼 수 있듯이, 방법은 다르지만, 기호 규칙

의 변화
(-x) `mod` (-y) = -(x `mod` y) 

여전히 나타납니다.

그래서 우리는 어떻게해야합니까?

0 단계 : 0으로 확인하십시오. 1 단계 : 부정확한지 확인하십시오. y. 서명 변경 규칙을 사용하십시오.
2 단계 : 긍정적 인 x을 확인하십시오. 그렇다면 y에이를 때까지 y을 가져 가십시오.
3 단계 : 0이 될 때까지 y을 추가하십시오.

코드에서, 그

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 

우리가 논리 권리를 가지고 보여줍니다.

+0

물론 음수에서도 오류가 발생할 수 있습니다. – hammar

+1

@ hammar이 편집에서 지금 다루었다고 생각합니다. 조금만. – AndrewC

+2

조금만 더, 어? :) – hammar