연산자란?

연산을 수행하는 기호이다.

용어
연산자 : 연산을 수행하는 기호
피연산자 : 연산의 작업 대상 (변수, 상수, 리터럴, 수식 등)
x + 3

// x, 3 : 피연산자
// + : 연산자

1. 식(式)과 대입 연산자

식 : 연산자와 피연산자를 조합하여 계산하는 것

식의 평가 : 식을 계산하여 결과를 얻는 것

int x = 5;

1. int y = 4 * x + 3;

2. int y = 4 * 5 + 3;

3. int y = 23;

2. 연산자의 종류

연산자 종류 연산자 피연산자 결과 값 설명
산술 연산 +, -, *, /, % 이항 숫자 사칙 연산 및 나머지 계산
부호 +, - 단항 숫자 음수, 양수 부호
문자열 + 이항 문자 두 문자열을 연결
대입 연산 =, +=, -=, *=, /=, %=. &=, ^=, |=, <<=, >>=, >>>= 이항 다양 우변의 값을 좌변에 대입
증감 연산 ++, -- 단항 숫자 1씩 증가, 감소
비교 연산 ==, !=, <, >, <=, >=, instanceof 이항 boolean 값을 비교
논리 연산 !, &&, || 단항, 이항 boolean 논리적 NOT, AND, OR 연산
조건 연산 (조건식) ? A : B 삼항 다양 조건식이 true면 A, false면 B 반환
비트 ~, &, |, ^ 단항, 이항 숫자, boolean 비트 NOT, AND, OR, XOR 연산
비트 쉬프트 <<, >>, >>> 이항 숫자 비트를 좌우측으로 밀어 이동
  • 0으로 나눌 경우 ArithmeticException 에러가 발생한다.
  • 0.0으로 나눌 경우 Infinity가 출력된다.
  • byte, short의 연산의 경우 int형으로 변환하여 계산된다.
  • 나머지 연산 시 나누는 수로 음수를 허용하지만 부호는 무시된다.
char c = 'a' + 1; // 에러 없음

char c1 = 'a';
char c = c1 + 1; // 에러 발생

위의 예제에서 에러가 없는 경우는 리터럴 간 연산이기 때문에 컴파일 시 컴파일러가 값을 대체하여 준다.

하지만 아래 에러 발생의 경우 c1이라는 값이 변수라서 컴파일러가 계산을 못하여 에러가 발생한다.

그래서 char c = (char) c1 + 1;과 같이 캐스팅 연산자를 사용해야한다.

2.1 피연산자의 개수에 의한 분류

// 한개, 단항
x++;

// 두개, 이항
int x = 1 + 1;

// 세개, 삼항
int x = (a == 1) ? 1 : 2;

삼항 연산자는 괄호 안에 조건문이 true일 경우 : 기준 좌측, false일 경우 우측을 반환한다.

3. 연산자의 우선순위와 결합 규칙

연산자가 둘 이상일 경우 연산자의 우선순위에 의해 연산 순서가 결정된다.

int x = 5 + 3 * 4;

우선순위가 확실하지 않다면 괄호로 식을 묶어서 계산한다. EX) int x = (5 + 3) * 4;

우선 순위 연산자 피연산자 결합 규칙
1 (), [] 연산자 다양 -
2 증감 (++, --), 부호 (+, -), 비트 (~), 논리 (!) 단항 좌측
3 산술 (*, /, %) 이항 우측
4 산술 (+, -) 이항
5 쉬프트 (<<, >>, >>>) 이항
6 비교 (<, >, <=, >=, instanceof) 이항
7 비교 (==, !=) 이항
8 논리 & 이항(단항)
9 논리 ^ 이항(단항)
10 논리 | 이항(단항)
11 논리 && 이항
12 논리 || 이항
13 조건 ( ? : ) 삼항
14 대입 (=, +=, -=, *=, /=, %=. &=, ^=, |=, <<=, >>=, >>>=) 이항 좌측

