외부 라이브러리를 이용하여 자바 클래스파일을 실행할 때는 라이브러리 파일의 경로를 따로 알려주어 classpath 환경변수에 등록해주어야 하고, 이때 사용하는 명령어는 $ java classpath [외부라이브러리 경로] com.eomcs.study.App이다.
외부 라이브러리가 아닌 자바에서 기본적으로 제공하는 명령코드들을 사용할 경우엔, .jar(Java ARchive) 라이브러리를 사용하며, 이 경우는 따로 클래스경로를 알려줄 필요가 없다.
※ .bat : 파일 안에 미리 경로나 명령어를 써놓고, cmd에서 파일명을 입력만 하면 명령어를 입력한 것 처럼 실행되는 파일이다. 자주 쓰는 긴 명령어나 긴 경로등을 효율적으로 활용하고자 할때 사용한다.
※ 예제 중 Exam1, Exam2등이 Run을 눌러도 실행되지 않는 이유는 메인 메서드가 없기 때문이다. 이클립스는 메인 메서드가 없는 파일을 컴파일 및 실행하지 않고 가장 최근 실행된 파일을 실행한다.
하나의 비트는 전기가 채워지거나 채워지지 않거나 2개의 상태가 가능하며, 컴퓨터에서는 이를 0 과 1로 읽는다.
8개의 비트의 집합을 바이트라 한다.
ex 1) 4비트로 양의 정수를 정의
ex 2) 4비트로 문자 정의
ex 3) 4비트로 색 정의
즉, 값에 대한 2진수 표현 규칙을 정의하면, 어떤 값이든 메모리의 전기적 상태로 저장할 수 있다
1) Sign-Magnitude (절대부호)
맨 앞자리를 부호로 사용하고 나머지 숫자를 값으로 사용하는 방식이다.
ex)
5 -> 0101 : +1 * (22 * 1 + 21 * 0 + 20 * 1)
-5 -> 1101 : -1 * (22 * 0 + 21 * 1 + 20 * 1
양수와 음수의 더하기가 불가능한 단점이 있다.
ex) 5 + (-5) -> 0101+1101 = 10010
4비트에서 5째자리수는 없어지므로 결과는 0010이고 이는 예상되는 값인 0과 다르다.
2) 1의 보수
음수인 경우 양수에서 0에 1 넣어주고 1에 0 넣어준 다음에 계산을 하는 방식이다.
계산 결과에 1을 더해야만 정확한 값이 나온다
ex) 5 + (-5) -> 0101+1010 = 1111
1을 더하면 값은 10000->0000이 되고 정확한 값이 나온다.
절대부호, 1의 보수 방식은 부동소수점에서 부동소수점에서 가수부를 저장할때 사용한다.
※ 부호부, 지수부, 가수부
숫자를 다음과 같은 형태로 나타낼 경우
--부호부 (Sign) : 1비트. 숫자의 부호를 나타내며, 양수일 때 0, 음수일 때 1이 된다.
--지수부 (Exponent) : 단정도에서 8비트, 배정도에서 11비트 . 지수를 나타낸다.
--가수부 (Mantissa) : 단정도에서 23비트, 배정도에서 52비트 . 가수 또는 유효숫자를 나타낸다.
3) 2의 보수
음수인 경우 1의 보수로 전환한 다음에 1에 0 넣어준 다음에 계산을 하는 방식이다.
ex) 5 + (-5) -> 0101+1011 = 10000->0000 => 0
ex) 4 + (-2) -> 0100+1110 = 10010->0010 => 2
ex) (-4) + 2 -> 1100+0010 = 1110 => -2
현대 컴퓨터 대부분이 정수를 2진수로 표현할 떄 2의 보수 방법을 사용한다.
빼기 대신에 더하면 되므로 빼기 연산이 필요없다는 특징을 가진다.
4) Excess - K 방식
변환하려는 음수 또는 양수에 k값을 더하여 결과값으로 만들고 이를 2진수로 만드는 방식이다.
k = 2(비트수-1)
ex)
음수에서 양수로 갈수록 2진수가 커진다.
부동소수점에서 지수부를 저장할 때 사용한다.
2진수로 표기하기엔 너무 길어져 보통 16진수로 표기해준다.
ex)
@GetMapping("/test1")
public String test1() {
return "정수" + 21_4748_3648; // 컴파일 오류 : 4바이트 메모리에 저장 불가
return "정수" + 21_4748_3647;
}
@GetMapping("/test2")
public String test2() {
return "정수" + -21_4748_3649; // 컴파일 오류 : 4바이트 메모리에 저장 불가
return "정수" + -21_4748_3648;
}
@GetMapping("/test3")
public String test() {
return "정수" + 932_0000_0000_0000_0000L; // 컴파일 오류 : 8바이트 메모리에 저장 불가
return "정수" + 922_0000_0000_0000_0000L;
}
@GetMapping("/test4")
public String test4() {
return "정수" + -932_0000_0000_0000_0000L; // 컴파일 오류 : 8바이트 메모리에 저장 불가
return "정수" + -922_0000_0000_0000_0000L;
}
4바이트 정수 리터럴 표기 : 100
8바이트 정수 리터럴 표기 : 100L(8바이트 메모리를 사용한단 의미이다)
ex) 12.375
1) 소수점 앞의 정수값을 2진수로 바꿔준다.
12->1100
2) 소수점 뒤의 값 또한 2진수로 바꿔준다.
0.375
-> 0.375 * 2= 0.75 ->0
-> 0.75 * 2 = 1.5 ->1
-> 0.5 * 2 = 1.0 -> 1
0.375 -> 0.011
3) 1과 2를 더해준다.
1100.011
4) 정규화를 수행하여 소수점을 없앤다
-1- 소수점 왼쪽에 한 개의 1만 남게 한다.
1.100011 * 23
-2- 소수점 왼쪽의 숫자 1을 버린다.
(어짜피 모든 경우는 왼쪽에 숫자 1만 존재하기 때문이다.)
0.100011 * 23
-3- 비트에 저장한다
※ 부동소수점 : 실수를 컴퓨터상에서 근사하여 표현할 때 소수점의 위치를 고정하지 않고 그 위치를 나타내는 수를 따로 적는 것을 말한다.
314.75
=3.1475 * 102
=31.475 * 101
=3147.5 * 10-1
=31475 * 10-2
이런걸 부동소수점이라 하고, 데이터타입 float의 어원도 이 부동소수점이다.
1) 4바이트 부동소수점
12.375f : 보통 이걸 쓴다.
12.375F
2) 8바이트 부동소수점
12.375 : 보통 이걸 쓰며, 부동소수점의 경우 사용은 4바이트보다 8바이트가 권장된다.
12.375d
12.375D
소수점 앞의 정수값과 소수점 이하의 값을 2진수화 하고, 정규화 처리를 하는 과정을 통해 메모리에 값이 저장되기 때문에 정확하게 범위를 산정할 수 없다.
또한 소수점이 부동이기 때문에, 소수점 앞 자리수, 소수점 뒤 자리수도 결정할 수 없다.
다만 IEEE방식에 따라 2진수로 바꾸더라도 값이 짤리지 않는 범위를 대략적으로 알 수 있다.
4바이트의 경우 소수점을 제거했을때 7개의 숫자라면 거의 99.9% 메모리에 저장 가능하다. 이를 single precision (단정도)라 부른다.
8바이트의 경우 소수점을 제거했을때 15개의 숫자라면 거의 99.9% 메모리에 저장 가능하다. 이를 double precision (배정도)라 부른다.
이 자릿수를 유효자릿수라 부른다.
8바이트 메모리는 4바이트 메모리보다 2배 더 많은 수를 저장할 수 있고 이는double의 어원이다.
-ex)
public class Exam0340 {
public static void main(String[] args) {
//## 4byte(float) 부동소수점의 유효자릿수
//소수점을 뺀 후 7자리 숫자까지는 거의 정상적으로 저장된다.
System.out.println(999.9999f); // 999.9999
System.out.println(999999.9f); // 999999.9
System.out.println(9.999999f); // 9.999999
System.out.println("----------------------------");
//유효자릿수가 7자리를 넘어가는 경우 값이 잘려서 저장될 수 있다.
System.out.println(987654321.1234567f); // 9.8765434E8
System.out.println(9.876543211234567f); // 9.876543
System.out.println(987654321123456.7f); // 9.876543E14
System.out.println("----------------------------");
//## 8byte(double) 부동소수점의 유효자릿수
//소수점을 뺀 후 16자리 숫자까지는 거의 정상적으로 저장된다.
System.out.println(987654321.1234567); // 9.876543211234567E8
System.out.println(9.876543211234567); // 9.876543211234567
System.out.println(987654321123456.7); // 9.876543211234568E14
System.out.println("----------------------------");
//유효자릿수가 16자리를 넘어가는 경우 값이 잘려서 저장될 수 있다.
System.out.println(987654321.12345678); // 9.876543211234568E8
System.out.println(9.8765432112345678); // 9.876543211234567
System.out.println(987654321123456.78); // 9.876543211234568E14
System.out.println("----------------------------");
//## 부동소수점을 저장할 때 정확하게 저장되지 않는 예
System.out.println(7 * 0.1); // 0.7000000000000001
// - 이유
// - IEEE-754 규격에 따라 부동소수점을 2진수로 바꾸다보면
// 정확하게 2진수로 딱 떨어지지 않는 경우가 있다.
// CPU, OS, 컴파일러, JVM의 문제가 아니다.
// - IEEE-754의 방법에 내재되어 있는 문제다.
// - 해결책
// - 시스템에서 필요한 만큼 소수점 이하 자리수를 적절히 짤라 사용하라!
// 위의 값이 정확히 0.7이 나오지 않으므로, 다음의 조건문을 실행시키면 false가 나온다.
System.out.println(7 * 0.1 == 0.7); // false
}
}