ch3_연산자

통합 문서입니다.


1. 문제

문제

ch3 범위(산술/비교/논리/대입/비트/시프트/삼항 연산자) 문제입니다.


A. 기초 문제

  1. 두 정수를 입력받아 합, 차, 곱, 몫, 나머지를 출력하시오.
  2. 세 점수를 입력받아 평균을 구하고, 평균이 60 이상이면 PASS, 아니면 FAIL을 출력하시오.
  3. 정수 하나를 입력받아 짝수/홀수를 판별하시오.
  4. 나이를 입력받아 20 이상 65 미만이면 일반 요금, 아니면 우대 요금을 출력하시오.

B. 비교/논리 연산

  1. 아이디/비밀번호가 모두 일치할 때만 로그인 성공 메시지를 출력하시오.
  2. 정수 3개를 입력받아 최댓값/최솟값을 구하시오(Math.max/min 사용 금지).
  3. 세 변의 길이를 받아 삼각형 성립 여부를 판별하시오.
  4. 윤년 판별식을 논리 연산자로 구현하시오.

C. 실수/정밀도

  1. 0.1 + 0.2 == 0.3 비교 결과를 출력하고, 왜 그런 결과가 나오는지 설명하시오.
  2. 허용 오차(EPSILON) 기반 실수 비교 함수를 작성하시오.
  3. 정수 나눗셈과 실수 나눗셈 결과가 달라지는 예제를 3개 작성하시오.

D. 비트/시프트 연산

  1. 정수 하나를 입력받아 다음을 출력하시오.
    • 2진수 문자열
    • << 1, >> 1, >>> 1 결과
  2. 비트 마스크를 사용해 권한 플래그(READ, WRITE, EXECUTE)를 구현하시오.
  3. RGB 정수값(0xRRGGBB)에서 R, G, B를 분리하는 코드를 작성하시오.
  4. 음수 시프트에서 >>>>> 결과 차이를 예제로 설명하시오.

E. 대입/증감/삼항

  1. 전위/후위 증감 연산 결과가 다른 코드를 5개 작성하고 결과를 예측한 뒤 검증하시오.
  2. short s = 1; s += 1;는 되는데 s = s + 1;가 안 되는 이유를 설명하시오.
  3. 중첩 삼항 연산자를 if-else로 리팩터링하는 연습 코드를 작성하시오.
  4. 복합 대입 연산(+=, *=)이 포함된 식에서 타입 변화를 추적하시오.

F. 디버깅 문제

다음 코드의 문제점을 찾고 수정하시오.

String role = new String("ADMIN");
if (role == "ADMIN") {
    System.out.println("관리자");
}

int total = 0;
for (int i = 1; i <= 1000000; i++) {
    total += i;
}
System.out.println(total);

수정 시 고려할 것:


G. 챌린지

  1. 계산기 프로그램을 작성하시오.
    • 입력: 피연산자 2개 + 연산자(+, -, *, /, %)
    • 0 나눗셈과 잘못된 연산자 처리 포함
  2. 비트 연산만 사용해 정수의 홀짝 판별, 절댓값 근사 함수를 작성하시오.
  3. 로그 시스템의 상태 코드를 비트 플래그로 설계하고, 조합/해제/검사 메서드를 구현하시오.

제출 체크리스트

  1. 연산자 우선순위가 헷갈리는 식에 괄호를 사용했는가?
  2. 문자열 비교에 equals를 사용했는가?
  3. 정수 오버플로우 가능성을 점검했는가?
  4. &&/||&/|의 차이를 코드에서 명확히 구분했는가?

2. 연산자

연산자

학습 목표


1. 연산자란

연산자는 피연산자(operand)에 규칙을 적용해 결과를 만드는 문법 요소다.
실무에서는 연산자 자체보다 평가 순서, 타입 승격, 부수 효과(side effect)를 이해하는 것이 중요하다.


2. 산술 연산자 (+, -, *, /, %)

2.1 기본 동작

int a = 7;
int b = 3;
System.out.println(a + b); // 10
System.out.println(a - b); // 4
System.out.println(a * b); // 21
System.out.println(a / b); // 2
System.out.println(a % b); // 1

정수 나눗셈은 소수부를 버린다.

2.2 0으로 나누기

정수:

int x = 10 / 0; // ArithmeticException

실수:

double x = 10.0 / 0.0;  // Infinity
double y = 0.0 / 0.0;   // NaN

정수/실수는 에러 처리 방식이 다르므로 구분해야 한다.

2.3 오버플로우

int max = Integer.MAX_VALUE;
System.out.println(max + 1); // 음수로 래핑

Java 정수 오버플로우는 예외 없이 wrap-around 된다.


3. 증감 연산자 (++, --)

3.1 전위/후위 차이