4. 산술 변환(usual arithmetic conversion)

산술 변환이란?

연산 수행 전에 발생하는 피연산자의 자동 형 변환으로 두 피연산자의 타입을 일치시키기 위한 변환이다.

  • 작은 타입에서 큰 타입으로 변환 시 데이터 손실을 줄이기 위함
  • int 보다 작은 char, short는 int로 변환
  • 쉬프트 연산자 (<<, >>, >>>), 증감 연산자(++, --) 제외
int x = 10;
long y = 100;

// (long) x + y = 110;

위의 예시처럼 x를 long으로 변환하여 연산을 하는 것이다.

5. 비교 연산자

비교 연산자란?

두 피연산자를 비교하기 위한 연산자이다. true, false 중 하나의 결과가 나오며 타입이 서로 다른 두 피연산자는 자동 형 변환 후 비교된다.

5.1 대소 비교 연산자

연산자 : <, >, <=, >=

if(a > b) {}
if(a < b) {}
if(a <= b) {}
if(a >= b) {}

대소 비교 연산자는 기본형에 사용할 수 있으며 참조형과 boolean형에는 사용이 불가하다.

5.2 등가 비교 연산자

연산자 : ==, !=

if(a == b) {}
if(a != b) {}

등가 비교 연산자는 모든 자료형에 사용 가능하다.

float와 double을 비교하려면 서로 근사 값이 달라 double형을 float로 변환 후 비교해야 한다.

 

* 문자열 비교

문자열 비교는 ==를 사용하지 않고 equals() 함수를 사용한다.

String str1 = new String("ABC");
String str2 = "ABC";

if(str == str2) // false
if(str.equals(str2)) // true

==은 객체를 비교하여 두 개의 객체가 달라 false를 반환하지만 equals()는 내용을 비교하여 true를 반환한다.

6. 논리 연산자

논리 연산자란?

둘 이상의 조건을 AND와 OR로 연결하여 하나의 식으로 표현하는 것이다.

6.1 논리 연산자

연산자 : &&, ||, !

  • && (AND) : 두 피연산자가 모두 true일 경우 true
  • || (OR) : 두 피연산자 중 하나라도 true일 경우 true
  • ! (부정) : true -> false, false -> true
10 < x && x < 20; // x는 10보다 크고 20보다 작다
10 < x || x < 20; // x는 10보다 크거나 20보다 작다

&&가 ||보다 우선순위가 높다.

 

* 효율적인 연산

  • && (AND) 연산 시 왼쪽이 false면 우측은 평가하지 않는다.
  • || (OR) 연산 시 왼쪽이 true이면 우측은 평가하지 않는다.

6.2 비트 연산자

비트 연산자란?

피연산자를 비트 단위로 논리 연산하는 것이다.

 

연산자 : &, |, ^, ~, <<, >>

  • | (OR) : 한쪽이 1이면 1을 얻고 아니면 0을 얻는다.
  • & (AND) : 양쪽 모두 1이면 1을 얻고 아니면 0을 얻는다.
  • ^ (XOR) : 값이 서로 다를 때 1을 얻고 같으면 0을 얻는다.
X Y X | Y X & Y X ^ Y
1 1 1 1 0
1 0 1 0 1
0 1 1 0 1
0 0 0 0 0
// OR 연산자 '|'
// 주로 값을 변경할때 사용
1. OxAB | OxF => OxAF

    10101011 (OxAB)
(|) 00001111 (OxF)
    --------
        1111 (OxAF)
    
// AND 연산자 '&'
// 주로 특정 비트의 값을 뽑을때 사용
2. OxAB & OxF => OxB

    10101011 (OxAB)
(&) 00001111 (OxF)
    --------
    00001011 (OxB)

// XOR 연산자 '^'
// 같은 값을 두고 연산하면 원형으로 돌아옴
3. OxAB ^ OxF => OxA4

    10101011 (OxAB)
    00001111 (OxF)
    --------
    10100100 (OxA4)
