3-3. 산술 연산자

Hyun Jun·2022년 1월 22일
0

자바의 정석

목록 보기
11/52
post-thumbnail
post-custom-banner

산술 연산자

사칙 연산자(+, -, *, /)와 나머지 연산자(%)로 구성.

 

사칙 연산자

수학의 사칙 연산과 같다. 피연산자가 정수형인 경우 0으로 나눌 수 없음. 부동소수형 값인 0.0f나 0.0d로 나누면 Infinity가 반환됨.

📌   [주의] 피연산자의 타입에 따라 연산 결과가 예상과 달라질 수 있음.

int a = 7;
int b = 2;
System.out.println(a / b); // 3.5가 아닌 3이 출력된다.

위 예시처럼 int끼리 나눗셈을 하면 결과값도 정수형인 int이기 때문에 소수점 아래 값을 표기할 수 없어 버려짐. (반올림이 아님에 주의)

byte a = 17;
byte b = 27;
byte c = a + b; // 컴파일 에러 발생

위 예시에서 컴파일 에러가 발생한 이유는 a + b 값이 int형인데 byte형으로 선언한 변수 c에 담으려고 했기 때문. 앞서 보았던대로 int보다 작은 타입끼리 연산하면 자동적으로 피연산자들을 int로 통일시키므로 결과값도 int가 됨. 아래처럼 고쳐야함.

byte c = (byte)(a + b);

 

byte a = 20;
byte b = 30;
byte c = (byte)(a * b); // c의 값은 600이 아니라 88이 됨.

이번에는 결과값을 담을 변수 c의 타입에 맞게 형변환을 시켰는데, 에러는 발생하지 않았지만 예상 밖의 결과 값이 나옴. 연산 결과가 byte 타입의 범위를 초과했기 때문에 int로는 표현 가능했던 결과값이 byte로 형변환될 때, 이진수 앞부분이 잘리고 88만 남겨짐.

 

연산 결과의 데이터 손실을 방지하기 위해 충분히 큰 범위의 타입을 사용하는 것이 권장됨.

이 때, 결과값의 타입을 넉넉하게 하는 것도 중요하지만, 피연산자 자체의 타입부터 넉넉한 것으로 설정하는게 좋음.

int a = 1_000_000;
int b = 2_000_000;
long c = a * b; // c = -1454759936

결과값이 담기는 변수 clong 타입이니 문제 없을 것 같지만, 애초에 int 끼리 연산했으므로 결과값도 int라서 예상 값인 2000000000000 이 int 범위 내에서 -1454759936 이 되어 반환됨.

long a = 1_000_000;
long b = 2_000_000;
long c = a * b; // c = 2000000000000

피연산자 타입도 long으로 바꾸니 정상 출력됨.

 

문자 간의 연산

문자(char)도 결국 숫자인 유니코드 값으로 변환되어 저장되므로 문자 간의 연산은 숫자간의 연산과 동일한 원리가 적용됨.

char c1 = 'a';
char c2 = (char)(c1 + 1); // c2 = 'b'

c1은 메모리상에서는 정수 97 ('a'의 유니코드)이므로, 1을 더하면 정수 98이 됨. 이 결과값을 다시 char로 형변환하면 c2에는 유니코드 98에 해당하는 문자 b가 담김.

char c3 = 'a' + 1; // c3 = 'b'

c3는 결과값을 char로 형변환하지 않았는데도 컴파일 에러가 없음. 변수를 참조하지 않고 단순 리터럴끼리 연산하면 컴파일러가 미리 연산을 수행해 실제 런타임에는 연산이 수행되지 않고 이미 'b'라는 값이 c3에 담긴 채로 실행된다.

profile
Back-end Engineer 👨‍💻
post-custom-banner

0개의 댓글