연산자

cutiepazzipozzi·2023년 4월 13일
1

지식스택

목록 보기
18/35
post-thumbnail

각자의 종류나 기능에 대해서만 알면 될 거 같아 가볍게 써보려고 한다!
그리고 연산자이기 때문에 내가 좋아하는 수학과 많이 닮아 있는 거 같아서! ❤️

🫠연산자

주어진 변수나 리터럴에 대해 연산을 수행하기 위한
(간단하게 예시를 들면 우리가 덧셈 뺄셈 등의 계산? 연산을 하기 위해 사용하는 기호들!! +, - 같은거)

✨연산자의 종류

(단항, 대입 제외 연산 방향 →)
(아래로 내려갈수록 우선순위가 낮아짐)

(ex. 대입 연산자 =가 사용된 이 식 x = y = 5을 보면,
우리는 상식적으로 y에 5 값을 넣어주고, x에 y값인 5를 넣어준다.)

1️⃣ 단항 연산자

** 연산자가 연산을 하는데 필요로 하는 피연산자의 개수에 따라 단항, 이항, 삼항 연산자로 불림 (우선순위는 단항이 가장 높음)

1. 증감 연산자: ++ --

보통의 단항 연산자는 피연산자의 왼쪽에 위치하지만, 이 둘은 양쪽에 모두 위치한다. 그리고 그 위치에 따라서 연산 결과가 변화한다.

  • 전위형: 피연산자 변수의 값을 먼저 증가시킨 후에 변수의 값을 읽어옴
    (값이 참조되기 전에 증가시킴)
  • 후위형: 변수의 값을 먼저 읽어온 후에 값을 증가시킴
    (값이 참조된 후 증가시킴)

이 차이를 알아보자.

int a = 5;

int b = 0;
b = a++; //후위형

int c = 0;
c = ++a; //전위형

System.out.println("b = "+b+" a = "+a); //b = 5 a = 6
System.out.println("c = "+c+" a = "+a); //c = 6 a = 6

++i 와 i = i+1 의 비교

결과는 두 식이 같지만 실제로 연산이 수행되는 과정에서 차이가 발생한다.
또한 ++i가 더 적은 명령으로 작업을 수행하여 더 빠르다.

※ i = i+1 의 컴파일 코드

  • istore_1
  • iload_1
  • iconst_1
  • iadd
  • istore_1

※ ++i의 컴파일 코드

  • istore_1
  • iinc 1 1

또한 +는 필요에 따라 피연산자를 형변환 하지만 증감 연산자는 형변환 없이 피연산자의 값을 변경한다.

2. 부호 연산자: + -

  • 용도: 피연산자의 부호를 바꿔주기 위해
  • 사용: boolean과 char형 제외 모든 기본형에 사용할 수 있다.
//간단한 사용 예시
int j = 100;
j = +j; 
System.out.println(j); //100
j = -j;
System.out.println(j); //-100

3. 비트전환 연산자: ~

  • 용도: 비트를 바꿔주기 위해 (1->0, 0->1)
  • 사용: 정수형, char형에서 만! 사용
    (** byte, short, char은 int형으로 변환된 후 전환)
2진수 값 = 00001010(2) / 10(10)
-> 비트전환 2진수 값 = 11110101(2) / -11(10)
(앞이 부호 표현을 해주는 bit인듯)

다만, 피연산자의 타입이 int보다 작다면 int형을 변환한 뒤 연산을 실시해야 한다.

byte b = 10;
byte result = (byte) ~b;
//그래서 꼭 위의 코드처럼 형변환을 표시 해줘야함

System.out.println(b); // 10
System.out.println(result); // -11

4. 논리부정 연산자: !

  • 용도: 논리형 값을 바꿔주기 위해(true->false, false->true)
    조건문과 반복문의 조건식에 사용돼 효율적으로 만들어 줌!
  • 사용: boolean형에서만 사용!
    ex. boolean check = false; System.out.println(!check); => true

2️⃣ 산술 연산자

아래의 산술 연산자는 모두 두 개의 피연산자를 취하는 이항 연산자이다.
이 때 이항 연산자는 피연산자의 크기가 4byte보다 작으면 int형으로 변환한 뒤 연산을 수행해야 한다!!

1. 사칙 연산자: + - * /


