컴퓨터는 10진수를 2진수로 표현해서 저장한다
그렇다면 실수의 경우는 어떻게 저장할까?
Java 의 primitive 타입인 float와 double 의 저장 방식을 살펴보았다
float 자료형의 경우는 32bit 의 크기를 갖는다
이때 비트를 3개의 부분으로 나누어 수를 저장한다

1.
맨 앞 1비트는 부호(flag) 정보를 저장한다
ex) 음수는 1, 양수는 0으로 저장한다
2.
10진수의 수를 2진수 수로 변환한다
ex) 5.125(10) -> 101.001(2)
1의 자리만 정수로 남기고 나머지 수를 소숫점 뒤로 보낸다
ex) 1.01001 * 2^2
mantissa 부분을 맨 뒷자리 23자리에 넣는다
ex) 01001: mantissa
이 부분이 무한하게 이어질 경우 23자리 이후의 값은 제거한다
제거하는 값 때문에 보통 오차가 발생한다
3.
지수부분 + 127(2^7) 의 값을 2진법으로 변환하고 부호 뒤의 8자리에 넣는다
ex) 2 + 127 = 129 -> 10000001
완성된 결과는 5.125 -> 010000000101001(2) 가 된다
double 타입의 경우는 위의 float 타입과 유사한 형식을 64bit 에 적용한다고 한다
Java는 위의 IEEE 754 부동소수점 방식을 primitive 타입에 채택했다
java.Math.BigDecimal 은 Java 언어에서 사용되는 고정소수점 및 임의정밀도 소수점 방식을 제공하는 클래스이다
위의 2번에서 발생할 수 있는 정밀도 손실 문제를 방지한다
또한 계산 속도는 double , float을 사용하는 경우보다 조금 느리지만 정밀한 결과를 보장한다.
BigDecimal의 주요 필드는 다음과 같다
1. intVal: BigInteger 타입(최소 70바이트, 타입의 한계가 없다)에 정수값을 저장한다
2. scale: 전체 소수점 자리수로, 32bit의 크기를 갖는다
소수점 첫째 자리부터 오른쪽부터 0이 아닌수로 끝나는 위치까지의 총 소수점 자리수를 말한다
ex) 012345.67890 의 scale: 4
예외) 0.00, 0.0 의 scale: 1
3. precision: 정밀도의 의미로, 숫자를 구성하는 전체 자리수를 말한다
왼쪽부터 0이 아닌 수가 시작하는 위치부터 오른쪽부터 0이 아닌 수로 끝나는 위치까지의 총 자리수를 말한다
ex) 012345.67890 의 precision: 9
BigDecimal 은 위 필드를 사용하여 아래와같이 수를 표현한다
intValue * 10^(-scale)
BigDecimal 은 primitive 타입이 아니기 때문에 객체를 생성해서 값을 초기화한다
BigDecimal value = new BigDecimal("12345.6789");
double 타입의 값이 아닌 String 으로 인자를 전달해야 부동소수점 방식으로 저장되지 않는다
또한 객체를 생성하는 방식이기 떄문에 ==(참조값 주소 비교) 이 아닌 equals() 메소드(값만 비교)로 값을 비교한다
BigDecimal 는 임의로 소수점을 처리할 수 있는 기능을 제공한다
나누기 메서드인 divide() 인자로 나눌 수, scale(소숫점 몇째자리까지 표현할 것인지)과 올림등의 타입 Enum 값을 받는다
RoundingMode 라는 enum 으로 올림/내림/반올림 등의 상태를 관리한다
ex) a.divide(b, 3, RoundingMode.HALF_EVEN);

나머지메서드인 remainder() 인자로 나눌 수, precision(전체자릿수) 를 받는다
precision 은 java.math.MathContext 클래스의 상수로 관리한다
ex) a.remainder(b, MathContext.DECIMAL128);

RDB를 관리하는 언어 중 하나인 MySQL에도 BigDecimal과 같은 고정소수점 타입을 DECIMAL 이라는 이름으로 제공한다
컬럼 선언 방법은 다음과 같다
DECIMAL(precision(전체자리수), scale(소수점 이하 자리수))
precision 설정없이 선언시 기본값 10.0을 적용한다
ex) foo DECIMAL(5, 2) DEFAULT 0.00 NOT NULL
지정된 소수 자리수보다 많은 자리의 값을 저장할 경우 지정된 소수 자리수 이하는 floor 처리된다
정밀한 수의 연산과 처리에 있어서, 또한 오버플로우나 언더플로우를 예방하기 위해 BigDecimal 의 사용은 도움이 될 것 같다
그러나 간단한 수의 연산과 저장에는 빠르게 실행되고 저장되는 primitive 타입을 채택하는 것이 맞을 것 같다
개발자의 판단이 중요하다고 여겨진다
차근차근 노력하면 뭐든지 잘 할 수 있을 것 같다
오늘도 화이팅해서 남은 하루 잘 마무리하자 ~
'[Kotlin&Spring] 5기 내일배움캠프' 카테고리의 다른 글
| [Kotlin&Spring] 5기 ArrayList 와 HashMap - Kiosk 과제 트러블슈팅 (0) | 2025.01.16 |
|---|---|
| [Kotlin&Spring] 5기 Abstract Class 와 Interface (1) | 2025.01.15 |
| [Kotlin&Spring] 5기 계산기 과제 트러블슈팅 - Java의 Optional 클래스 (0) | 2025.01.10 |
| [Kotlin&Spring] 5기 Enum에 대해 DB에서 바라보기 (1) | 2025.01.08 |
| [Kotlin&Spring] 5기 System.out.println() 메서드와 Logger (0) | 2025.01.07 |