프로그램에서 데이터를 처리하여 결과를 산출하는 것을 연산(Operations)이라고 한다.


- 연산자(Operator) : 어떤 연산을 나타내는 표시나 기호 

- 피연산자(Operand) : 해당 연산식에서 연산되는 데이터

- 연산식(Expressions) : 연산자와 피연산자를 이용하여 연산의 과정을 표현한 것



* 연산자의 종류


 유형

연산자

피연산자 수 

기능

예시 

과값

산술 연산자 

+, -, *, /, % 

2개 (이항)

사칙연산과 나머지 계산 

z = x + y

 숫자

부호 연산자

+, - 

1개 (단항) 

양수 및 음수의 표현

x = -x

 숫자

문자열 연산자

2개 (이항) 

두 문자열을 연결 

 "안녕" + "하세요"

문자열

대입 연산자

=, +=, -=, *=, /=

%=, &=, ^=, |=, <<=, >>= 

2개 (이항) 

좌변의 변수에 우변의 값을 대입

x += 1  (x = x + 1)

x &= y  (x = x & y)

 

증감 연산자

++, -- 

1개 (단항)

1만큼 증가(++) 또는 감소(--) 

++x (선증가 후연산)

x++ (선연산 후증가)

숫자 

비교 연산자 

==, !=, <, >, >=, <=, instanceof 

2개 (이항) 

값의 비교

x >= y  (x가 y보다 크거나 같은가)

boolean - true/false

논리 연산자 

!, &, |, &&, || 

단항 또는 이항

NOT(!), AND(&, &&), OR(|, ||) 연산

밑에 추가 설명

boolean - true/false

조건 연산자

(조건식) ? T : F 

3개 (삼항) 

조건식이 참이면 T, 거짓이면 F

(x > y) ? x : y

 

비트 연산자 

~, &, |, ^ 

단항 또는 이항

비트 XOR, AND, OR, NOT 연산 

밑에 추가 설명

숫자, boolean 

쉬프트 연산자 

<<, >>, >>> 

2개 (이항) 

비트 이동 연산자로 비트를 좌측, 우측으로 밀어서 이동 

밑에 추가 설명

숫자 




▶ 산술 연산자


1. 자바는 리터럴 간의 연산은 타입 변환 없이 계산한다.

ex) char c = 'A' + 1; // c에는 유니코드 66인 'B' 가 저장된다.

(But.) char c2 = c + 1; // c는 int타입으로 변환되고 1과 연산되므로 산출 타입은 int이다. 따라서 컴파일 에러.

위의 경우, c를 int타입으로 캐스팅(Casting)해서 char 타입으로 변환해야 한다.


2. 오버플로우 탐지 : 산출 타입(Type)으로 표현할 수 없는 값이 산출되면, 오버플로우가 발생하고 쓰레기값을 얻는다.


3. / 또는 % 연산자 사용 시 우측 피연산자는 0을 사용할 수 없다. 0으로 나누게 되면 예외(ArithmeticException)가 발생한다. 또한 실수 타입인 0.0 또는 0.0f로 나누면 예외가 발생하지 않고, / 연산의 결과는 Infinity(무한대) 값을 가지며, % 연산의 결과는 NaN(Not a Number)을 가진다. 이 때는 데이터가 엉망이 되므로 그 다음의 연산을 수행해선 안된다. 따라서 부동소수점(실수)을 입력받을 때 입력값의 NaN 여부를 조사하고 연산을 수행해야 한다.

(But.) NaN인지 조사할 때 == 연산자를 사용해선 안되며, Double.isNaN() 을 사용해야 한다. 그 이유는 NaN는 != 연산자를 제외한 모든 비교 연산자에서 false를 리턴하기 때문이다.



▶ 비교 연산자


1. 비교 연산자에서는 연산을 수행하기 전에 타입 변환을 통해 피연산자의 타입을 일치시킨다.


