Python의 부동소수점의 보다 자세한 내용은 아래 문서를 참고해주세요.
숫자형은 배정밀도 64비트 부동소수점 형식(double precision 64-bit binary format floating point number)을 따릅니다. (오늘날 (2000년 11월) 거의 모든 기계는 IEEE-754 부동 소수점 산술을 사용)
배정밀도 64 비트란, 숫자 하나를 표현하는데 64비트의 용량을 사용할 수 있으며 이는 옛날에 사용하던 32비트 방식에 비해 ‘두 배 더 정밀하게’ 수를 표현 할 수 있다는 의미입니다.
부동소수점이란 부(떠서)+동(움직이다) 즉, 소수점을 이동시키면서 숫자를 표현하는 방식입니다.
이는 한정된 메모리 공간을 효율적으로 사용하기 위한 방법으로, 정수(소수점 앞의 수)와 소수점 뒤의 수를 따로 저장하여 실수를 표현하지 않고 유효숫자와 소수점의 위치 값으로 숫자를 나타냅니다.
S영역에는 음양의 값, E에는 소수점의 위치, F에는 유효숫자의 값이 저장됩니다.
<aside> 💡 숫자 용어 정리
0.0075 ==> 75
2.430 ==> 2.430
8230 ==> 823
</aside>
<aside> 💡 0.1 + 0.2은 왜 0.3이 나오지 않을까요?
이를 이해하기 위해서는 우선 10진수를 2진수로 바꾸는 방법을 알아야 합니다. 프로그래밍 언어는 기본적으로 사람이 사용하기 편리하도록 10진수를 기반으로 수를 표현하지만 컴파일 과정에서 2진수로 전환되기 때문입니다.
앞의 정수부(0)는 그대로 두고 소수부에 1이 나올 때까지 2를 곱합니다.
.5 * 2 === 1
1이 나오면 이제 정수부와 합쳐봅니다. 이것이 소수를 이진수로 바꾸는 방법입니다.
0.5의 이진수 표현은 0.1
이번에는 0.1을 이진수로 바꿔보겠습니다.
.1 * 2 === 0.2,
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.2 * 2 === 0.4 // 여기서부터 같은 결과가 반복되기 시작합니다.
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.
.
.
정부수와 합치면 결과는 0.000110011001100110011...
0.5와 다르게 0.1은 무한소수화 됩니다. 컴퓨터는 메모리의 한계로 무한한 값을 저장할 수 없기 때문에 적당한 소수점 위치에서 반올림하여 계산을 종료합니다.
그렇다면 0.2는 어떨까요?
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.
.
.
정부수와 합치면 결과는 0.00110011001100110011...
마찬가지로 0.2 역시 무한소수화됩니다. 때문에 프로그래밍 언어는 값을 확실히 계산할 수 없는 두 수의 합을 십진수로 계산해야하기 때문에 오차가 발생합니다.
실제로 자바스크립트가 표현 가능한 0.3과 가장 가까운 수는 0.299999999999999988897769753748434595763683319091796875
입니다. 하지만 여기서 적당히 소수점 버림을 하면 0.1 + 0.2 의 답은 0.2 가 되어버리기 때문에 표현할 수 있는 살짝 더 큰 수인 0.30000000000000004
를 반환하는 것입니다.
</aside>
각 언어마다 이를 해결할 수 있는 방법이 있습니다. 이러한 문제가 생길 수 있다를 인지하고 있어야 합니다.