-
Zero Division with Floating-Point Numbers프로그래밍 언어 2023. 11. 16. 02:04
개발을 하면서 어떠한 값을 0으로 나누는 미친 짓을 하는 개발자는 없겠지만 (
그게 나야) 부동소수점에서의 Zero Division을 알아보고자 한다.우선 두 가지의 배경 지식이 필요하다.
부동 소수점 계산
첫 번째로 흔한 개발자 상식으로 나오는 문제를 살펴보자. $1.1 + 0.1 == 1.2$는 $true$일까? 아님 $false$일까? 정답은 $false$이다.
이는 부동 소숫점을 어떻게 표현하는지에 대해 확인하면 왜 $false$가 나오는지 알 수 있다. float의 경우 부호 $1$비트, 지수 부분 $8$비트, 가수 부분 $23$비트로 구성되고, double의 경우 부호 $1$비트, 지수 부분 $11$비트, 가수 부분 $52$비트로 이루어져있다.
정수와 다르게 부동 소숫점은 정확한 값으로 표현할 수 없으며 근사값으로 표현되기 때문에 동등 비교 시 $false$가 출력된다.
단, float 타입의 경우 정확도가 매우 떨어져 $1.1f + 0.1f == 1.2f$가 $true$를 반환하게 된다. 정확한 소숫점 계산을 위해선 float타입이 아닌 double 타입을 사용하길 권장한다.
Zero Division
두 번째로 코딩을 하다 보면 하지 말아야 할 연산 중 자주 마주하는 상황이 있다. 바로 $0$으로 나누는 행위이다. 이를 Zero Division이라고 부르며 이는 프로그래머가 의도하지 않은 값을 출력하여 심각한 버그를 발생시킨다.
부동 소수점의 Zero Division
그렇다면 부동소수점 형태의 $0$으로 나눈다면 어떻게 될까?
에러가 발생하지 않고 $inf$라는 값이 출력된다. 부동소수점으로 $0$을 정확하게 표현할 수 없어 $0$은 아니지만 $0$과 거의 비슷한 아주 작은 수로 표현해야 하기 때문이다. $1.0f \ / \ 0.0f$는 $0.0f$에 비해 $1.0f$가 굉장히 큰 값이므로 무한대로 발산하기 때문에 $inf$가 출력된다.
그렇다면 $0.0f \ / \ 0.0f$의 값은 무엇일까? $NaN$, 즉 정의할 수 없는 값이 출력된다. $0.0f \ / \ 0.0f$은 어떠한 값으로 수렴하지도 않고 발산하지도 않아 정의할 수 없기 때문에 $NaN$이 출력된다.
그렇다면, $0.0f$로 나누는 행위가 에러가 아니라면 $1.0f \ / \ 0.0f == 1.0f \ / \ 0.0f$는 $true$일까? $false$일까?
$true$가 반환된다. 그렇다면, $0.0f \ / \ 0.0f == 0.0f \ / \ 0.0f$는 $true$일까? $false$일까?
$false$가 반환된다. 이러한 결괏값을 내는 이유를 확인하기 위해선 Visual Studio의 Compiler가 부동 소수점을 어떻게 다루는지에 대해 알아볼 필요가 있다.
Visual Studio의 옵션 중엔 /fp라는 옵션이 존재한다. 이는 Specify floating-point behvaior, 즉 Compiler가 부동 소수점을 어떻게 다루고, 최적화하고, 예외처리하는지에 대한 옵션이며 여러 옵션이 있지만 /fp:precise 옵션이 Default 값이다.
해당 옵션에선 특별한 값들($NaN$, $+infinity$, $-infinity$, $-0.0$)에 대한 비교 연산을 따로 정의하고 있다.
그 중 $NaN$의 경우 정의되있지 않은 값이기 때문에 $NaN$끼리의 동등 비교 연산은 $false$를 반환하고 $+infinity$, $-infinity$, $-0.0$는 동등 비교 연산 시 $true$를 반환한다.
'프로그래밍 언어' 카테고리의 다른 글
OOP Design Pattern - Structural Pattern (0) 2024.01.18 OOP Design Pattern - Creational Pattern (0) 2024.01.12 [C++] 이동 의미론 Move Semantics (0) 2023.11.20 입실론 테스트 (0) 2023.11.20 객체 지향 설계 SOLID (0) 2023.11.16