2. 예외 : 0.2 == 0.2f 의 경우 이진 포맷의 가수를 사용하는 모든 부동소수점 타입은 0.1을 정확히 표현할 수 없기 때문에 0.1f는 0.1의 근사값으로 나타나므로 피연산자를 모두 float 타입으로 강제 타입 변환한 후 비교 연산을 수행해야 한다.


3. String 객체의 문자열 비교할 때는 ==가 아닌 equlas() 메소드를 사용해야 한다. == 사용 시 객체의 번지값을 비교하므로 번지가 다른 객체일 경우 같은 문자열 상수라도 false가 나온다.



▶ 논리 연산자


1. AND (논리곱) - && 또는 & : 피연산자 모두 true일 경우 연산 결과로 true를 반환한다.


2. OR (논리합) - || 또는 | : 피연산자 중 적어도 하나가 true일 경우 연산 결과로 true를 반환한다.


3. XOR (배타적 논리합) - ^ : 피연산자가 하나는 true이고 다른 게 false일 경우에만 연산 결과는 true를 반환한다. (서로 다를 경우)


4. NOT (논리부정) - ! : 피연산자의 논리값을 바꾼다. true 이면 false ,  false이면 true로 변환한다.



▶ 비트 연산자


1. 비트 연산자는 데이터를 비트(bit) 단위로 연산한다.


2. 비트 반전 연산자, 논리 부정(~)

# 피연산자를 이진수로 표현했을 때, 0을 1로, 1은 0으로 반전한다.

# 정수 타입(byte, short, int, long)의 연산자에게만 사용된다.

# 연산 후, 부호 비트인 최상위 비트를 포함해서 모든 비트가 반전된다.

# 비트 반전 연산자의 산출 타입은 int 타입이다.

# 비트 반전 연산자의 산출값에 1을 더하면 부호가 반대인 정수를 얻는다.


3. 논리곱(AND) - & : 두 비트 모두 1일 경우에만 연산 결과가 1이 된다.


4. 논리합(OR) - | : 두 비트 중 적어도 하나가 1이면 연산 결과는 1이 된다.


5. 배타적논리합(XOR) - ^ : 두 비트 중 하나는 1이고 다른 하나가 0일 경우 연산 결과는 1이 된다.



▶ 쉬프트 연산자(비트 이동 연산자)


1. a << b : 정수 a를 이진법으로 표현했을 때, 각 비트를 b만큼 왼쪽으로 이동시키고 빈자리는 0으로 채워진다.


2. a >> b : 정수 a를 이진법으로 표현했을 때, 각 비트를 b만큼 오른쪽로 이동시키고 빈자리는 정수 a의 최상위 부호 비트와 같은 값으로 채워진다.


3. a >>> b : 정수 a의 각 비트를 b만큼 오른쪽으로 이동시키고 빈자리는 0으로 채워진다.



* 연산 방향 및 우선 순위


 연산자

연산 방향

우선 순위 

증감(++, --), 부호(+, -), 비트(~), 논리(!) 

← 

 높음












낮음

산술(*, /, %)

산술(+, -)

쉬프트(<<, >>, >>>) 

비교(<, >, <=, >=, instanceof) 

비교(==, !=) 

논리(&)

논리(^)

논리(|) 

논리(&&) 

논리(||) 

조건( ? : ) 

대입(=, +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=, >>>=)






타입 변환 : 데이터 타입을 다른 데이터 타입으로 바꾸는 것.



- 자동 타입 변환(Promotion)


 : 프로그램 실행 중에 자동으로 타입 변환이 일어나는 것을 의미한다.



큰 크기의 타입 ← 작은 크기의 타입


* 여기서 크기는 사용하는 메모리 크기(바이트 수)를 말한다.


즉, byte ▶ short  int  long  float  double 순서 또는 char  int 순서로 자동 타입 변환이 일어난다.


참고로 long(8 byte)이 float(4 byte)보다 크지만 표현할 수 있는 숫자의 범위가 float이 더 크기때문에 float이 더 큰 타입으로 표시된 것이다. 또한, 정수 타입이 실수 타입으로 변환될 경우 자연수 뒤에 소수점과 소수점이하가 표시된다.


