Java
연산자
lleesla
2024. 6. 17. 23:10
연산자와 연산식
- 프로그램에서 데이터를 처리하여 결과를 산출하는 것을 연산이라고 한다.
- 연산에 사용되는 표시나 기호를 연산자라고 하고, 연산이 되는 데이터를 피연산자라고 한다.
- ex) + , - , / , * : 연산자
- ex) x, y : 피연산자
- 연산자별로 연산 후 산출되는 값의 타입이 다르다.
- 예를 들어 산술 연산자는 숫자타입(byte, short, int, long, float, double), 비교 연산자와 논리 연산자는 논리 타입으로 나온다.
연산의 방향과 우선순위
x > 0 && y < 0
다음의 연산식에서 &&가 먼저 처리될까 등호가 먼저 처리될까?
프로그램에서는 연산자의 연산 방향과 연산자 간의 우선순위가 정해져 있다.
우선순위가 같은 연산자의 경우 왼쪽에서 오른쪽으로 연산을 시작한다.
a = b = c = 5
위의 연산식은 a=b, b=c, c=5 순서로 진행된다.
1. 단항, 이항 , 삼항 연산자 순으로 우선순위를 가진다.
2. 산술, 비교, 논리, 대입 연산자 순으로 우선순위를 가진다.
3. 단항과 대입 연산자를 제외한 모든 연산의 방향은 왼쪽에서 오른쪽이다.
4. 복잡한 연산식에서는 괄호를 사용해서 우선순위를 정해준다.
단항 연산자
- 단항 연산자는 피연산자가 단 하나뿐인 연산자를 말한다.
- 부호 연산자(+,-), 증감 연산자(+ +, - -), 논리 부정 연산자(!), 비트 반전 연산자(~)가 여기에 포함된다.
부호연산자(+, -)
- 부호 연산자에는 양수 및 음수를 표시하는 +, -가 있다.
- boolean 타입과 char 타입을 제외한 나머지 기본 타입에 사용할 수 있다.
- 산술 연산자이기도 하고, 부호 연산자이기도 하다.
- 부호 연산자로 쓰일 때에는 하나의 피연산자만 필요하다.
- 일반적으로 부호 연산자를 다음과 같이 정수 및 실수 리터럴 앞에 붙어 양수 및 음수를 표현한다.
int i1 = +100;
double d1 = +3.14;
- 부호 연산자는 변수 값의 부호를 유지하거나 바꾸기 위해 사용된다.
-
- 연산자는 변수 값의 부호를 유지한다.
-
- 연산자는 변수 값의 부호를 양수는 음수로, 음수는 양수로 바꾼다.
int x = -100;
int result1 = +x;
int result2 = -x;
- 위 코드를 보면 result1에는 x 값인 음수 -100이 그대로 저장되고 result2는 부호가 변경된 양수 100이 저장되는 것을 알 수 있다.
- 이 연산자를 사용할 때 주의 점은 산출 타입은 int 타입이 된다는 것이다. 예를 들어 short 타입 값을 부호 연산하면 int 타입 값으로 바뀌는 것이다. 그래서 다음 코드는 컴파일 에러가 발생한다.
short s = 100;
short result = -s; //컴파일 에러 발생
따라서 아래와 같이 코드가 변경 되어야 한다.
short s = 100;
int result3 = -s;
증감 연산자(+ +, - -)
- 증감 연산자는 변수의 값을 1 증가(+ +) 시키거나 1 감소(- -) 시키는 연산자를 말한다.
- boolean 타입을 제외한 모든 기본 타입의 피연산자에 사용할 수 있다.
연산직 설명
+ + | 피연산자 | 다른 연산을 수행하기 전에 피연산자의 값을 1 증가시킴 |
- - | 피연산자 | 다른 연산을 수행하기 전에 피연산자의 값을 1 감소시킴 |
피연산자 | + + | 다른 연산을 수행한 후에 피연산자의 값을 1 증가시킴 |
피연산자 | - - | 다른 연산을 수행한 후에 피연산자의 값을 1 감소시킴 |
-
-
- 연산자는 피연산자의 기존 값에 1을 더해서 그 결과를 다시 피연산자에 저장한다.
-
- 예를 들어 num 변수의 기존 값이 5라면 ++num 연산 후 num 변수의 값은 6이 된다.
- 그래서 + + 연산자를 증가 연산자라고 부른다.
-
-
- 연산자는 피연산자의 기존 값에 1을 뺀 후 그 결과를 다시 피연산자에 저장한다.
-
- 예를 들어 num 변수의 기존 값이 5라면 - -num 연산 후 num 변수의 값은 4가 된다.
- 그래서 - - 연산자를 감소 연산자라고 부른다.
- 연산식에서 증감 연산자만 있는 경우에는 증감 연산자가 변수 앞 뒤 어디든 위치해도 상관 없다.
int x = 1;
int y = 1;
int result1 = ++x + 10;
int result2 = y++ + 10;
- 위 코드를 보면 result1에는 12가 저장된다.
논리 부정 연산자(!)
- 논리 부정 연산자는 true를 false로, false를 true로 변경하기 때문에 boolean 타입에만 사용할 수 있다.
- 조건문과 제어문에서 사용되어 조건식의 값을 부정하도록 해서 실행 흐름을 제어할 때 주로 사용된다.
비트 반전 연산자(~)
- 비트 반전연산자는 정수 타입(byte, short, int, long)의 피연산자에만 사용되며 피연산자를 2진수로 표현했을 때 비트값인 0을 1로, 1은 0으로 반전한다.
- 모든 비트가 반전되기 때문에 부호가 반대인 새로운 값이 산출된다.
이항 연산자
이항 연산자는 피연산자가 두 개인 연산자를 말한다.
*산술 연산자(+, -, , /, %)
- 산술 연산자는 boolean 타입을 제외한 모든 기본 타입에 사용할 수 있다.
- / 는 나눗셈, %은 나머지를 돌려주는 연산자이다.
오버플로우 탐지
- 산술 연산을 할 때 주의점은 연산 후의 산출 값이 산출 타입으로 충분히 표현 가능한지 봐야한다.
- 산출 타입으로 표현할 수 없는 값이 산출될 경우, 오버플로우가 발생하고 쓰레기 값을 언을 수 있기 때문이다.
int x = 1000000;
int y = 1000000;
int z = x * y;
- 위 코드는 컴파일 에러가 발생하지는 않는다. 하지만 변수 z에 올바른 값이 저장되지 않는다.
- int타입에 저장될 수 있는 값의 범위를 초과하기 때문이다.
- 실제로 연산을 하면 쓰레기값 -727379968을 얻게 된다.
- 올바른 값을 얻기 위해서는 둘 중(x, y) 하나라도 long 타입이 되어야 하고, z가 long 타입이어야 한다.
정확한 계산은 정수 사용
- 정확한 계산을 해야 할 때는 부동소수점(실수) 타입을 사용하지 않는 것이 좋다.
- 사과 1개를 0.1 단위 10조각으로 보고, 그 중 7조각(0.7)을 뺀 3조각(0.3)을 result 변수에 저장한다.
- result 변수는 당연히 0.3일 것이다.
int apple = 1;
double pieceUnit = 0.1;
int number = 7;
double result = apple - number*pieceUnit;
- 출력 결과를 보면 result의 값은 0.29999999999993이 되어 정확히 0.3이 되지 않는다.
- 부동소수점 타입(float, double)은 0.1을 정확히 표현할 수 없어 근사치로 처리하기 때문이다.
- 따라서 정확한 계산을 위해서는 다음과 같이 해야한다.
int apple = 1;
int totalPieces = apple * 10;
int number = 7;
int temp = totalPieces - number;
double result = temp/10.0;
NaN과 Infinity 연산
- / 또는 % 연산자를 사용할 때도 주의할 점이 있다.
- 좌측 피연산자가 정수 타입인 경우 나누는 수인 우측 피연산자는 0을 사용할 수 없다.
- 실행시 컴파일은 정상적으로 되지만 예외가 발생한다.
- 하지만 실수 타입인 0.0 또는 0.0f로 나누면 예외가 발생하지 않고, / 연산의 결과는 무한대 값을 가지며, % 연산의 결과는 NaN(Not a Number)을 가진다.
입력값의 NaN 검사
- NaN은 부동 소수점 숫자에서 발생할 수 있는 특수한 값으로, 유효한 숫자가 아님을 나타낸다.
- 입력값의 NaN 검사는 주어진 값이 NaN인지 여부를 확인하는 과정을 말한다.
- 대부분의 프로그래밍 언어는 이를 확인하기 위한 함수나 메서드를 제공하며, 일반적으로 isNaN() 함수를 사용한다.
- 이 함수는 주어진 값이 NaN이면 true를 반환하고, 그렇지 않으면 false를 반환한다.
- NaN 검사는 데이터 유효성 검사나 계산 결과의 정확성을 보장하는 중요한 과정이다.
비교 연산자(<, ≤, >, ≥, ==, ≠)
- 비교 연산자는 대소 또는 동등을 비교해서 boolean 타입인 true/false를 산출한다.
- 대소 연산자는 boolean 타입을 제외한 기본 타입에 사용할 수 있고, 동등 연산자는 모든 타입에 사용될 수 있다.
- 주로 제어문인 조건문(if), 반복문(for, while)에서 주로 이용되어 실행흐름을 제어할 때 사용된다.
- 만약 피연산자가 char 타입이면 유니코드 값으로 비교 연산을 수행한다.
('A' < 'B') -> (65 < 66)
- 0.1 == 0.1f와 같은 경우엔 결과 값이 false가 나온다.
- 그 이유는 0.1f가 0.1을 정확히 표현할 수 없기 때문이다.
논리 연산자(&&, ||, &, |, ^, !)
- 논리 연산자는 논리곱(&&), 논리합(||), 배타적 논리합(^) 그리고 논리 부정(!) 연산을 수행한다.
- 논리 연산자의 피연산자는 boolean 타입만 사용할 수 있다.
- &&와 &는 산출 결과는 같지만 연산 과정이 다르다.
- &&는 앞의 피연산자가 false라면 뒤의 피연산자를 평가하지 않고 바로 false라는 산출 결과를 낸다.
- 왜냐하면 하나라도 false라면 전체 연산식은 false이기 때문이다.
- &는 두 피연산자 모두를 평가해서 산출 결과를 낸다.
- 따라서 &보다는 &&가 더 효율 적으로 동작한다.
비트 논리 연산자(&, |, ^, ~)
- 비트 AND(&): 두 피연산자의 각 비트가 모두 1일 때 1을 반환한다.
- 비트 OR(|): 두 피연산자의 각 비트 중 하나 이상이 1일 때 1을 반환한다.
- 비트 XOR(^): 두 피연산자의 각 비트가 서로 다를 때 1을 반환한다.
- 비트 NOT(~): 피연산자의 각 비트를 반전시킨다(0은 1로, 1은 0으로).
비트 이동 연산자(<<, >>, >>>)
- 비트 왼쪽 시프트(<<): 피연산자의 비트를 왼쪽으로 지정된 수 만큼 이동시킨다. 오른쪽에 새로 생성된 비트는 0으로 채워진다.
- 비트 오른쪽 시프트(>>): 피연산자의 비트를 오른쪽으로 지정된 수 만큼 이동시킨다. 왼쪽에 새로 생성된 비트는 원래의 부호 비트와 같은 값으로 채워진다(부호 보존).
대입 연산자
- 대입 연산자는 오른쪽 피연산자의 값을 좌측 피연산자인 변수에 저장하는 것이다.
- 오른쪽 피연산자는 리터럴 및 변수, 그리고 다른 연산식이 올 수 있다.
- 오른쪽 피연산자의 값을 변수에 저장하는 단순 대입 연산자가 있고, 정해진 연산을 수행한 후 결과를 변수에 저장하는 복합 대입 연산자도 있다.
삼항 연산자
- 삼항 연산자는 세 개의 피연산자를 필요로 하는 연산자를 말한다.
- ? 앞의 조건식에 따라 콜론(:) 앞뒤의 피연산자가 선택된다고 해서 조건 연산식이라고 부르기도 한다.
조건식 ? ture : false
- 조건식을 연산하여 조건이 참이면 삼항 연산자의 결과는 ture가 된다.
- 조건이 거짓이면 결과는 false가 된다.
- true 자리와 false 자리에는 주로 값이 오지만 연산식이 올 수도 있다.