(^) 00001111 (OxF)
    --------
    10101011 (OxAB)
  • ~ (비트 전환 연산자) : 0 -> 1, 1 -> 0으로 논리 부정 연산자와 비슷하다. 1의 보수 연산자라고도 한다.
1. (~) 00001010 (10) => 11110101 (-11)

2. (~) 00001010 (10) => 11110101 (-11) + 1 => 11110110 (-10) // 1의 보수 + 1

위의 예제 중 2번을 부면 비트 전환 연산자를 이용해 1의 보수를 구하고 구한 값에 1을 더하니 마이너스 값을 얻는 걸 알 수 있다.

(-) 부호만 붙여도 양 -> 음, 음 -> 양으로 변환을 할 수 있지만 비트 연산자를 이용하게 되면 아래와 같이 부호가 다른 값을 구할 수 있다.

 

EX) ~N+1 : 양 -> 음

     ~(N-1) : 음 -> 양

  • <<, >> (쉬프트 연산자) : 피연산자의 각 자리(2진수)를 '>>' 오른쪽, '<<' 왼쪽으로 이동(shift)하는 연산자이다.
    자리 이동으로 범위를 벗어나게 되면 0으로 채워진다. '>>' 연산자는 이동시킬 때 부호 있는 정수는 1을 부호 없는 정수는 0을 채운다.
1. 10진수 8은 2진수 00001000이다.
2. 8 << 2는 10진수 8의 2진수를 왼쪽으로 2자리 이동하라는 것이다. // 00 001000
3. 저장범위가 넘어가면 빈자리는 0으로 채운다. // 00 00100000 (32)

위의 예시 중 2번에서 연산자 우측에 있는 피연산자는 자리를 몇 번 이동할지 정하는 숫자이다.

좌측 피연산자는 산술 변환이 되어 int보다 작은 값이면 int로 변환하지만 우측 피연산자는 타입을 일치시키지 않아도 돼서 산술 변환이 일어나지 않는다.

// >> => x / 2^n의 결과

8 >> 1 -> 4
8 >> 2 -> 2

// << => x * 2^n의 결과

8 << 1 -> 16
8 << 2 -> 32

위의 예시는 이동(쉬프트) 연산자 이용하여 x / 2^n과 x * 2^n을 구하는 식이다.

이동(쉬프트) 연산자가 *, / 보다 더 빠르기는 하나 가독성이 떨어진다.

 

8 >> 32 하게 되면 int타입이 32bit여서 제자리 값이 된다. 그래서 8 >> 34는 8 >> 2와 같다.

 

7. 조건 연산자

조건 연산자는 유일한 삼항 연산자이다.

 

연산자 : ? :

// (조건문) ? 식1 : 식2
// 조건식이 true면 식1을 false면 식2를 수행한다.
x > y ? x : y;

x > 0 ? 1 : (x == 0 ? 0 : -1);

if문으로 바꿔서 사용이 가능하며 결합 규칙은 오른쪽에서 왼쪽으로 진행된다.

8. 대입 연산자

대입 연산자는 변수에 값을 대입할 때 사용하는 이항 연산자이며 결합 규칙은 오른쪽에서 왼쪽으로 진행된다.

 

연산자 : =, op=(op와=사이에 공백 없음)