int i = 200;

double d = i; // 이때 d는 200.0이 된다. 



자동 타입 변환에서는 딱 한 가지 예외가 있는데, char는 2 바이트의 크기를 가지지만 char의 범위는 0~65535이므로 음수가 저장될 수없다. 즉, 음수가 저장될 수 있는 byte 타입은 char 타입으로 자동 변환시킬 수 없다.




Q) 데이터 손실 유무는 ?


A) 변환 이전의 값은 변환 이후에도 그대로 보존된다. 쉽게 말하자면 작은 양동이의 물을 큰 양동이로 옮긴다고 해도 물의 양은 변하지 않는 것과 같은 것이다.




- 강제 타입 변환(Casting)


 : 큰 데이터 타입을 작은 데이터 타입으로 쪼개어 강제로 저장하는 것을 의미한다.



큰 크기의 타입 → 작은 크기의 타입



즉, byte ◀ short  int  long ◀ float ◀ double 순서 또는 char ◀ int 순서로 강제 타입 변환이 일어난다.



# 사용 방법


작은 크기 타입 = (작은 크기 타입) 큰 크기 타입;


int i = 214748364;

byte b = (byte) i;


위의 경우 끝의 1 byte만 byte 타입 변수에 담게 된다. 즉, 변환되어질 데이터(작은 크기의 타입)보다 큰 것을 강제 타입 변환을 할 때 기존의 값은 보존되지 않는다.



# 주의 사항


int -> float으로 강제 타입 변환을 할 때,


float : 부호(1비트) + 지수(8비트) + 가수(32비트)


로 구성되어 있기 때문에 int 값이 123456780 처럼 가수 23비트로 표현불가능한 숫자일 경우 근사값으로 변환된다. 이 점은 정밀도 손실을 발생시키기 때문에 모든 int값을 안전하게 실수 타입으로 변환시키려면 double 타입을 사용하는 것이 현명하다. 


double : 부호(1비트) + 지수(11비트) + 가수(52비트)


그 이유는 int값은 4바이트 = 32비트 이므로 double의 가수 52비트보다 항상 작기 때문에 정밀도 손실없이 변환이 가능하다.



헷갈린다면 다른 타입으로 강제 타입 변환 시 변환될 타입(작은 크기의 타입)의 최대값과 최소값을 넘어가는지 확인하면 된다.

아래는 기본타입의 최대값과 최소값을 나타낸 표이다.



 기본 타입

최대값 상수 

최소값 상수 

byte 

Byte.MAX_VALUE 

Byte.MIN_VALUE 

short

Short.MAX_VALUE 

Short.MIN_VALUE 

int 

Integer.MAX_VALUE 

Integer.MIN_VALUE 

long 

Long.MAX_VALUE 

Long.MIN_VALUE  

float 

Float.MAX_VALUE 

Float.MIN_VALUE 

double 

Double.MAX_VALUE

 Double.MIN_VALUE 





더블 버퍼링(Double Buffering)은 이중 버퍼링이라 불리기도 하며, 그래픽 객체에 이미지를 그릴 때 사용되는 기법이다.



Q) 왜 사용하는가 ? 


A) API를 시작하다보면 비트맵 이미지를 사용하게 된다. 그 때 이미지들이 전환되면서 영상처럼 부드럽게 움직일 거라 생각하지만 실제로 이미지들이 움직일 때마다 화면이 깜빡이는 현상이 눈에 들어온다. 쉽게 말하자면 아래와 같은 상황인 것이다.


▶ 게임 캐릭터이미지를 구현할 때 이미지를 움직이게 하고 싶다.

그러나 캐릭터가 띄엄띄엄 움직임과 동시에 깜빡거리는 화면

때문에 게임할 맛이 안난다.



그 이유는 컴퓨터가 이미지를 지웠다가 새 이미지를 다시 그리고 하는 방식을 반복하기 때문이다.


