Codefights.com에서 Arcade - Python 을 풀다가 상당히 재미있는 버그를 하나 알게 되어 작성한다.
1 2 3 4 5 6 7 8 9 10 11 | #include <iostream> int division(int x, int y) { return x / y; } int main() { std::clog << division(15, -4) << std::endl; return 0; } | cs |
C에서 이렇게 int끼리의 나눗셈의 결과가 나머지가 존재할 경우, '/' 연산자 특성상 나머지를 버리고 몫만을 리턴하기 때문에 결과 값은 -3이 된다. 소숫점으로 나타내면 -3.xx~ 로 나타나겠지만 int 형으로 형변환하면서 -3이 되는 것이다.
( C에서는 두 오퍼랜드 모두 Integer형일 경우 Integer를 반환하고, 하나라도 Float일 경우 Float형으로 소숫점을 붙여 반환한다. 이를 Classic Division이라고 한다. )
1 2 3 4 | def division(x, y): return x / y print division(15, -4) | cs |
하지만 같은 역할을 할 법한 코드를 Python 2에서 작성하여 쓸 경우, 예상과는 달리 -4가 리턴된다.
이는 흔히 Floor Division 이라고 일컫는 정수 나눗셈 방법인데, 두 오퍼랜드가 모두 정수이고 나누어져서 나온 결과가 정수가 아니라면 항상 나온 값보다 작은 정수를 리턴하는 방식이다. 예를 들어, 5/3 의 경우 1.xx 로 1보다는 크고 2보다는 작은 값이 나오므로 1이 리턴된다. 따라서 위의 예시인 15/-4 를 할 경우 -3과 -4 사이의 값이므로 더 작은 값인 -4가 리턴되는 것이다. 이 방식이 문제가 되는 이유는, 흔히 참이라고 생각하는 연산이 거짓이 된다는 점에 있다.
예를 들면, 정수 x와 y에 대해서, (x/-y) == -(x/y) 는 당연히 참이 되어야 하지만, 실제 위의 예시를 들어 보면 (15/-4) 는 -4가 되고 -(15/4) 는 -3이 되므로 거짓이 되어버린다.
이 문제는 Python 3 버전에서는 고쳐졌다고 한다. Python 3에서는 정수를 정수로 나누어도 Float을 반환해버리는 True Division을 사용하기 때문에 애초부터 저런 문제가 발생하지 않으며, Floor Division을 사용하고 싶을 때에는 15//-4 처럼 '//' 연산자를 사용하면 된다.
'Programming' 카테고리의 다른 글
[Python] 멀티프로세싱 환경에서의 logging doRollOver() Error 32 해결법 (0) | 2018.04.09 |
---|---|
[Python] 데코레이터(Decorator)의 이해 (0) | 2018.03.11 |
[C++] std::string split (0) | 2018.01.17 |
CodeFights - alternatingSums (0) | 2018.01.15 |
CodeFights - commonCharacterCount (0) | 2017.12.27 |