연산자 설명
= 왼쪽의 피연산자에 오른쪽의 피연산자를 대입
+= 왼쪽의 피연산자에 오른쪽의 피연산자를 더한 후, 그 결과 값을 왼쪽의 피연산자에 대입
-= 왼쪽의 피연산자에 오른쪽의 피연산자를 뺀 후, 그 결과 값을 왼쪽의 피연산자에 대입
*= 왼쪽의 피연산자에 오른쪽의 피연산자를 곱한 후, 그 결과 값을 왼쪽의 피연산자에 대입
/= 왼쪽의 피연산자에 오른쪽의 피연산자로 나눈 후, 그 결과 값을 왼쪽의 피연산자에 대입
%= 왼쪽의 피연산자에 오른쪽의 피연산자로 나눈 후, 그 나머지 값을 왼쪽의 피연산자에 대입
&= 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 AND 연산한 후, 그 결과 값을 왼쪽의 피연산자에 대입
|= 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 OR 연산한 후, 그 결과 값을 왼쪽의 피연산자에 대입
^= 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 XOR 연산한 후, 그 결과 값을 왼쪽의 피연산자에 대입
<<= 왼쪽의 피연산자를 오른쪽의 피연산자만큼 왼쪽 이동 후, 그 결과 값을 왼쪽의 피연산자에 대입
>>= 왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호를 유지하며 오른쪽 이동 후, 그 결과 값을 왼쪽의 피연산자에 대입
>>>= 왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호에 상관없이 오른쪽 이동 후, 그 결과 값을 왼쪽의 피연산자에 대입
n = 5 // 대입
n += 5 // 더한 후 대입
n -= 5 // 뺀 후 대입
n *= 5 // 곱한 후 대입
n /= 5 // 나눈 후 대입
n %= 5 // 나눈 후 나머지 대입
n &= 5 // AND 후 대입
n |= 5 // OR 후 대입
n ^= 5 // XOR 후 대입
n <<= 5 // 왼쪽으로 이동 후 대입
n >>= 5 // 부호 유지하면 오른쪽으로 이동 후 대입
n >>>= -5 // 부호 상관 없이 오른쪽으로 이동 후 대입

참조

https://kephilab.tistory.com/28

 

4. Java 자바 - 연산자 종류, 연산자 우선순위

1. 연산자 종류 연산자 종류 연산자 피연산자 수 산출값 설명 산술 연산 +, -, *, /, % 이항 숫자 사칙연산 및 나머지계산 한다. 부호 +, - 단항 숫자 음수 / 양수 부호 문자열 + 이항 문자 두 문자를 연

kephilab.tistory.com

https://tcpschool.com/java/java_operator_assignment

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

 

'개발 언어 > Java' 카테고리의 다른 글

[Java] 배열  (0) 2021.08.19
[Java] 제어문  (0) 2021.08.18
[Java] 형변환  (0) 2021.08.18
[Java] 실수형의 소수점 표현 방식과 BigDecimal  (0) 2021.08.13
[Java] 오버 플로우, 언더 플로우  (0) 2021.08.12

형 변환 (캐스팅, Casting) 이란?

변수나 리터럴의 타입을 다른 타입으로 변환하는 것을 형 변환이라고 한다.

형 변환 방법

double d = 85.4;
int score = (int) d;

위와 같이 형 변환 연산자 '()'를 이용하여 변환한다.

변환 과정

double d = 85.4;

int score = (int) d;
int score = (int) 85.4;
int score = 85;

기본형의 형 변환

char c = (char) 65; // int -> char
int i = (int) 'A'; // char -> int
int i = (int) 1.6f; // float -> int
float f = (float) 10; // int -> float

boolean타입은 다른 타입과 형 변환이 안된다.

정수형 간의 형 변환

// 큰 타입 -> 작은 타입
byte b = (byte) 10; // 1010(10) -> 1010(10)
byte b = (byte) 300; // 100101100(300) -> 00101100(44)

// 작은 타입 -> 큰 타입
int i = (int) 10; // 1010(10) -> 1010(10)
int i = (int) -2; // 11111110(-2) -> 111111100(-2)
  • 작은 타입으로 변환할 경우 값의 손실이 발생할 수 있다.
  • 큰 타입으로 변환할 경우 값의 손실이 없다.
  • 변환하고자 하는 값이 양수면 0, 음수면 1을 빈칸에 채워 넣는다.

실수형 간의 형 변환

작은 타입 -> 큰 타입 (float -> double)

  • float의 기저인 127을 빼고 double의 기저인 1023을 더한다.
  • float의 가수 23자리를 채우고 빈칸에 0을 채운다.

