[Java] Int 와 long / float 와 double
Int 와 float 로 지정 되는 변수는 32bit
long 과 double로 지정 되는 변수는 64bit로 표현된다.
이때, 자바에서는 long 으로 지정될 때 수치 끝에 l or L을
float로 표현 될 때는 f or F 붙여야만 오류가 나지 않는다.
왜일까 ?
우선 int 와 long 의 표현범위 차이를 보자
int 의 표현 범위는 -2,147,483,648~ 2,147,483,647
long의 표현 범위는 -9,223,372,036,854,775,808~ 9,223,372,036,854,775,807
long a = 21474836471;
이경우에
이런 오류를 마주 할 수 있다 .
long의 경우 우선적으로 4byte인 intger로 메모리 절약 차원에서 저장되게되는데
적당한 양의 수를 커버 할 수 있고 JVM에서 피연산자를 4byte단위로 저장하게 되기 때문이다.
long a = 21474836471L;
인경우에 정상적으로 저장되는 걸 알수 있다.
그런데 4byte단위가 유리하고 메모리 절약을위해 상대적으로 작은 int를 기본으로 선택한 정수는 이해가 되는데
실수의 경우 더 큰 double 이 기본인게 이해가 안 됐다.
float a = 1.1;
double로 기본 저장됨을 알 수 있다.
0.1 0.2 같은 특정 소수는 이진법으로 변환하면 무한히 순환하게 되는데 가능한 근사치로
IEEE 754에 따라 저장하는데, 이때 생기는 오차를 줄이려고 기본적으로 double로 사용한다.
float a = 0.1f;
double b = 0.1;
System.out.println(a+0.2);
System.out.println(b+0.2);
이경우 float 에 욱여넣은 대가를 받게 되는데
어마무시한 오차를 마주할 수 있게된다.
모든 소수가 그런 건 아니고 0.125 0.25 같은 류는 별 문제가 없는데 (1/8 , 1/4 등등)
분모가 2의 배수인경우는 근사치가 아니라 그냥 표현이 되기 때문이다.
float a = 0.125f;
double b = 0.0625;
System.out.println(a+0.125);
System.out.println(b+1.25);
이런 소수점을 사용하면 당연히 정확도 면에서 문제가 생기게 되는데
단위를 줄여서 사용 (ex) 0.1 달러 => 10센트) 하거나
java에서 지원하는 BigDecimal 함수를 사용한다거나 하는 해법이 있기는 하다.
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/math/BigDecimal.html
BigDecimal (Java SE 15 & JDK 15)
All Implemented Interfaces: Serializable, Comparable public class BigDecimal extends Number implements Comparable Immutable, arbitrary-precision signed decimal numbers. A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit int
docs.oracle.com
예시로 합을하나 해보면
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
BigDecimal value1 = new BigDecimal("0.1");
BigDecimal value2 = new BigDecimal("0.2");
System.out.println(value1.add(value2));
}
}
소수의 사용을 지양하는 방법이 가장 좋은것 같긴하다.