(출처: 자바의 정석)

  • int(4byte)보다 크기가 작은 자료형은 int형으로 변환 후에 연산을 수행
  • 두 개의 피연산자 중 자료형의 표현범위가 큰 쪽에 맞춰 형변환된 후 연산을 수행
  • 0으로 나누는 것은 금지!!! ArithmeticException 오류 발생
byte a = 10;
byte b = 20;
byte c = (byte) (a+b);
//형변환을 통해 int(a+b)형의 값을 다시 byte형으로 바꿔서 돌려준다.

byte a = 10;
byte b = 30;
byte c = (byte) a*b;
System.out.println(c); //44가 출력
//원래 값은 300이지만 byte의 값 범위(127)를 넘어가 자료 손실이 발생함

long a = 1000000 * 1000000;
long b = 1000000 * 1000000L;
System.out.println(a); // -727379968
System.out.println(b); //10^12
//위는 int*int로 인식이 되어 오버플로우 발생
//아래는 L이라는 long리터럴 사용했으므로 long으로 결과가 계산됨

char c1 = 'a';
// char c2 = c1+1; //char로 형변환을 해주지 않아 컴파일 에러
char c2 = 'a'+1; //얘는 리터럴이기 때문에 형변환 해주지 않아도 OK
//따라서 위의 변수 c2는 컴파일 시 'b'로 변화됨
  • 상수 or 리터럴 간의 연산은 컴파일 시에 컴파일러가 계산하여 그 결과로 대체
  • 나눗셈을 할 때 갖고자 하는 자료형으로 표시하기 ex. /1000f
    (안그러면 우리가 자주 쓰는 숫자 범위에서는 int로 모조리 바뀜,,)

2. 나머지 연산자: %

  • 용도: 나머지 값을 구하기 위한 연산자
  • 사용: boolean제외 모든 기본형에 사용될 수 있음

특이점이 있는데

System.out.pritnln(-10%8) //-2
System.out.println(10%-8) //2

첫번째 피연산자의 부호를 따라 결과값의 부호가 결정된다!

3. 쉬프트 연산자: << >> >>>

= 2진수로 표현했을 때의 각 자리를 오른쪽/왼쪽 으로 이동한다고 하여 이름 붙여짐

  • 용도: 나머지 값을 구하기 위한 연산자
  • 사용: only 정수형 변수
x << n = x*2^n의 결과와 같고
x >> n = x/2^n의 결과와 같다

=> 그러나 가독성이 그리 좋은 편은 아니기 때문에 속도가 빠른 메리트가 있어도 막 많이 사용되지는 않는 것 같다.

3️⃣ 비교 연산자

= 두 개의 변수 or 리터럴을 비교 하는데 사용되는 연산자
= 결과는 무조건 true or false
= 두 자료형이 서로 다르다면 큰 쪽으로 형변환을 시켜준다!

1. 대소비교 연산자 < > <= >=

  • 용도: 두 피연산자의 크기를 비교
  • 사용: boolean을 제외하고 모두 사용 가능! but 참조형 XXXXXXXX

2. 등가비교 연산자 == !=

  • 용도: 두 피연산자에 저장돼 있는 값이 같은지 다른지 비교하는 연산자
  • 사용: 기본형, 참조형 모두 사용할 수 있다!
  • 기본형은 값이 같은지, 참조형은 주소값을 저장하기 때문에 같은 객체를 가리키는지 확인할 수 있다!
//같은지 다른지 비교 예시
float f = 0.1f;
double d = 0.1;
double d2 = (double) f;

System.out.println(10.0 == 10.0f); //true
System.out.println(0.1 == 0.1f); //false
System.out.println(d == f); //false
System.out.println(d == d2); //false
System.out.println(d2 == f); //true

위의 예제에서 의문이 들 수 있다. 왜 10.0와 10.0f는 같으면서 0.1과 0.1f는 다른지? 이건 0.1이 실수형이기 때문이다. 실수형인 double과 float는 근사값으로 저장되어 실질적으로 값이 0.1000~~149~로 저장되기 때문이다.

4️⃣ 논리 연산자

4.1 논리 연산자: && ||

  • 용도: 조건식 간의 결합을 위해
  • 사용: 조건문, 반복문에서 주로 사용
    + 피연산자로 boolean형 or 그 값을 결과로 하는 조건식만을 허용
  • && 이 || 연산보다 우선순위가 높기 때문에 괄호를 사용해 우선순위를 명확히 해주면 더 좋다.

