주문 DB 스키마를 작성하다가
Price(가격) 칼럼을 만들려고 int 타입으로 간단하게 생각하고 넘길려고 했는데,
만약 가격이 소수점으로 표현된다면 정확하게 표현할 수 있을까?
라는 의문이 들었습니다.
역시나 찾아보니 float 자료형을 쓰면 안된다는 이야기가 많았습니다.
소수점을 float 실수형으로 그냥 표현하면 되지 왜 문제가 될까요?
컴퓨터가 저장하는 실수값
컴퓨터는 어떤 값을 저장할때 RAM에 저장을 하는데,
RAM 기억공간
사진과 같이 0과 1로 표현해서 저장합니다.
즉 어떤 수를 저장하고 싶다면 0과 1로 바꿔야하니 이진법으로 변환해서 저장하게 됩니다.
그렇다면 여기서 컴퓨터가 실수를 저장하려면 어떻게 저장할까요?
IEEE라는 곳에서 실수를 저장하는 방식에대해 설명한 것이 있습니다.
0과 1을 저장하는 32칸을 먼저 준비한 후
제일 첫번째 보라색 부분은 + 인지 - 인지 표현을 1과 0으로 표현해주고
예를 들어
5.125 을 메모리에 표현한다고 한다면
5.125를 이진법 변환 해준다. → 101.001
이진법 변환 해준뒤 왼쪽 첫번째 소수점으로 이동해준다 → 1.01001 x 22
1.01001 → 23~32칸 부분에 넣어줍니다.
22 을 이진법 변환 해줍니다. 2+127→ 10000001 2~9칸에 넣어줍니다.
이것이 실수를 표현하는 방식인데 여기에선 아주 큰 문제가 있습니다.
0.125 10진수를 2진수로 표현하면 0.001로 정리가 되지만
0.1과 같은 10진수를 2진수로 표현하면 순환소수가 되게됩니다. 0.1 → 0.000110011…
이런 숫자가 나왔을 때, 위에 방식으로는 32칸 뒤에 부분 값은 버려지게 됩니다.
그래서 버려지는 부분만큼 오차가 생기게 됩니다.
let a = 0.1;
let b = 1.1;
a+b == 1.2 // false
위와 같은 결과가 나오는 이유입니다.
해결방법
정말 정확히 계산하고 싶다면 정수로 → DECIMAL, CURRENCY와 같은 자료형이 있는데 DECIMAL과 같은 자료형은 정수(정확히는 문자열로 저장한뒤 정수로 변환)로 저장한뒤 소수점을 찍는 방식이라 가장 적합한 방식이라고 할 수 있습니다.
소수점을 사용하고 싶다면, 반올림 문법 사용
double 자료형 사용(숫자 1개당 64칸을 사용하기 때문에 오차 범위가 거의 적음, 단점: 메모리 용량 2배 필요) → 하지만 정확성에 문제가 있음