큰 타입 -> 자은 타입 (double -> float)

  • double의 기저인 1023을 빼고 float의 기저인 127을 더한다.
  • double의 가수 52자리 중 23자리만 저장하고 나머지는 버린다.

주의점)

  1. 24번째 자리가 1일 경우 반올림이 발생한다.
  2. float 타입의 값을 넘는 경우 ±무한대(큰 경우), ±0(작은 경우)의 결과를 얻는다.

정수형과 실수형 간의 형 변환

저장 방식

정수형의 저장 방식
실수형의 저장 방식

정수형 -> 실수형 변환

10진수 7 (0 | 000...00111) 111 -> 1.11 * 2^2+127 (정규화) (0 | 10000001 | 11000...000)

 

주의점)

int의 최대 값인 약 20억을 변환할 경우 최대 10자리의 정밀도가 필요하다. 큰 값을 변환할 경우 deouble형으로 변환해야 오차가 발생하지 않는다.

 

EX)

int -> float -> int : 9123456 -> 91234568.0 -> 91234568

int -> double -> int : 9123456 -> 91234567.0 -> 91234567

실수형 -> 정수형 변환

정수형은 소수점 이하를 표현할 수 없기 때문에 소수점 이하의 값은 버려진다.

EX)

9.1234567f -> 9

 

float (0 | 10000010 | 001000111111001101011101) -> 1001.001000111111001101011101

int (0 | 0000000....00001001)

 

위의 예시처럼 소수점은 모두 버려진다.

만약 정수로 변환 시 정수의 범위를 넘는다면 오버플로우가 발생한다.

자동 형 변환

  1. 편의상의 이유로 형 변환을 생략할수 있다. 
  2. 형변환을 명시 해주면 의도적인 형 변환으로 간주하여 에러가 발생하지 않는다. 
  3. 서로 다른 타입의 덧셈의 경우 더 큰 범위를 가진 타입으로 자동 형 변환이 이루어져 계산되어 값 손실을 줄이고 올바른 값을 얻는다.

연산자의 범위보다 큰 값을 저장하는 경우 에러가 발생한다. EX) incompatible types: possible lossy conversion from int to byte

 

아래의 예시는 위의 3가지 특징을 보여주는 예시이다.

1. float f = 1234;
2. char c = (char) 100;
3. int i = 3;
   double d = 1.0 + i;
   // double d = 1.0 + (double) i;

자동으로 형 변환하는 것을 산술 변환이라고 한다.

자동 형 변환의 규칙

  • 기존의 값을 최대한 보존할 수 있는 타입으로 자동 변환
  • 표현 범위가 넓은 쪽으로 변환하여 값 손실을 줄인다.
  • char와 short는 같은 2byte지만 값의 범위가 달라 자동 형 변환이 될 수 없다.

자동 형 변환의 타입 나열

// 1byte => 2byte => 4byte => 8byte => 4byte => 8byte

byte  => short => int   => long  => float => double
	  char =>

위의 순서대로 변환 시 자동 변환이 된다.

반대 방향으로 변환시 캐스팅 연산자를 써줘야 한다.

형 변환의 정리

  1. boolean을 제외한 나머지 7개의 기본형은 서로 형 변환이 가능하다.
  2. 기본형과 참조형은 서로 형 변환할 수 없다.
  3. 서로 다른 타입 간의 연산은 형 변환하는 것이 원칙이나 작은 범위에서 큰 범위로 변환 시 캐스팅 연산자 생략 가능하다.

'개발 언어 > Java' 카테고리의 다른 글

[Java] 제어문  (0) 2021.08.18
[Java] 연산자  (0) 2021.08.18
[Java] 실수형의 소수점 표현 방식과 BigDecimal  (0) 2021.08.13
[Java] 오버 플로우, 언더 플로우  (0) 2021.08.12
[Java] 상수와 리터럴  (0) 2021.08.11

실수형의 종류

  범위 bit byte
float 1.4E-45 ~ 3.4E38 32 4
double 4.9E-324 ~ 1.8E308 64 8

