본문 바로가기

issue & tip

부동소수점

반응형

부동소수점수를 다루는 산술 연산의 주의점


double, float 등 부동소수점을 계산할 때 오차가 발생해 의도한 값이 되지 않는 경우


@Test

public void doubleCalTest() {

double resultDouble = 0.0;

resultDouble = 0.7+0.1;

System.out.println("0.7 + 0.1 =" + resultDouble);

}


결과

0.7 + 0.1 =0.7999999999999999



소스코드 상에 기술된 10진수를 자바 실행환경에서 2진수로 변환해 계산하기 때문에 부동소수점수에서는 10진수와 2진수 변환시 오차가 발생한다.


따라서 금액계산 등 오차를 허용하지 않고 정확한 수치를 요구하는 경우에는  BigDecimal 클래스를 이용하여 계산해야 한다.


BigDecimal  클래스


BigDecimal의 생성자에 연산 대상 수치를 문자열(""로 에워싼 것)로 전달한다.

연산 대상 수치를 가진 BigDecimal 인스턴스가 생성되면 메서드를 호출해 연산을 실행한다.

반환값도 BigDecimal 인스턴스이다.


+ add

- subtract

* multiply

/ divide

% remainder


BigDecimal로 나눗셈을 할때 나누어 떨어지지 않는 수치를 계산하면 java.lang.ArithmeticException 예외가 발생한다.


계산할 소수점의 자리수

끝수를 버릴것인가 올릴것인가


끝수처리는 java.math.RoundingMode에 정의되어 있다.


RoundingMode 상수

HALF_UP  - 반올림

UP - 0에서 멀어지도록 올림. 음수인 경우 -5.5의 소수점 이하 첫째자리까지 올리면 -6된다

DOWN - 0에 가까워지도록 내림. 음수인 경우 -5.5의 소수점 이하 첫째자리까지 내리면 -5된다


양 또는 음의 무한대 값에 근접하도록 올림 할때는


CEILING - 양의 무한대 값에 근접하도록 올림. 양수인 경우 UP과 같다. 하지만 음수의 경우  -5.5의 소수점 이하 첫째자리 까지 -5가된다.

FLOOR - 음의 무한대 값에 근접하도록 내림. 양수인 경우 DOWN과 같다. 하지만 음수의 경우  -5.5의 소수점 이하 첫째자리 까지 -6가된다.


@Test

public void bigDecimalTest() {

BigDecimal val1 = new BigDecimal("0.7");

BigDecimal val2 = new BigDecimal("0.1");

BigDecimal result = val1.add(val2);

System.out.println("0.7 + 0.1 =" + result );

result = val1.subtract(val2);

System.out.println("0.7 - 0.1 =" + result );

result = val1.multiply(val2);

System.out.println("0.7 * 0.1 =" + result );

val1 = new BigDecimal("7.0");

val2 = new BigDecimal("3.0");

result = val1.divide(val2, 0, RoundingMode.DOWN);  //소수점 미만을 내림

System.out.println("7.0 / 3.0 =" + result );

result = val1.remainder(val2);

System.out.println("7.0 % 3.0 =" + result );

}


Math 클래스와 StrictMath 클래스

계산 결과가 정확해야 하는 업무 애플리케이션는 그다지 사용하지 않지만, 자바에서는 기본적인 사칙연산 외에 제곱근이나 삼각 함수 등 다양한 계산을 하는 메서드가 java.lang.Math 클래스와 java.lang.StrictMath  클래스가 있다.


Math 클래스는 실행환경의 연산 처리를 이용해 연산 결과를 반환

StrictMath는 모든 플랫폼의 자바 환경에서 동일한 결과를 반환


환경에 따라서 Math클래스와 StrictMath 클래스의 실행결과에 차이가 날 수 있다.


Math 쪽은 실행환경의 연산처리를 이용하므로 이론상 StrictMath보다 속도가 빠르다.



부호없는 Integer와 Long 지원

