1-1. 컴퓨터의 표현 방식 - 2진수, 16진수, 8진수
자바도 설치하고 이클립스를 통해서 프로그램도 만들어보았지만.
여전히 프로그래밍이 뭔지 감이 오진 않는다(당연하다).
그렇기에 나는 컴퓨터가 데이터를 어떻게 표현하는 지부터 이해할 필요가 있다.
컴퓨터는 2진수을 사용한다.
컴퓨터의 반도체가 데이터를 0과 1로만 표현할 수 있기 때문이다.
이 0과 1의 최소 단위를 비트(bit)라고 하며, 8비트가 모이면 1바이트(byte)가 된다.
그리고 자바는 2진수, 8진수, 16진수가 활용된다.
그렇기에 일상에서 사용하는 10진수의 수에 익숙해있는 나는 다른 진수의 표현에 익숙해질 필요가 생겼다.
일단 보기 쉽게 표로 정리해보자.
10진수 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
2진수 0 | 1 | 10 | 11 | 100 | 101 | 110 | 111 | 1000 | 1001 |
숫자는 그리 어렵지 않다(이전의 배움을 떠올렸다).
하지만 문자 또한 2진수로 표현되어야 한다.
예를 들어 A라는 알파벳 대문자는 숫자 65라는 값으로 표현하도록 약속되어있다.
따라서 컴퓨터 내부에서 A는 2진수 1000001로 표현이 된다.
이를 아스키 값이라고 한다.
그런데 보다시피 2진수는 정말 무진장 긴 숫자다.
그렇기에 2진수를 줄여서 표현하기 위해 8진수와 16진수를 사용한다(하지만 그만큼 비트를 많이 잡아먹게 된다).
0부터 16까지의 수를 각각의 진수로 표현하면 아래와 같다.
10진수 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
2진수 | 0000 | 00001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 |
8진수 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 |
16진수 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
10진수 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | |
2진수 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 | 10000 | |
8진수 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | |
16진수 | 9 | A | B | C | D | E | F | 10 |
프로그램에서 진수를 활용하여 문자가 표현되기 위해서 각각의 진수를 표현할 때는 앞에 붙는 용어가 생긴다.
2진수는 0B, 8진수는 0, 16진수는 0X를 주로 붙인다.
예를 들어 10진수의 10은 코드에서 2진수 0B1010, 8진수 012, 16진수 0XA로 표현될 수 있다.
1-2. 부호 있는 수를 표현하는 방법
그렇다면 만약 음수는 어떻게 표현할 수 있을까.
이 역시 0과 1로 표현이 된다.
부호를 나타내는 비트는 맨 앞에 붙이며 이 비트를 부호 비트(Most Significant Bit ; MSB)라고 부른다.
부호 비트가 0이면 양수, 1이면 음수이다.
예를 들어 8비트로 5라는 숫자를 표현하면 다음과 같다.
00000101 > 여기서 맨 앞의 0이 부호 비트이다.
그렇다면 -5를 8비트로 표현하면 1000101일까?
정답인지 알기 위해선 두 수를 더하면 된다.
두 수를 더해서 0이 나온다면 1000101이 -5가 맞다는 뜻이기 때문이다.
0000101
+1000101
=1001010
잉? 0이 되지 않는다.
그렇다면 -5는 어떻게 나타내는 것일까.
이 때 나타나는 개념이 바로 '2의 보수'이다.
보수란 보충해주는 수라는 뜻이다.
그러니까 2의 보수란 어느 숫자에 보수가 더해지면 2가 되는 수라는 뜻이다.
그런데 이 수가 어떻게 컴퓨터에서 음수가 될 수 있냐면 다음과 같은 원리이다.
예를 들어 4비트만 사용하는 컴퓨터에서 0011의 2의 보수를 찾아 더했다.
0011+1101=10000이 된다.
그런데 이 컴퓨터는 4비트만 사용하는 컴퓨터다.
그렇기에 결과값의 맨 앞에 있는 1은 사라지게 된다(이 것을 트렁케이트된다 - truncate 라고 표현한다).
결과적으로 0011에 1101을 더하니 0이 되게 된 것이다.
그래서 2진수에서 2의 보수는 음수가 되는 것이다.
2. 변수란 무엇일까?
변수란 말 그대로 변하는 수이다.
고정된 데이터가 아니라 늘 변하는 데이터를 뜻하는 것이다.
사람의 나이도 변수일 것이고, 은행에 넣어둔 내 텅장의 잔고도 늘 변수일 것이다.
이렇게 변하는 값들을 저장하는 공간을 변수라고 표현한다.
프로그램에서 이 변수를 사용하기 위해선 어떤 형태의 자료들을 저장할 것인지 정해야한다.
사람의 나이를 저장하려면 정수 형태를 써야 할 것이고, 이름을 저장하려면 문자 형태를 써야 한다.
이 형태를 변수의 '자료형'이라고 한다.
자료형을 선택했다면 변수의 이름도 정해주어야 한다.
이렇게 변수의 자료형을 선택하고 이름을 정하는 모든 과정을 '변수를 선언한다'라고 한다.
만약 게임 레벨을 변수로 선언하고 이 변수에 값 10을 넣어보려 한다면 아래와 같이 표현할 수 있다.
int level;
level = 10;
여기서 int는 정수를 나타내는 자료형이다.
level은 게임 레벨을 의미하는 변수 이름이다.
그래서 이 두 줄의 코드를 해석해보면 이러하다.
'level이란 이름의 변수를 정수 자료형으로 선언한다, 그리고 선언한 level 변수에 값 10을 대입한다.'
이를 프로그램화 시키면 아래와 같다.
package chapter2;
public class Variable1 {
public static void main(String[] args) {
int level; // 정수형 변수 level을 선언
level = 10; // level 변수에 값 10을 대입
System.out.println(level); // level 값 출력
}
}
그리고 이렇게도 표현할 수 있다.
이 과정을 변수의 초기화(변수의 선언과 대입이 동시에 이루어지는 것)라고 한다.
package chapter2;
public class Variable1 {
public static void main(String[] args) {
int level = 10; // level 변수 선언과 동시에 값을 대입(초기화)
System.out.println(level);
}
}
이 변수의 이름은 때에 맞는 용도에 맞게 지으면 된다.
하지만 아래와 같은 제약 사항이 있다.
1) 변수 이름은 영문자(대,소문자)나 숫자를 사용할 수 있고, 특수 문자 중에서는 $, _ 만 사용할 수 있다.
2) 변수 이름은 숫자로 시작할 수 없다.
3) 자바에서 이미 사용 중인 예약어는 사용할 수 없다.
변수의 이름은 프로그램에서 계속 사용되게 될 것이기에 사용 목적에 맞게 의미를 잘 부여해서 만드는 것이 좋다.
만약 학생 수를 뜻하는 변수를 만들어야할 때 'ns'와 'numberOfStudent' 둘 중 어느 이름이 더 잘 이해될까.
당연히 후자이다.
또한 변수의 이름은 대부분 소문자로 시작해서 여러 단어로 이루어질 때 중간 단어의 첫 글자를 대문자로 사용하는 것도 흔히 쓰는 변수 이름을 만드는 요령이다.
이것은 함수를 선언할 때도 사용하는 표기법인데 중간에 튀어나온 대문자가 낙타의 등처럼 보인다며 카멜 표기법(camel notation)이라고 한다(네이밍이 귀엽다).
3. 변수가 저장되는 공간의 특성, 자료형
변수는 컴퓨터 내부의 메모리 공간에 저장된다.
그리고 이후에 같은 변수를 연산에 사용하거나 값을 출력할 일이 있으면 이 공간에 있는 값을 가져오는데 이름을 사용하여 값을 가져온다.
즉 변수를 선언한다는 것은 선언한 변수 이름으로 어떤 위치에 있는 메모리를 얼마만큼의 크기로 사용하겠다는 뜻이다.
자바에서 제공하는 자료형은 기본 자료형과 참조 자료형이 있다.
기본 자료형은 자바 라이브러리에서 기본으로 제공하며, 메모리의 사용량도 정해져 있다.
정수형 | 문자형 | 실수형 | 논리형 | |
1바이트 | byte | - | - | boolean |
2바이트 | short | char | - | - |
4바이트 | int | - | float | - |
8바이트 | long | - | double | - |
1) 정수 자료형
정수 자료형은 양수, 음수, 0을 나타내는 데 사용하는 자료형이다.
표에서 보다시피 4가지의 자료형으로 나타낼 수 있다.
예를 들어 10진수 10을 int형(4바이트, 32비트)으로 저장한다면 이렇게 표현이 된다.
= 00000000000000000000000000001010
즉 int형으로 표현될 수 있는 수의 범위는 (-2의 31승부터 2의 31승)-1 의 영역이다.
각각의 형들은 표현할 수 있는 수의 범위가 정해져있으며 그 형을 벗어난 숫자가 입력되면 오류가 난다.
byte형은 1바이트 = 8비트이기에 2의 7승까지의 숫자, 127까지의 수만 표현할 수 있는데 128을 출력하라고 하면 할 수 없는 것이다.
그렇다면 각기 다른 정수 자료형으로 출력한 두 값을 더하면 어떻게 될까?
자바는 자동으로 int형으로 변환시켜 값을 저장한다.
즉 정수의 기본형은 int형이다.
그렇다고 다른 형들이 사용되지 않는 것은 아니고 다른 언어와의 호환을 위해서, 목적에 따라 사용이 된다.
이런 정수 자료형 중 가장 긴 long형은 int형의 범위를 넘어서는 정수를 사용할 때 사용된다.
그런데 이 long형을 사용할 때는 주의할 점이 있다.
int num1 = 12345678900;
long num2 = 12345678900;
위의 두 문장을 선언하면 두 문장이 모두 오류가 난다.
첫 번째 문장은 int형으로 표현할 수 있는 범위를 벗어났기 때문에 오류가 난다.
두 번째 문장은 자바가 기본적으로 숫자를 int형으로 처리하기 때문에 오류가 난다.
이런 경우에는 이 숫자를 long형으로 처리해야한다고 컴파일러에게 알려주어야 한다.
그러기 위해선 식별자인 L이나 l을 숫자 뒤에 붙여준다(당연히 int형이 인식할 수 있는 숫자라면 붙이지 않아도 된다).
long num2 = 12345678900L; // 이러면 값이 출력되게 된다.
2) 문자 자료형
문자 역시 숫자와 마찬가지로 특정 정수의 값으로 정해져있는 약속을 따른다.
그리고 이 코드의 값을 모아 둔 것을 '문자 세트'라고 하고 문자를 코드로 바꾸는 문자 인코딩, 코드를 문자로 변환하는 문자 디코딩의 과정을 통해 프로그램은 문자를 출력한다.
이것에 가장 기본이 되는 문자 인코딩은 아스키(ASCII) 코드이다.아스키 코드는 영문자, 숫자, 특수 문자 등을 나타내는 문자 세트이다.하지만 아스키 코드는 1바이트만을 사용하는 문자이기에 다른 언어의 다양하고 복잡한 언어 문자를 표현하기엔 한계가 있다.그래서 2바이트 이상을 사용하게 되는 각 언어의 표준 인코딩을 정의해 놓은 것이 '유니코드(unicode)'이다.
자바는 이 유니코드에 기반하여 문자를 표현하기 때문에 문자 자료형인 char형은 2바이트를 사용한다.문자형 변수는 다음과 같이 선언할 수 있다.
char myChar = 'A';
이렇게 문자를 변수에 대입하면 문자 그대로 저장하는 것이 아니라 그 문자에 해당하는 정수 값(아스키 코드 값)이 저장된다.
이제 책에 나온 예제를 통해 문자 자료형을 더 완벽히 이해해보자!
package chapter2;
public class characterEx1 {
public static void main(String[] args) {
char ch1 = 'A';
System.out.println(ch1); // 문자 출력
System.out.println((int)ch1); // 문자에 해당하는 정수 값(아스키 코드 값) 출력
char ch2 = 66; // 정수 값 대입
System.out.println(ch2); // 정수 값에 해당하는 문자 출력
int ch3 = 67;
System.out.println(ch3); // 문자 정수 값 출력
System.out.println((char)ch3); // 정수 값에 해당하는 문자 출력
}
}
/*
이 예제의 출력 값은,
A
65
B
67
C
이다.
*/
프로그램에서 문자를 사용할 때는 항상 작은 따옴표(' ')를 사용한다.
만약 문자를 여러 개 이은 문자열을 사용할 때는 큰 따옴표(" ")를 사용한다.
문자열이란 "Hello"처럼 여러 개의 문자를 큰 따옴표로 감싸 표현하고 기본 자료형으로는 표현할 수 없다. 그리고 문자열 끝에는 항상 널 문자('\0')가 있다.
즉 'A'와 "A"는 전혀 다른 값이다.
또한 유니코드 값을 직접 사용할 수도 있다.
'한'이라는 글자의 유니코드 값은 '\uD55C'이다.
여기서 \표시와 백슬래시 표시는 같은 값으로 본다.
그런데 만약 문자형 변수에 숫자를 저장하면 것은 어떻게 될까?
결과를 먼저 말하자면 당연히 가능하다.
하지만 음수 값은 표현할 수 없다.
3) 실수 자료형
만약 실수를 컴퓨터 내부에서 표현한다고 생각해보자.실수 3.14를 표현한다고 했을 때 간단히 생각하면 정수 3과 소수 .14로 나누어 표현할 수 있겠다.하지만 0과 1 사이의 무한 개의 실수를 모두 데이터화하여 표현할 수가 없기 때문에 컴퓨터에서는 실수를 정수와는 조금 다른 방식으로 표현한다.
- 부동 소수점 방식
실수 값 0.1은 1.0X10의 마이너스1승으로 표현할 수 있겠다.
이처럼 가수 부분(1.0)과 지수 부분(-1)을 나누어서 실수를 나타내는 방식을 부동 소수점 방식이라고 한다.
이 내용을 완벽히 이해하지 못해도 괜찮다.
다만 지수와 가분을 구분해서 표현해내는 방식이 부동 소수점 방식이라는 사실만 기억하자.
- float형과 double형
실수 자료형에는 float형과 double형이 있다.
float형은 부호 1비트, 지수부 8비트, 가수부 23비트로 총 32비트(4바이트)를 사용한다.
double형은 부호 1비트, 지수부 11비트, 가수부 52비트로 총 64비트(8바이트)를 사용한다.
자바에서 실수는 double형을 기본으로 사용하기에 float형 값이 대입될 때는 실수 뒤에 F 또는 f를 붙여 표현한다.
package chapter2;
public class DoubleEx1 {
public static void main(String[] args) {
double dnum = 3.14;
float fnum = 3.14F;
System.out.println(dnum);
System.out.println(fnum);
}
}
여기서 3.14는 double형으로 컴퓨터 내부에 저장되어 dbum 값에 대입된다.
float형으로 대입되는 값 3.14는 F 또는 f를 숫자 뒤에 붙여서 식별해준다.
** 부동 소수점 방식은 지수로 표현되는 값이 0을 나타낼 수 없다. 만일 결과 값이 정수로 나와야하는데 지수가 0일 수 없어서 오류가 발생하는 것이다. 하지만 오차를 감수하고라도 더 넓은 범위의 실수 값을 표현할 때는 부동 소수점 방식을 사용한다.
4) 논리 자료형
논리 자료형은 어떤 변수의 참, 거짓을 나타내는 데 사용한다.
종류는 boolean형 한 가지 뿐이다.
결혼 여부, 수행의 여부, 값의 존재 여부 등을 참과 거짓으로 나타낼 수 있다.
예시는 아래와 같다.
boolean isMarried;
boolean형 변수는 1바이트로 값을 저장하며 true, false 두 가지 값만 가진다.
package chapter2;
public class BooleanEx {
public static void main(String[] args) {
boolean isMarried = true;
System.out.println(isMarried);
}
}
5. 자료형 없이 변수 선언하기(쓰일려나?)
자바 10부턴 변수를 사용할 때 문법적 변화가 생겼다.
자바의 모든 변수를 사용할 땐 사용할 자료형을 정확히 명시해야했는데 자바 10부터는 자료형을 쓰지 않고 변수를 사용할 수 있었다.
이를 지역 변수 자료형 추론(local variable type inference)이라고 하며 var를 사용하여 변수를 선언한다.
이는 다른 프로그래밍 언어에서도 이미 사용하고 있다.
하지만 자바에서 var를 사용할 때는 한번 선언한 자료형 변수는 다른 자료형 변수로 사용될 수 없고, 지역 변수(프로그램 내에서 사용할 수 있는 변수)만 사용이 가능하다.
'⁂ Java > : 독학으로 공부하기(과거)' 카테고리의 다른 글
[java] #3-1 조건문 : 제어 흐름 이해하기 (0) | 2022.07.01 |
---|---|
[java] #2-2 비트 연산자 (0) | 2022.07.01 |
[java] #2-1 자바의 기본 연산자 (0) | 2022.06.30 |
[java] #1-3 상수와 리터럴 (0) | 2022.06.30 |
[java] #1-1 그래서 자바가 뭔데? (2) | 2022.06.29 |