JavaScript

웹 개발의 필수 언어

동적인 웹 페이지 구현을 위한 핵심 프로그래밍 언어.

Java

객체지향 프로그래밍

안정적이고 확장성 있는 백엔드 개발의 대표 언어.

HTML

웹의 기초

웹 페이지의 구조를 정의하는 마크업 언어.

React

현대적 UI 라이브러리

효율적인 사용자 인터페이스 구축을 위한 JavaScript 라이브러리.

CSS

웹 디자인의 핵심

웹 페이지의 시각적 표현을 담당하는 스타일 언어.

Spring

자바 웹 프레임워크

기업급 애플리케이션 개발을 위한 강력한 프레임워크.

Java/자바 학습

자바 산술 연산자와 오버 플로우/ 언더 플로우

lamarcK 2025. 5. 19. 21:03

기본 이해

산술 연산자는 수학적 계산을 수행하는 프로그래밍 언어의 기본 연산자다.

계산기의 기본 버튼들(+, -, ×, ÷)과 동일한 역할을 수행한다.

작동 방식

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