기본 이해
산술 연산자는 수학적 계산을 수행하는 프로그래밍 언어의 기본 연산자다.
계산기의 기본 버튼들(+, -, ×, ÷)과 동일한 역할을 수행한다.
작동 방식
int a = 10;
int b = 3;
int sum = a + b; // 덧셈
int diff = a - b; // 뺄셈
int mult = a * b; // 곱셈
int div = a / b; // 나눗셈
int mod = a % b; // 나머지
자바의 타입 승격(Type Promotion) 규칙을 따른다.
///데이터 타입 크기
byte: 1바이트 (-128 ~ 127)
char: 2바이트 (0 ~ 65535)
short: 2바이트 (-32768 ~ 32767)
int: 4바이트 (-2^31 ~ 2^31-1)
long: 8바이트 (-2^63 ~ 2^63-1)
float: 4바이트 (±3.4E-38 ~ ±3.4E+38)
double: 8바이트 (±1.7E-308 ~ ±1.7E+308)
자바의 연산 규칙
- 모든 byte, short, char는 int로 변환 (정수 연산의 기본 단위가 int)
- 피연산자 중 하나가 long이면 다른 피연산자도 long으로 변환
- 피연산자 중 하나가 float이면 다른 피연산자도 float으로 변환
- 피연산자 중 하나가 double이면 다른 피연산자도 double로 변환
byte b = 10;
short s = 20;
char c = 'A'; // 65
int i = 30;
long l = 40L;
float f = 50.0f;
double d = 60.0;
// byte, short, char -> int로 변환되는 연산
int result1 = b + s; // byte + short = int
int result2 = s + c; // short + char = int
int result3 = b + c; // byte + char = int
// long 포함 연산
long result4 = i + l; // int + long = long
long result5 = s + l; // short + long = long
// float 포함 연산
float result6 = l + f; // long + float = float
float result7 = i + f; // int + float = float
// double 포함 연산
double result8 = f + d; // float + double = double
double result9 = l + d; // long + double = double
// 여러 연산자 사용
int result10 = b * s / c; // byte * short / char = int
long result11 = l * i + s; // long * int + short = long
float result12 = f / i * l; // float / int * long = float
double result13 = d * f - l; // double * float - long = double
실제로 디버그를 해보면 오류가 나지 않고 변수에 할당이 되는 것을 알 수 있다. 이는 할당하려는 변수의 형식대로 변환됐다는 것을 의미한다.
존재 이유와 목적
필요성
- 수학적 계산 수행
- 데이터 처리 및 변환
- 알고리즘 구현
실제 개발에서의 역할
- 금융 계산
- 통계 처리
- 게임 로직 구현
- 데이터 분석
핵심 구성요소
주요 연산자
- + (덧셈)
- - (뺄셈)
- * (곱셈)
- / (나눗셈)
- % (모듈로/나머지)
주의사항과 일반적 오류
정수 나눗셈에서 소수점 손실
// 정수 나눗셈 - 소수점 손실
int a = 5;
int b = 2;
int result1 = a / b; // 2 (2.5가 아님)
// 정수끼리 나눗셈 결과를 실수로 저장해도 이미 손실된 값이 저장됨
double result2 = a / b; // 2.0 (2.5가 아님)
// 올바른 실수 계산을 위해서는 최소 하나의 피연산자가 실수여야 함
double result3 = (double)a / b; // 2.5
double result4 = a / (double)b; // 2.5
double result5 = (double)a / (double)b; // 2.5
기본적으로 IntelliJ 같은 IDE에서 이런 경우를 확인해주긴 한다.
0으로 나누기 시도
int a = 10;
int b = 0;
int result1 = a / b;
정수를 0으로 나눌 경우
ArithmeticException 오류가 발생한다.
double c = 10.0;
double d = 0.0;
double result2 = c / d;
double e = 0.0;
double f = 0.0;
double result3 = e / f;
실수 를 0으로 나눌 경우
- 실수를 0으로 나누면 Infinity를 반환한다.
- 실수 0을 0으로 나누면 NaN 반환한다.
Infinity와 NaN은 모두 double(또는 float) 타입의 특수한 값이다. 실수(floating-point) 타입에 Infinity와 NaN이 존재하는 이유는 IEEE 754 표준(컴퓨터에서 실수를 표현하는 국제 표준)때문인데 수학적 연산의 연속성을 위해 Infinity를 포함하고 잘못된 연산의 결과를 표현하기 위해 NaN을 포함한다.
오버플로우/언더플로우 미고려
오버플로우와 언더플로우는 범위를 가진 타입의 고질적인 문제점이다. 이러한 문제는 데이터 타입의 표현 범위 제한 때문에 발생하는데 예를 들면 byte 타입은 -128 ~ 127까지 밖에 표현이 되지 않는데 -128 미만을 표현하거나 127 초과를 표현하려고 해서 발생하게 된다. 오버플로우의 경우 표현할 수 있는 최대치나 최소치를 넘어서는 값이 나올 경우 지구를 한바퀴 돈 것처럼 반대쪽으로 빙 돌아서 반대쪽 방향의 최댓값으로 변환되는 것이다. byte 타입의 경우 최대치를 넘거나 최소치를 넘거나 모두 오버플로우다.
언더플로우의 경우 실수형에서만 사용되는 용어인데 실수형의 최소치보다 작아지면 결과값이 0이 된다.
오버플로우(Overflow)
- 정수형의 경우
- 연산 결과가 해당 타입의 표현 범위를 벗어나는 모든 상황
- 최대값 초과와 최소값 미만 모두 오버플로우로 통칭
- 예: byte에서 127 + 1 = -128 또는 -128 - 1 = 127
- 실수형의 경우
- 연산 결과가 해당 타입의 최대값을 초과하는 경우
- 결과값이 Infinity가 됨
- 예: Double.MAX_VALUE * 2 = Infinity
언더플로우(Underflow)
- 실수형에서만 사용되는 용어
- 연산 결과가 표현 가능한 최소 정규화 값보다 작은 경우
- 결과값이 0이 됨
- 예: Double.MIN_VALUE / 2 = 0
///정수 오버플로우
byte a = 127;
byte b = -128;
a++;
b--;
실제로 증감 연산자를 사용하면 값이 오버플로우되어서 반대쪽으로 값이 넘어가 버리는 것을 확인할 수 있다.
// 1. 정수 오버플로우
int maxInt = Integer.MAX_VALUE; // 2147483647
int result1 = maxInt + 1; // -2147483648 (오버플로우)
// 2. 정수 언더플로우
int minInt = Integer.MIN_VALUE; // -2147483648
int result2 = minInt - 1; // 2147483647 (언더플로우)
// 3. 실수 오버플로우
double maxDouble = Double.MAX_VALUE;
double result3 = maxDouble * 2; // Infinity (오버플로우)
// 4. 실수 언더플로우
double minPositiveDouble = Double.MIN_VALUE; // 양수 최소값
double result4 = minPositiveDouble / 2; // 0.0 (언더플로우)
// 5. 계산 결과 예상과 다른 경우
int a = 1000000;
int b = 1000000;
int result5 = a * b; // 예상값: 1000000000000, 실제: -727379968 (오버플로우)
// 올바른 계산을 위해 long 사용
long result6 = (long)a * b; // 1000000000000
디버깅 포인트
// 잘못된 예
int result = 5 / 2; // 결과: 2
// 올바른 예
double result = 5.0 / 2; // 결과: 2.5
비교 분석
정수 연산 vs 실수 연산
특성 | 정수 연산 | 실수 연산 |
---|---|---|
정밀도 | 정확함 | 근사값 가능 |
속도 | 빠름 | 상대적으로 느림 |
메모리 | 적게 사용 | 더 많이 사용 |
용도 | 카운팅, 인덱싱 | 과학 계산, 금융 |
실무 활용
코드 예시
// 금융 계산
public double calculateInterest(double principal, double rate, int years) {
return principal * (1 + rate * years);
}
// 평균 계산
public double calculateAverage(int[] numbers) {
int sum = 0;
for(int num : numbers) {
sum += num;
}
return (double)sum / numbers.length;
}
베스트 프랙티스
- 나눗셈 전 0 체크
- 큰 숫자 연산 시 long 사용
- 금융 계산 시 BigDecimal 사용
[관련 개념]
- 변수와 데이터 타입
- 형변환
[후속 개념]
- 비트 연산자
- 논리 연산자
- 복합 대입 연산자
'Java > 자바 학습' 카테고리의 다른 글
자바의 논리 연산자 (1) | 2025.05.21 |
---|---|
자바의 비교 연산자 (1) | 2025.05.21 |
자바의 부호/증감 연산자 (0) | 2025.05.19 |
자바 싱글톤 패턴 (Singleton Pattern) (0) | 2025.05.18 |
Java의 this 키워드 (1) | 2025.05.18 |