자바 8 이후로 int와 long에서 부호없는 값을 가질수 있게 되었다.

toUnsignedString 메서드를 사용



@Test

public void toUnsignedString() {

int i = Integer.MAX_VALUE;

String val = Integer.toUnsignedString(i);

System.out.println("Integer UnsignedString = "+val);

i = Integer.MAX_VALUE + Integer.MAX_VALUE + 1;

val = Integer.toUnsignedString(i);

System.out.println("Integer UnsignedString MAX_VALUE= " +val);

i = i+1;

val = Integer.toUnsignedString(i);

System.out.println("Integer UnsignedString MAX_VALUE + 1 = " + val);

long l = Long.MAX_VALUE + Long.MAX_VALUE +1;

val = Long.toUnsignedString(l);

System.out.println("Long UnsignedString MAX_VALUE = " + val);

l = l +1;

val = Long.toUnsignedString(l);

System.out.println("Long UnsignedString MAX_VALUE + 1  = " + val);

}



결과

Integer UnsignedString = 2147483647

Integer UnsignedString MAX_VALUE= 4294967295

Integer UnsignedString MAX_VALUE + 1 = 0

Long UnsignedString MAX_VALUE = 18446744073709551615

Long UnsignedString MAX_VALUE + 1  = 0


참조형

참조형은 인스턴스가 위차한 메모리영역(힙 영역)의 주소를 가지는 자료형이다.

참조형으로 변수만 선언한 경우(초기값을 지정하지 않ㅇ는 경우) 참조할 주소가 없으므로 그 값은 null로 아무것도 가리키지 않는 상태가 된다.


class Sample{

Data a;

Data b = new Data();

}


Data a  Data b

스택     값 = null  값 = 참조주소


참조주소

힙  인스턴스의 값 (인스턴스가 생성 ( new Data() 되야 비로소 영역이 정해진다.))


참조형 데이터의 경우 그 데이터가 가르키는 인스턴스를 변경한다는 것은 참조하는 주소를 변경한다는 뜻이다.

단, 문자열 클래스인 String은 예외로, 큰따옴표("")로 에워싼 똑같은 값을 직접 대입한 경우 각각의 데이터는 같은 참조 주소를 나타낸다.


@Test

public void referenceStringTest () {

String a = "가나다라마바사";

String b = "가나다라마바사";

boolean result = (a == b);

System.out.println("a == b : " + result);

}


결과


a == b : true


String의 경우

같은 값이 이미 존재하는지 확인한 후 같은 값이 존재하면 그 인스턴스의 참조주소를 반환하도록 내부에서 처리한다.


스택영역과 힙영역

자바에서는 설정한 값을 메모리 영역에 확보한다.

데이터는 메모리 영역에 있는 스택 영역에 설정된다. 이때 기본 자료형은 설정할 크키가 정해져 있으므로 스택 영역에 함께 설정된다.

하지만 클래스 등 참조형 데이터는 인스턴스화 될 때가지 메모리 영역을 어느정도 사용할지 알수가 없다.

따라서 참조형 데이터는 처음에 참조 주소를 저장할 수 있는 크기만 확보해두고, 인스턴스화됐을 때 그 값을 메모리 영역의 힙이라는 곳에 저장한다.

스택영역에 있는 참조형 데이터의 값은 어느 힙 영역을 보면 되는 지 알 수 있도록 그 인스턴스 주소가 저장된다.

그러므로 예를 들어 참조형 데이터끼리 값을 비교해도 참조 주소를 비교하는 것이므로 인스턴스의 값 자체를 비교할 수 는 없다.




출처-실무에서 바로 통하는 자바

반응형

'issue & tip' 카테고리의 다른 글

파일 입출력  (0) 2018.04.25
래퍼클래스와 제네릭  (0) 2018.04.24
스레드  (0) 2018.04.24
문자열과 날짜  (0) 2018.04.24
백세코딩#소프트웨어 개발의 기본  (0) 2018.04.16