|| = OR 결합 = 한 쪽만 true여도 true를 결과로 얻음
&& = AND 결합 = 양쪽 모두 true여야 true를 결과로 얻음

  • 효율적인 연산을 한다.
    ex. OR의 경우 왼쪽의 연산이 true라면 오른쪽 연산은 볼 필요도 없이 true

4.2 비트 연산자: & | ^

  • 용도: 이진 비트연산 수행을 위해
  • 사용: 실수형 float, double 제외 모든 기본형에서 사용 가능함

& = AND 연산자 = 양쪽이 모두 1이어야 결과가 1
| = OR 연산자 = 한쪽만 1이어도 결과가 1
^ = XOR 연산자 = 두 값이 서로 다를 때만 결과가 1
** 참고로 boolean형은 true가 1, false가 0이다.

int x = 3; // 011
int y = 5; // 101

System.out.println(x|y); //7(111)
System.out.println(x&y); //1(001)
System.out.println(x^y); //6(110)

(+) 삼항 연산자: ? ~ : ~

세 개의 피연산자를 필요로 하기 때문에 삼항 연산자이다.

int result = (x>0) ? x : -x; //요런식으로 작성 가능

//위의 상항 연산자는 아래의 조건문과 같다.
if(x>0) result = x;
else result = -x

(+) 대입 연산자: = / op=

= 변수에 값 or 수식의 연산결과를 저장하는데 사용!

  • 왼쪽은 변수, 오른쪽은 리터럴 or 변수 or 수식
  • 가장 낮은 연산순위를 가지므로 제일 마지막에 수행!
  • 할당 연산자라고도 불림!
// ex. op=
i += 3;
i >>= 3;
i ^= 3;

//ex. =
i = i+3;
i = i % 3;
i = i ^ 3;

연산자 연습문제

3-1. 다음 연산의 결과를 적으시오.

int x = 2;
int y = 5;
char c = 'A';

System.out.println(1+x << 33); //6
System.out.println(y+=10 - x++); //13
  • <<는 쉬프트 연산자이며 덧셈이 이뤄지면 3이 되고, 33bit 만큼 쉬프트가 이뤄져야 하는데 int는 32bit 이므로 1bit만큼만 왼쪽으로 shift하면 011(2)는 110(2)로 변화하여
    4+2=6, 즉 정답은 6이 된다.
  • 후위 연산자는 주어진 앞의 연산이 이뤄진 후에 덧셈 혹은 뺄셈이 진행된다.

3-7. 변환 결과값이 소수점 셋째 자리에서 반올림 된, 화씨가 섭씨로 변환되는 코드를 작성하시오.

int fahrenheit = 100;
float celcius = (int)((5/9f * (fahrenheit - 32))*100 + 0.5) / 100f; //정답!!
System.out.println("Fahrenheit:"+fahrenheit);
System.out.println("Celcius:"+celcius); 

원래 소수점 둘째 자리까지 나타내려면 원래의 값에 100을 곱한 뒤 다시 100을 나눠줘야 한다.
근데 0.5는 왜 더해주는지 잘 모르겠다(반올림 해야 해서 0.5를 더해준 거 같긴 하다). float 자료형을 표시(f)해주지 않으면 값이 int형으로 자동 인식되기 때문에 실수형으로 표현하기 위해 분모 9와 나눌 때의 100에 모두 f를 주었다.

3-8. 아래 코드의 문제점을 수정해서 실행결과와 같은 결과를 얻도록 하시오.

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

char ch = 'A';
ch = (char)(ch + 2);

float f = 3 / 2f;
long l = 3000 * 3000 * 3000L;

float f2 = 0.1f;
double d = 0.1;

boolean result = (float)d==f2;
  • 이항연산은 두 피연산자의 타입을 일치시킨 뒤 연산을 수행해야 함!!
  • 둘 모두 byte 값이어도 형변환이 이뤄지지 않으면 int형으로 인식됨
  • char 타입도 덧셈연산의 과정을 거치며 int 타입으로 변화함
  • 3000은 int 타입이므로 모두 곱한 값은 int의 범위를 넘어가 오버플로우가 발생할 수 있으므로 하나는 long 타입 표시를 해줘야 한다.
  • 마지막은 double 값을 유효자릿수가 적은 float에 맞춰주는 것이 좋다!

참고

자바의 정석, 2nd Edition.
https://www.devkuma.com/docs/java/operator/
(사진) https://myeonguni.tistory.com/40

profile
노션에서 자라는 중 (●'◡'●)

0개의 댓글