즉, 이미지를 그리는 데 시간이 소요되므로 이미지의 출력이 잦을수록 깜빡거리는 현상이 심해진다.


이에 대한 해결방안으로 버퍼 역할을 해줄 메모리 장치 컨텍스트(보이지 않는 화면)를 하나 더 사용하여 그곳에 이미지를 그리고, 기존화면을 유지하다가 이미지가 완성되면 실제 화면 장치 컨텍스트로 한꺼번에 베껴 그리는 것이다. 


아래는 이를 그림으로 표현한 것이다.






Q) 어떻게 사용하는가 ?


A) 자바를 예로 들자면,


//FIELDS

Image buffImage;

Graphics buffg;


//CONSTRUCTOR

(클래스명) {

repaint(); // 호출 시 repaint() -> update(g) -> paint(g) 순서로 메소드가 호출된다.

}


//METHODS

public void paint(Graphics g) {

if(buffg == null) {

buffImage = createImage(이미지 넓이, 이미지 높이); //버퍼링용 이미지 생성


if(buffImage == null) System.out.println("더블 버퍼링용 오프 스크린 생성 실패");

else buffg = buffImage.getGraphics(); 

//이미지를 생성해도 그래픽 객체를 얻어야 이미지 위에 그리고자하는 것을 그릴 수 있다.

}

update(g); // 이렇게 하면 반복적인 메소드 실행이 가능하다.

}


public void update(Graphics g) {


buffg.drawImage(그릴 이미지, 0, 0, this);


g.drawImage(buffImage, 0, 0, this); //실제 화면(g)으로 오프스크(buffg)에 그려진 이미지(buffImage)를 옮김.

}



컴퓨터 그래픽에서는 크게 비트맵 기반의 그래픽과 벡터 기반의 그래픽으로 나뉘어진다.


- 비트맵(Bitmap) : 비트의 지도를 뜻하며 각각의 픽셀에 저장된 일련의 비트 정보 집합이다. 

  픽스맵(Pixmap) 또는 래스터(raster)이미지라고도 불린다.


디스플레이는 픽셀들의 배열로 구성되어 있다. 픽셀들의 총 갯수나 배열 방법, 너비와 높이의 비율이 디스플레이의 해상도를 결정짓는다.


ex) 1080X720의 해상도를 가진 디스플레이는 가로 1080개와 세로 720개의 픽셀을 가지며 픽셀의 총 갯수는 1080X720개이다.


이 픽셀들을 점이라 생각하면 이해하기 쉽다. 무수한 점들로 이루어진 이미지이므로 사실적인 이미지 표현이 가능하다.

그러나 너무 확대할 경우 픽셀들이 보일 수 있으므로 이미지를 편집할 때 주의해야한다. 

확대해도 픽셀들이 보이지 않는 이미지의 경우 해상도가 높은 이미지라고 표현한다.


* 비트맵 이미지의 편집 툴로 Adobe Photoshop이 있다.



-벡터(Vector) : 수학적으로 계산된 그래픽의 형태 디스플레이에 비트맵화(래스터화)되어 표시된다.

  비트맵보다 더 많은 연산을 요구하기 때문에 하드웨어에 부담을 주므로 대부분 비트맵 이미지를 사용한다.

  그러나 벡터 이미지에는 비트맵 이미지가 갖는 해상도란 개념이 없다. 즉, 좌표 위의 선들을 이용해서 이미   지가 표현되므로 확대, 축소가 자유롭다.


* 벡터 이미지의 편집 툴로 Adobe Illustrator 가 있다.

'Note' 카테고리의 다른 글

GCC 사용법  (0) 2018.06.29
git 명령어 & Bitbucket 사용하기  (0) 2018.06.27
Domain Name System - DNS와 네임서버  (0) 2017.06.20
운영체제별 개행문자(줄바꿈문자)  (0) 2017.06.20
FPS : Frames Per Second  (1) 2017.03.28

+ Recent posts