실수형의 저장 형식

  부호 (Sign) 지수 (Exponent) 가수 (Mantissa)
float 1 8 23
double 1 11 52

소수 점의 표현 방식

  • 소수 점의 표현 방식은 두 가지가 있으며 두 가지 방식은 고정 소수점 방식부동 소수점 방식이다.
  • 컴퓨터는 정수와 마찬가지로 실수를 2진수로 표현해야 하기 때문에 실수를 표현하는 것이 정수를 표현하는 것보다 많이 복잡하다.
  • 10진수의 유한 소수가 2진수로 무한 소수가 될수 있어 2진수로 10진수를 정확하게 표현하기 어렵고 버려지는 값들로 인해 오차가 발생한다.

고정 소수점 방식

  • 부호 : 0이면 양수, 1이면 음수

각 위치마다 2진수가 저장되기 때문에 표현할수 있는 범위가 제한적이다.

총 32bit로 표현 가능한 실수의 범위와 정밀도가 제한적이어서 잘 사용하지 않는다.

 

부동 소수점 방식

  • 부호 (Sign) : 0이면 양수, 1이면 음수
  • 지수부 (Exponent) : 소수점의 위치를 나타낸다.
  • 가수부 (Mantissa) : 양의 정수를 표현한다.
부동 소수점은 IEE 754 표준 방식을 따르고 있다.

부동 소수점 방식의 각 위치의 bit는 타입에 맞는 실수형 bit와 동일하다.

고정 소수점 방식보다 넓은 범위와 높은 정밀도를 가지고 있기 때문에 많은 시스템에서 부동 소수점 방식을 사용한다.

부동 소수점 방식의 오차

double num = 0.1;

for(int i = 0; i < 1000; i++) {
	num += 0.1;
}

System.out.println(num);

위의 예상 결과가 100으로 예상이 되지만 실제로는 100.09999999999859가 출력된다.

이처럼 컴퓨터가 연산하는 모든 실수형 연산은 작은 오차가 있다.이런 경우 작은 오차에도 민감한 금융 업계에서는 이 오차가 큰 영향을 미칠 수 있다.

부동 소수점 방식의 오차 해결 방법

해결 방법은 BigDecimal 클래스를 사용하는 것이다.

 

BigDecimal의 특성

  • BigDecimal은 실수형과 달리 정수를 이용하여 실수를 표현한다.
  • 오차가 없는 2진수 정수로 변환하여 다룬다.
  • 실수를 정수와 10의 제곱의곱으로 표현한다. ex) 정수 * 10^-scale
  • 정수를 저장하기 위해 BigInteger를 사용한다.

BigDecimal의 생성

BigDecimal bd = new BigDecimal("123.456789"); // 문자열 리터럴
BigDecimal bd = new BigDecimal(123.456789); // 실수형 리터럴
BigDecimal bd = new BigDecimal(123456789); // 정수형 리터럴
BigDecimal bd = BigDecimal.valueOf(123.456789); // 실수형 리터럴
BigDecimal bd = BigDecimal.valueOf(123456789); // 정수형 리터럴

생성의 예제에서 실수형 타입의 값을 매개변수로 사용하면 오차가 발생한다.

BigDecimal bd = new BigDecimal(0.1); // 0.100000....5511...
BigDecimal bd = new BigDecimal("0.1"); // 0.1

BigDecimal의 연산

BigDecimal b = new BigDecimal("123");

// 더하기
BigDecimal b1 = b.add(BigDecimal.ONE); // 124
// 빼기
BigDecimal b2 = b.subtract(BigDecimal.TEN); // 113
// 나누기
BigDecimal b3 = b.divide(new BigDecimal("10")); // 12
// 나머지
BigDecimal b4 = b.remainder(new BigDecimal("10")); // 3;

BigDecimal의 반올림

