[Java] 진법 변환 토이 프로젝트 (N진수를 K진수로 변환하기, No Library)
개요
코딩 테스트에서 진법 변환 문제가 나왔습니다.
여러 조건 때문에 결국 못 풀어서 한이 남아 아예 프로젝트를 하나 만들고 포스팅으로 박제하고자 합니다.
한번 익혀두면 잊어버리지 않으니, 공부하면 좋은 지식이 될 거라 생각합니다.
N진수를 입력 받아 N진수를 K진수로 변환하는 방법을 알아보겠습니다.
ex) 1111(2) -> 17(8)
N = (2 ~16) 진수
K = (2~16)진수
NotationConversion
NotationConversion은 제가 지은 프로젝트 이름입니다.
N진수를 K진수로 바꾸는 변환 과정은 다음과 같습니다.
N진법으로 표기된 숫자를 10진법으로 바꾸고 바꾼 10진수를 K진법으로 바꿔줬습니다.
자바 코드로 먼저 확인해보겠습니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/*
N진수를 받아 K진법으로 만드는 프로젝트
2진수 ~16진수를 입력받아, 2진수 ~16진수로 변환해주는 프로그램
진수를 입력받고 10진수로 변환한 다음, 다시 원하는 진수로 변환시켜보자.
*/
public class NotationConversion {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("몇 진수를 입력하시겠습니까? (2~16만입력만 가능합니다.)");
int N = Integer.parseInt(br.readLine());
System.out.println("수를 입력해 주세요. 10이상은 대문자를 입력하십시오.");
String number = br.readLine();
// 먼저 입력 받은 각각의 진수를 10진법으로 바꿔준다.
int decimal = toDecimal(N, number);
System.out.println("몇 진수로 바꾸시겠습니까?");
int K = Integer.parseInt(br.readLine());
String answer = conversionToK(decimal, K);
System.out.print("결과 : " + answer);
}
// N진수를 10진수로 변환.
public static int toDecimal(int N, String number) {
int result = 0;
// 입력이 10진법인 경우 바로 리턴
if(N == 10) {
return Integer.parseInt(number);
}
else if(N >= 2 && N <= 16){
char[] num = number.toCharArray();
/*
0부터 시작하여 진수와 곱해주고 각 자리 수 숫자를 더해준다. 그리고 그 결과를 다음 자리수로 갈 때 진수와 곱해주고 현재 자리수 값을 더해준다. 반복.
*/
for(int i=0; i<num.length; i++) {
if(!errorCheck(num[i], N)) {
System.out.println("잘못된 입력입니다. 프로그램을 다시 실행하십시오.");
System.exit(0);
}
// 10이상의 숫자는 'A'를 빼고 +10을 해주면 된다.
if(num[i] >= 'A') {
result = result * N + (num[i] - 'A' + 10);
}
else {
result = result * N + (num[i] - '0');
}
}
}
else {
System.out.println("계산할 수 없는 진수입니다. 프로그램을 다시 실행하십시오.");
System.exit(0);
}
return result;
}
// 10진수를 K진수로 변환.
public static String conversionToK(int decimal, int K) {
StringBuilder sb = new StringBuilder();
int current = decimal;
while(current > 0) {
// N진법으로 나누었는데 10보다 작으면 바로 추가
if(current % K < 10) {
sb.append(current % K);
}
// 10이상은 알파벳으로 표기한다.
else {
// 10진수를 구해주는 법과 반대로 수행해주면 된다. 10이상의 수부터 표현할 수 있기 때문에 10을 빼주는 것이다.
sb.append((char)(current % K - 10 + 'A'));
}
current /= K;
}
return sb.reverse().toString();
}
// 주어진 진법 보다 높은 숫자가 입력으로 들어오면 오류.
public static boolean errorCheck(char num, int notation) {
int n = 0;
if(num >= 'A') {
n = num - 'A' + 10;
}
else {
n = num - '0';
}
if(n >= notation) {
return false;
}
return true;
}
}
Step 1. 입력받은 N진수를 10진수로 변환.
N진수에서 10진수로 변환할 때, 각 자릿수마다 10진수 결과에 N을 곱해주면서 각 자릿수의 값을 더해주는 방식으로 해결했습니다.
맨 마지막 자릿수(일의 자리)는 0승을 곱해주기 때문에 처음 시작할 때의 result 값을 0으로 설정해줬습니다.
1111(8)을 10진수로 변환하는 과정을 표로 보여드리겠습니다. 1111(8) = 585(10)
i | num[i] | result = result * 8 + (num[i]) |
0 | 1 | 1 = 0 * 8 + (1) |
1 | 1 | 9 = 1 * 8 + (1) |
2 | 1 | 73 = 9 * 8 + (1) |
3 | 1 | 585 = 73 * 8 + (1) |
Step2. 10진수를 K진수로 변환.
10진수를 K진수로 변환하는 방법은 간단합니다. 수학적으로는 10진법으로 표기된 숫자를 K로 나누어 그 나머지를 표시하고 더 이상 나누어지지 않을 때까지 반복하면 됩니다.
여기서 주의할 점은 일반적으로 String 타입으로 정답을 도출해 낼 것입니다. 이 과정에서 최종 String값을 reverse()해줘야 정상적인 답이 도출됩니다.
BinaryToHexadecimal (2진법 -> 16진법)
10진법의 변환 과정을 거치지 않고 2진법에서 16진법으로 바로 바꾸는 방법입니다.
이 방법은 자주 출제되고 여기저기 노출되는 유형이기 때문에 정리하겠습니다.
사실 이 메소드를 구현하는 것이 코딩 테스트에 나왔었는데, 하 너무 아쉽습니다.
정말 간단합니다.
16^1 = 2^4인 점을 생각한다면,
2진수의 4비트가 16진수의 1비트를 나타내는 원리를 이용하는 것이 핵심 포인트입니다.
코드로 확인하겠습니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class binary2Hex {
// 2진법 -> 16진법 변환하기
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("2진수를 입력하십시오 : " );
String binary = br.readLine();
System.out.println(binToHex(binary));
}
public static String binToHex(String binary) {
String answer = "";
StringBuilder sb = new StringBuilder();
int length = binary.length();
// 4로 나누어 떨어질 때까지 0을 앞에다 추가해준다.
// 4자리로 끊기 위함.
while(length % 4 != 0) {
sb.append("0");
length++;
}
binary = sb.toString() + binary;
// 전체 길이에서 4로 나눠줌으로써 총 반복횟수 결정.
for(int i=0; i<length / 4; i++) {
// 4자리씩 끊은 2진수 저장.
String subBinary = binary.substring(i*4, i*4+4);
int Hex = 0;
// 10진법의 수를 K진법으로 바꾸는 방법과 유사.
// 앞에서부터 진법을 차례대로 곱해가면서 현재 자리의 수를 더해준다.
for(int j = 0; j<subBinary.length(); j++) {
char num = subBinary.charAt(j);
if(num >= '0' && num <= '9') {
Hex = Hex * 2 + (num-'0');
}
else {
Hex = Hex * 2 + (num - 'A' + 10);
}
}
if(Hex >= 10) answer += (char)(Hex - 10 + 'A');
else answer += Hex;
}
return "0x"+answer;
}
}
주의사항
☞ 2진수는 4자리씩 끊어지지 않을 수 있습니다.
- (16진수의 길이) % 4 == 0이 될 때까지, 기존 16진수 앞에 "0"을 붙여줍니다.
☞ 4자리씩 끊어서 나온 2진수의 각 자릿수 합을 16진수의 한 자릿수로 바꿔줍니다.
- 예를 들어, 28(10) = 11100(2)
-> "0" 추가
-> 0001 1100
-> 4자리씩 10진수 도출 = 1, 12
-> 16진수로 변환 = 1, C
☞ 16진수임을 표시하기 위해 앞에 "0x"를 붙여줍니다.
-> "0x" 추가
= 0x1C
※ 간단하게 진행한 알고리즘 토이 프로젝트라 미흡하고 오류가 많을 수 있습니다. 피드백은 환영합니다.
'공부 || 정리 > Algorithm' 카테고리의 다른 글
[Java] 다익스트라(Dijkstra) 알고리즘. (0) | 2021.05.28 |
---|---|
[Java] 이분 탐색(Binary Search) (2) | 2021.05.15 |
[Java]투 포인터 / 슬라이딩 윈도우 알고리즘 (6) | 2021.05.13 |
[Java] DFS, BFS 정리 (4) | 2020.12.15 |
[Java] 스택(Stack) 정리 및 구현 (1) | 2020.06.17 |
댓글
이 글 공유하기
다른 글
-
[Java] 다익스트라(Dijkstra) 알고리즘.
[Java] 다익스트라(Dijkstra) 알고리즘.
2021.05.28 -
[Java] 이분 탐색(Binary Search)
[Java] 이분 탐색(Binary Search)
2021.05.15 -
[Java]투 포인터 / 슬라이딩 윈도우 알고리즘
[Java]투 포인터 / 슬라이딩 윈도우 알고리즘
2021.05.13 -
[Java] DFS, BFS 정리
[Java] DFS, BFS 정리
2020.12.15