int i = 5;
int a = ++i; // i를 먼저 6으로 만들고 a=6
int b = i++; // b=6 대입 후 i=7

3.2 실무 권장

복잡한 식 안에서 i++를 섞으면 가독성이 급격히 떨어진다.

// 지양
arr[i++] = arr[++i] + i--;

증감과 계산은 분리하는 편이 안전하다.


4. 비교 연산자 (==, !=, >, <, >=, <=)

비교 결과는 항상 boolean이다.

int age = 20;
boolean adult = age >= 19;

4.1 실수 비교 주의

double a = 0.1 + 0.2;
System.out.println(a == 0.3); // false 가능

실수는 오차가 있으므로 허용 오차 기반 비교를 사용한다.

boolean same = Math.abs(a - 0.3) < 1e-12;

5. 동등성 비교: == vs equals

5.1 primitive

==는 값 비교다.

int x = 10;
int y = 10;
System.out.println(x == y); // true

5.2 reference

==는 참조 동일성(같은 객체인가)을 비교한다.

String s1 = new String("java");
String s2 = new String("java");
System.out.println(s1 == s2);      // false
System.out.println(s1.equals(s2)); // true

문자열/값 객체의 내용 비교는 equals가 기본이다.


6. 논리 연산자와 단락 평가

6.1 &&, ||, !

boolean a = true;
boolean b = false;
System.out.println(a && b); // false
System.out.println(a || b); // true
System.out.println(!a);     // false

6.2 단락 평가 (Short-circuit)

if (obj != null && obj.isValid()) {
    // obj null 체크 후 접근
}

이 패턴이 NPE를 줄이는 핵심이다.

6.3 &, |와의 차이

&, |는 boolean에도 쓸 수 있지만 양쪽을 항상 평가한다.

if (obj != null & obj.isValid()) { // 지양: null이면 NPE 위험
}

조건식에서는 보통 &&, ||를 사용한다.

단락 평가 흐름도

&&||에서 오른쪽 피연산자를 생략 평가하는 조건을 시각화한 그림이다.


7. 비트 연산자 (&, |, ^, ~)

정수 비트를 직접 다룬다.

int a = 0b1100;
int b = 0b1010;
System.out.println(a & b); // 0b1000
System.out.println(a | b); // 0b1110
System.out.println(a ^ b); // 0b0110
System.out.println(~a);    // 비트 반전

용도:


8. 시프트 연산자 (<<, >>, >>>)

8.1 왼쪽 시프트 <<

비트를 왼쪽으로 밀고 빈칸을 0으로 채운다.

int x = 3;       // 0011
int y = x << 2;  // 1100 -> 12

8.2 부호 유지 오른쪽 시프트 >>

부호 비트를 유지하며 오른쪽 이동한다.

int x = -8;
int y = x >> 1; // -4

8.3 부호 없는 오른쪽 시프트 >>>

왼쪽을 0으로 채운다.

int x = -8;
int y = x >>> 1; // 큰 양수

암호화, 해시, 비트 포맷 처리에서 중요하다.

시프트 연산 시각화

<<, >>, >>>가 비트를 어떻게 이동시키는지 예제로 정리한 그림이다.


9. 대입/복합 대입 연산자

기본 대입:

int n = 10;

복합 대입:

n += 5;
n *= 2;

주의 포인트:

short s = 1;
s += 1;       // 가능 (내부 캐스팅)
// s = s + 1; // 컴파일 오류 (int 결과)

복합 대입에는 숨은 캐스팅 규칙이 있어 결과를 반드시 확인해야 한다.


10. 삼항 연산자 (조건 ? 값1 : 값2)

단순 분기값 선택에 유용하다.

int score = 85;
String grade = score >= 80 ? "PASS" : "FAIL";

복잡한 삼항 중첩은 가독성을 해치므로 if로 바꾸는 것이 낫다.


11. 우선순위와 결합 방향

우선순위를 전부 암기하는 것보다 원칙을 지키는 게 좋다.

  1. 애매하면 괄호를 쓴다.
  2. 부수 효과가 있는 연산(++, --, 대입)을 식에서 분리한다.
  3. 한 줄 식이 길어지면 중간 변수를 도입한다.

예:

// 지양
boolean ok = a + b * c > d && e != 0 || f < g;

// 권장
int calc = a + (b * c);
boolean left = calc > d;
boolean right = e != 0;
boolean ok = (left && right) || (f < g);

12. 자주 나오는 실무 버그

  1. 문자열 비교를 ==로 수행
  2. 정수 나눗셈 결과를 실수라고 착각
  3. && 대신 &를 써서 불필요 평가/NPE 발생
  4. 오버플로우를 고려하지 않은 카운터/금액 연산
  5. 복합 대입의 자동 캐스팅을 모르고 타입 버그 발생

13. 정리