BigDecimal b1 = new BigDecimal("12.34").setScale(0, RoundingMode.UP); // 13 UP
BigDecimal b2 = new BigDecimal("-12.34").setScale(0, RoundingMode.UP); // -13 UP

BigDecimal b3 = new BigDecimal("12.34").setScale(0, RoundingMode.DOWN); // 12 DOWN
BigDecimal b4 = new BigDecimal("-12.34").setScale(0, RoundingMode.DOWN); // -12 DOWN

BigDecimal b5 = new BigDecimal("12.34").setScale(0, RoundingMode.CEILING); // 13 CEILING
BigDecimal b6 = new BigDecimal("-12.34").setScale(0, RoundingMode.CEILING); // -12 CEILING

BigDecimal b7 = new BigDecimal("12.34").setScale(0, RoundingMode.FLOOR); // 12 FLOOR
BigDecimal b8 = new BigDecimal("-12.34").setScale(0, RoundingMode.FLOOR); // -13 FLOOR

BigDecimal b9 = new BigDecimal("12.44").setScale(0, RoundingMode.HALF_UP); // 12 HALF_UP
BigDecimal b10 = new BigDecimal("12.54").setScale(0, RoundingMode.HALF_UP); // 13 HALF_UP

BigDecimal b11 = new BigDecimal("12.50").setScale(0, RoundingMode.HALF_DOWN); // 12 HALF_DOWN
BigDecimal b12 = new BigDecimal("12.61").setScale(0, RoundingMode.HALF_DOWN); // 13 HALF_DOWN

BigDecimal b13 = new BigDecimal("12.50").setScale(0, RoundingMode.HALF_EVEN); // 12 HALF_EVEN
BigDecimal b14 = new BigDecimal("12.61").setScale(0, RoundingMode.HALF_EVEN); // 13 HALF_EVEN

BigDecimal b15 = new BigDecimal("12").setScale(0, RoundingMode.UNNECESSARY); // 12 UNNECESSARY
BigDecimal b16 = new BigDecimal("12.1").setScale(0, RoundingMode.UNNECESSARY); // ArithemeticException UNNECESSARY
  • setScale의 RoundingMode를 설정하지 않으면 기본으로 UNNECESSARY가 설정된다.
  • setScale의 첫번째 인자 값은 소수점 자릿수이다. 0번부터 시작하며 몇 번째 소수점을 올림 또는 내림할 것인지 지정하는 것이다.
  • setScale의 두번째 인자 값은 올림, 반올림, 내림, 반내림 등 어떤 모드로 설정할 것인지에 대한 값이다.

BigDecimal의 반올림 정리표

아래의 표는 RoundingMode enum을 참고하였다.

  UP DOWN CEILING FLOOR HALF_UP HALF_DOWN HALF_EVEN UNNECESSARY
5.5 6 5 6 5 6 5 6 throw ArithmeE..
2.5 3 2 3 2 3 2 2 throw ArithmeE..
1.6 2 1 2 1 2 2 2 throw ArithmeE..
1.1 2 1 2 1 1 1 1 throw ArithmeE..
1.0 1 1 1 1 1 1 1 1
-1.0 -1 -1 -1 -1 -1 -1 -1 -1
-1.1 -2 -1 -1 -2 -1 -1 -1 throw ArithmeE..
-1.6 -2 -1 -1 -2 -2 -2 -2 throw ArithmeE..
-2.5 -3 -2 -2 -3 -3 -2 -2 throw ArithmeE..
-5.5 -6 -5 -5 -6 -6 -5 -6 throw ArithmeE..
  • UP : 양수 -> 올림, 음수 -> 내림
  • DOWN : 양수 -> 내림, 음수 -> 올림
  • CEILING : 올림
  • FLOOR : 내림
  • HALF_UP : 5이상 올림, 5 미만 버림 (반올림)
  • HALF_DOWN : 6이상 올림, 6 미만 버림 (반올림)
  • HALF_EVEN : 자리의 값이 짝수 -> HALF_DOWN, 홀수 -> HALF_UP
  • UNNECESSARY : 나눗셈 결과가 딱 떨어지는 수가 아니면 throw ArithemeticException 발생

