Base32 만들기 #66
Replies: 9 comments 15 replies
-
Base64가 많이들 접하셨겠지만 64진수로 구성된 데이터 표시 단위로 보시면 됩니당 :) @YoungSeokHong 님이 언급하신대로 Base2와 Base16이 구현되어 있는데 |
Beta Was this translation helpful? Give feedback.
-
@YoungSeokHong |
Beta Was this translation helpful? Give feedback.
-
바쁘신 와중에도 좋은 내용 감사합니다! |
Beta Was this translation helpful? Give feedback.
-
16진수에서 int로 변환한 뒤 32진수로 변환우선은 16진수에서 int로 변환한 뒤, 32진수로 변환하는 방법으로 함수들을 만들어봤습니다. getBaseString 함수(16진수에서 int로 변환)#include <cmath>
std::string Base32::getBaseString() {
int sum = 0;
int size = hexVector.size();
for(int i=0; i<size; i++) {
sum += (hexToDec(hexVector[i]) * pow(16, size - i - 1));
}
return decToBase32(sum);
} int에서 32진수로 바꿔주는 함수std::string Base32::decToBase32(int sum){
std::string result;
int count = 0;
int base32;
for (int i = 0; i < 32; i += 5) {
if ((sum >> i) > 0) count = i / 5;
}
for (int i = count * 5; i >= 0; i -= 5) {
base32 = ((sum >> i) & 31);
if (base32 < 10) result.push_back(base32 + '0');
else result.push_back(base32 - 10 + 'a');
}
return result;
} 만들고 나니 생각보다 구조도 간단하고 이방법도 괜찮은 것 같습니다. int도 안 거치고 바로 비트연산으로 하는 방법도 있을 것 같은데 조금 더 생각해봐야겠네요. 다 만들어서 gtest 돌려볼려 했는데 이상하게 어딘가 빼먹은 것 같은데 다 비교해봤을 때는 Base16이랑 헤더파일, Exception파일도 같은데 어디가 잘 못됐는지를 못 찾겠네요ㅠ 혹시 같은 문제를 겪고 계시거나 짐작가는 부분이 있으신 분은 피드백 부탁드립니다! 저도 오류 잡는대로 다시 코멘트 하겠습니다. |
Beta Was this translation helpful? Give feedback.
-
Base32 테스트 결과getBaseString 함수를 약간 수정해서 Base32테스트를 진행했습니다. getBaseStringstd::string Base32::getBaseString() {
int sum = 0;
int size = hexVector.getSize();
int i =0;
for(u_int8_t hex : hexVector) {
sum += (hex * pow(16, size - i - 1));
i++;
}
return decToBase32(sum);
} Test Value::testing::Values(
TestParamType(std::vector<u_int8_t>{ 0x61 }, "31"),
TestParamType(std::vector<u_int8_t>{ 0x62 }, "32"),
TestParamType(std::vector<u_int8_t>{ 0x63 }, "33"),
TestParamType(std::vector<u_int8_t>{ 0x99 }, "4p"),
TestParamType(std::vector<u_int8_t>{ 0x98 }, "4o"),
TestParamType(std::vector<u_int8_t>{ 0x61, 0x62, 0x63 }, "313233"),
TestParamType(std::vector<u_int8_t>{ 0x6c, 0x6d, 0x6e, 0x6f }, "3c3d3e3f"),
TestParamType(std::vector<u_int8_t>{ 0x65, 0x66, 0x67 }, "353637")
) 그 결과, 수를 하나만 입력했을 때는 잘 계산하지만 입력값이 2개 이상일 때는 오류가 났습니다. 두 개 이상의 수가 들어올 때 이를 int로 변환하는 과정에서 수를 모두 더해버려서 숫자가 떡이 되버리는 것 같습니다ㅠ 가령 0x61, 0x62, 0x63이 들어왔을 때 이 세수를 모두 더해버려서 294(10)를 32진수로 변환하는 것 같습니다.
해결 방법으로는 어차피 u_int_8이 256크기의 숫자이기 때문에 hex를 두개씩만 받아서 더하고 계산하도록 픽스해놓는 방법이 있긴 한데, 그다지 좋은 방법은 아닐 것 같습니다 ㅠㅠ 조금 더 생각해보고 도저히 안되겠으면 그 방법을 사용해야될 것 같습니다. 전체 코드를 보시고싶으신 분은 제가 포크를 딴 repository에 added_base32 브랜치에서 확인하실 수 있습니다! |
Beta Was this translation helpful? Give feedback.
-
Base32 완성우선 어제 말했던 방식으로 getBaseString을 수정해서 Base32를 완성 시켰습니다. getBaseStringstd::string Base32::getBaseString() {
std::stringstream ss;
int sum = 0;
int i =0;
int size = hexVector.getSize();
for(u_int8_t hex : hexVector) {
if(i % 2 == 0) sum = hex * 16;
else {
sum += hex;
ss << decToBase32(sum);
}
i++;
}
return ss.str();
} decToBase32std::string Base32::decToBase32(int sum){
std::string result;
int count = 0;
int base32;
for (int i = 0; i < 32; i += 5) {
if ((sum >> i) > 0) count = i / 5;
}
for (int i = count * 5; i >= 0; i -= 5) {
base32 = ((sum >> i) & 31);
if (base32 < 10) result.push_back(base32 + '0');
else result.push_back(base32 - 10 + 'a');
}
return result;
} 결과계속해서 Base64 만들어보겠습니다! |
Beta Was this translation helpful? Give feedback.
-
모든 계산을 비트연산으로 수정처음에 목표했던 것 처럼 int를 사용하지 않고 받은 수를 바로 비트연산으로 왼쪽으로 4칸 밀어줘서 += hex * 16과 같은 효과가 나도록 했습니다. 그 뒤, 들어온 수는 비트연산자 예를들어 '0x6'에 해당하는 '0110'을 받을 경우
Base32의 getBaseString 함수std::string Base32::getBaseString() {
std::stringstream ss;
u_int8_t sum = 0;
int i =0;
for(u_int8_t hex : hexVector) {
if(i % 2 == 0) {
sum = (hex << 4);
}else {
sum |= hex;
ss << decToBase32(sum);
}
i++;
}
return ss.str();
} ‼질문@designe @yeonns |
Beta Was this translation helpful? Give feedback.
-
@designe 앞에서부터 읽을 경우예를들어 0x5A 즉 뒤에서부터 읽을 경우 (단순 16->32진수 변환)하지만 뒤에서부터 읽을 경우, 앞에서와 같이 0x5A 즉 이러한 이유 때문에 뒤에서 부터 읽어서 변환한 수를 패킷으로 보내고 도착해서 16진수로 바꿔준다음 앞의 0들을 날리는 방식을 선택하는 것이 어떨까 싶습니다! 제가 맞는 말을 하는지 모르겠네요 ㅠㅠ 검토 부탁드립니다! |
Beta Was this translation helpful? Give feedback.
-
뒤에서부터 읽는 경우의 Base32를 만들었습니다. getBaseString 함수std::string Base32::getBaseString() {
std::stringstream ss;
int sum = 0;
int rest = hexVector.getSize() % 5;
int count = 0;
for(u_int8_t hex : hexVector) {
count++;
sum = (sum << 4) | hex;
if(count % 5 == rest) {
ss << bitsToBase32(sum);
sum = 0;
}
}
return ss.str();
} 이 부분 구현이 생각보다 까다로웠습니다ㅠㅠ 32는 2^5이고 16은 2^4이므로 4와 5의 최소공배수인 20을 사용했습니다. 즉 20비트씩 끊어서 계산을 했습니다. 이때 앞에서부터 20비트씩 끊으면 숫자가 변형될 수 있으므로 뒤에서부터 20비트씩 끊기위해 hexVector의 크기를 5로 나눈 나머지를 구해서 먼저 그 나머지만큼 끊어서 bitsToBase32함수를 돌린 뒤, 20개씩 끊어서 bitsToBase32함수를 돌렸습니다. 예를 들면 16진수 이 방법 덕분에 들어오는 16진수가 아무리 커도 모두 32진수로 바꿀 수 있게 되었습니다. ::testing::Values(
TestParamType(std::vector<u_int8_t>{ 0x05 }, "5"),
TestParamType(std::vector<u_int8_t>{ 0x60 }, "30"),
TestParamType(std::vector<u_int8_t>{ 0x63 }, "33"),
TestParamType(std::vector<u_int8_t>{ 0x99 }, "4p"),
TestParamType(std::vector<u_int8_t>{ 0x98 }, "4o"),
TestParamType(std::vector<u_int8_t>{ 0x61, 0x62, 0x63 }, "62oj3"),
TestParamType(std::vector<u_int8_t>{ 0x6c, 0x6d, 0x6e, 0x6f }, "1m6qrjf"),
TestParamType(std::vector<u_int8_t>{ 0x65, 0x66, 0x67 }, "6apj7"),
TestParamType(std::vector<u_int8_t>{
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79
}, "30c5h66p35cpjmgqbaddm6qrjfe1on4srkelr7eu3p")
) 위 테스트 수행결과 모두 성공했습니다 bitsToBase32 함수std::string Base32::bitsToBase32(int value){
std::string result;
int count = 0;
int base32;
for (int i = 0; i < 20; i += 5) {
if ((value >> i) > 0) count = i / 5;
}
for (int i = count * 5; i >= 0; i -= 5) {
base32 = ((value >> i) & 31);
result.push_back(convertInt2Char(base32));
}
return result;
} 저번에 만들어뒀던 32진수를 만들어내는 함수입니다. 이 함수는 특별히 바뀐건 없고 들어오는 값이 최대 32비트에서 최대 20비트로 변경되었으므로 계산 효율을 아주 조금이나마 높이고자 첫 for문의 조건을
|
Beta Was this translation helpful? Give feedback.
-
안녕하세요. Base32를 만들기 위해 Discussion을 하나 새로 만들었습니다. 앞으로 Base32와 관련된 내용들은 이곳에서 이야기 나눠주세요!
그동안 대회준비에 밀린 과제에 바빠서 너무 오랜만에 코멘트를 하네요 죄송합니다ㅠㅠ 우선, 공부할겸 Base32을 Base16을 참고해서 구현해봤습니다.
source/Base32.cpp 변환함수(Char2Int)
우선 Base16의 Char2Int 변환함수입니다.
16진수와 ASCII코드를 알고 있다면 구조는 비교적 단순합니다.
숫자의 경우에는 ASCII # 0x30 ~ 0x39에 위치하고 있기 때문에 0x30에 해당하는 '0'을 빼주었고 문자의 경우에는 ASCII # 0x61~에 위치하고 있기 때문에 0x61에 해당하는 'a'를 빼주되 'a'는 16진수에서 10진수 10에 해당하므로 10을 더해줬습니다. 여기서 저희가 할 일은 그저 32진법까지 문자를 추가해주는 것 입니다.
source/Base32.cpp 변환함수(Int2Char)
Base16의 Int2Char 변환함수입니다.
이 또한 저희가 해줄 것은 별로 없습니다. 들어온 숫자에 따라 인덱스에 해당하는 문자가 output으로 나가기 때문에 단순히 32진법에 해당하는 문자들을 모두 입력해주면 됩니다.
‼source/Base32.cpp getHexVector 함수
여기서 부터 조금 생각을 해봐야할 것 같습니다.
Base16의 경우 우리가 현재 쓰고 있는 HexVector가 16진수로 이루어져 있기 때문에 별 다른 변환없이 바로 hexVector의 값을 가져다 쓰면 됩니다.
하지만 Base2나 우리가 만들어야 할 Base32같은 경우에는 16진수로 이루어진 HexVector의 진법변환이 필요합니다.
Base2의 예를 들어 설명하겠습니다.
가령 1100(2) 즉 0xC에 해당하는 숫자가 들어왔을 때 아래 그림과 같이 & 연산자로 부분을 추출한 뒤 조건 연산자로 구분해 1100이 차례대로 result에 들어가게 됩니다.
비슷한 방식으로 16진수를 32진수로 바꾸는 방법을 생각중인데 이 경우에는 더 높은 진수로 바꿔줘야하고, 벡터를 한개씩 읽어 여러개의 벡터를 만드는 것이 아닌 여러 벡터를 읽어 더 적은 수의 벡터를 만들어야 하므로 생각이 조금 필요할 것 같습니다.
가장 편한 방법은 그냥 16진수를 10진수로 변환해서 계산한 뒤 다시 32진수로 바꿔주는 방법인데 이 방법은 코드도 더러워지고 속도도 느려질 것 같아 그다지 좋은 방법은 아닌 것 같습니다. 비트 연산으로 처리하는 것이 가장 좋을 것 같은데, 혹시 괜찮은 방법이 있으면 말씀해주세요!
그외
사실 그 외의 것들은 Base16을 참고하면서 하면 크게 어렵거나 생각해볼 것은 없을 것 같습니다.
추가적으로 base32Test.cpp의 test value들도 모두 16진수에서 32진수로 바꿔줬습니다.
쓰고 나니 너무 기네요 ㅠㅠ 혹시 읽어보시다가 이상한 부분 있으면 피드백 부탁드립니다! getHexVector함수 부분만 힘줘서 읽어주시면 될 것 같습니다ㅋㅋㅋ
Beta Was this translation helpful? Give feedback.
All reactions