참고

* http://tcpschool.com/java/java_datatype_floatingPointNumber

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

* https://madplay.github.io/post/the-need-for-bigdecimal-in-java

 

자바 BigDecimal: 정확한 실수의 표현과 부동 소수점

자바에서 정확하게 실수를 표현하려면 어떻게 해야 할까? 그리고 부동 소수점 방식이란 무엇일까?

madplay.github.io

 

'개발 언어 > Java' 카테고리의 다른 글

[Java] 연산자  (0) 2021.08.18
[Java] 형변환  (0) 2021.08.18
[Java] 오버 플로우, 언더 플로우  (0) 2021.08.12
[Java] 상수와 리터럴  (0) 2021.08.11
[Java] 기본형과 참조형  (0) 2021.08.11

오버 플로우란?

해당 타입의 범위를 넘어서는 것을 오버플로우라고 한다.

오버플로우는 에러가 발생하지 않지만 예상과 다른 결과가 나온다.

 

정수형

정수형의 저장 형식과 범위

저장 형식

  • S : 부호 비트 (양 : 0, 음: 1)
  • N : 타입의 크기(bit)

범위

  • byte : -128 ~ 127 (2^7 ~ 2^7-1)
  • short : -32,768 ~ 32,767 (2^15 ~ 2^15-1)
  • int : - 2,147,483,648 ~ 0 ~ 2,147,483,647 (2^31 ~ 2^31-1)
  • long : -9,223,372,036,854,775,808 ~ 0 ~ 9,223,372,036,854,775,807 (2^63 ~ 2^63-1)

정수형의 선택 기준

  • JVM의 피연산자 스택(operand stack)이 피연산자를 4byte단위로 저장하기 때문에 int를 사용하는 것이 효율적이다.

정수형의 오버 플로우

2진수 1111 + 0001 = 10000이다.

하지만 2진수는 4bit를 범위로 가지고 있어서 0000이 된다.

반대로 0000 - 0001 = 9999이다.

 

즉, 최대값 + 1 = 최소값이 되고 최소값 - 1 = 최대값이 된다.

  부호 없는 정수 2진수 부호 있는 정수  
  0 0000 0  
  1 0001 1  
  2 0010 2  
  3 0011 3  
  4 0100 4  
  5 0101 5  
  6 0110 6  
  7 0111 7 오버 플로우 발생
  8 1000 -8
  9 1001 -7  
  10 1010 -6  
  11 1011 -5  
  12 1100 -4  
  13 1101 -3  
  14 1110 -2  
오버 플로우 발생 16 1111 -1  
0 0000 0  
  1 0001 1  
  2 0010 2  
  • 부호 없는 정수 -> char 0 ~ 65,535
  • 부호 있는 정수 -> short -32,768 ~ 32,767

실수형의 저장 형식과 범위

저장 형식

  • S (Sign) : 부호
  • E (Exponent) : 지수
  • M (Mantissa) : 가수

float

  • 저장 형식 : S(1) + E(8) + M(23) = 32bit (8byte)
  • 범위 : 1.4E-45 ~ 3.4E38

double

  • 저장 형식 : S(1) + E(11) + M(52) = 64bit (16byte)
  • 범위 : 4.9E-324 ~ 1.8E308

실수형의 오버 플로우, 언더 플로우

  • 오버 플로우 : 무한대 (infinity)
  • 언더 플로우 : 양의 최소값보다 작은 값으로 0이 된다.

'개발 언어 > Java' 카테고리의 다른 글

[Java] 형변환  (0) 2021.08.18
[Java] 실수형의 소수점 표현 방식과 BigDecimal  (0) 2021.08.13
[Java] 상수와 리터럴  (0) 2021.08.11
[Java] 기본형과 참조형  (0) 2021.08.11
[Java] 명명 규칙  (0) 2021.08.11

+ Recent posts