问题描述
我们都知道,当我们需要进制转换时,可以有以下的方法:
1.字符串 到 整型:使用 atoi
2.整型 到 字符串:使用 sprintf
但是,如果我们想直接对字符串进行进制转换,又或者是输入的整数太长,通常的方法就无法满足我们的需求
原理分析
首先我们知道,任意
n
n
n进制数(
n
∈
N
,
n
≥
2
n\in N,n \ge 2
n∈N,n≥2)可以写成以下的形式:
a
m
a
m
−
1
.
.
.
a
1
a
0
=
a
0
n
0
+
a
1
n
1
+
.
.
.
+
a
m
−
1
n
m
−
1
+
a
m
n
m
(
m
∈
N
)
a_ma_{m-1}...a_1a_0 = a_0 n^0+a_1n^1+...+a_{m-1}n^{m-1}+a_mn^m \quad (m \in N) \\
amam−1...a1a0=a0n0+a1n1+...+am−1nm−1+amnm(m∈N)
例如:
十进制数
6371
6371
6371 ,可以表示成:
6371
=
1
∗
1
0
0
+
7
∗
1
0
1
+
3
∗
1
0
2
+
6
∗
1
0
3
6371 = 1 *10^0 + 7 * 10^1 + 3*10^2+6*10^3
6371=1∗100+7∗101+3∗102+6∗103
十六进制数
7
f
e
6
7fe6
7fe6 ,可以表示成:
7
f
e
6
=
6
∗
1
6
0
+
14
∗
1
6
1
+
15
∗
1
6
2
+
7
∗
1
6
3
7fe6 = 6 * 16^0 + 14*16^1+15*16^2+7*16^3
7fe6=6∗160+14∗161+15∗162+7∗163
知道了这个之后,我们可以使用下面得方法进行简单的进制转换,如:
6371
=
1
∗
1
0
0
+
7
∗
1
0
1
+
3
∗
1
0
2
+
6
∗
1
0
3
6371 = 1 *10^0 + 7 * 10^1 + 3*10^2+6*10^3
6371=1∗100+7∗101+3∗102+6∗103
我们将十进制数
6371
6371
6371 转换为 十六进制数,因为有:
1
0
0
=
1
6
0
1
0
1
=
10
∗
1
0
0
=
10
∗
1
6
0
1
0
2
=
10
∗
1
0
1
=
100
∗
1
6
0
=
4
∗
1
6
0
+
6
∗
1
6
1
1
0
3
=
10
∗
1
0
2
=
40
∗
1
6
0
+
60
∗
1
6
1
=
8
∗
1
6
0
+
68
∗
1
6
1
=
8
∗
1
6
0
+
14
∗
1
6
1
+
3
∗
1
6
2
\begin{aligned} 10^0& = 16^0 \\10^1&=10*10^0= 10*16^0 \\10^2& =10*10^1 =100*16^0 = 4*16^0 + 6 * 16^1 \\10^3&=10*10^2=40*16^0+60*16^1=8*16^0+68*16^1= 8*16^0 + 14*16^1 + 3*16^2 \end{aligned}
100101102103=160=10∗100=10∗160=10∗101=100∗160=4∗160+6∗161=10∗102=40∗160+60∗161=8∗160+68∗161=8∗160+14∗161+3∗162
我们将其全部代入上面的式子,有:
6371
=
1
∗
1
6
0
+
7
∗
(
10
∗
1
6
0
)
+
3
∗
(
4
∗
1
6
0
+
6
∗
1
6
1
)
+
6
∗
(
8
∗
1
6
0
+
14
∗
1
6
1
+
3
∗
1
6
2
)
=
(
1
+
70
+
12
+
48
)
∗
1
6
0
+
(
18
+
84
)
∗
1
6
1
+
18
∗
1
6
2
=
131
∗
1
6
0
+
102
∗
1
6
1
+
18
∗
1
6
2
=
(
3
∗
1
6
0
+
8
∗
1
6
1
)
∗
1
6
0
+
(
6
∗
1
6
0
+
6
∗
1
6
1
)
∗
1
6
1
+
(
2
∗
1
6
0
+
1
6
1
)
∗
1
6
2
=
3
∗
1
6
0
+
14
∗
1
6
1
+
8
∗
1
6
2
+
1
∗
1
6
3
\begin{aligned} 6371 &= 1 *16^0 + 7 * (10*16^0) + 3*(4*16^0 + 6 * 16^1)+6*(8*16^0 + 14*16^1 + 3*16^2) \\ &= (1+70+12+48)*16^0 + (18+84)*16^1+18*16^2 \\ &=131*16^0 +102*16^1+18*16^2 \\ &= (3*16^0+8*16^1)*16^0 + (6*16^0+6*16^1)*16^1+(2*16^0+16^1)*16^2 \\ &= 3*16^0 + 14*16^1 + 8*16^2 + 1*16^3 \end{aligned}
6371=1∗160+7∗(10∗160)+3∗(4∗160+6∗161)+6∗(8∗160+14∗161+3∗162)=(1+70+12+48)∗160+(18+84)∗161+18∗162=131∗160+102∗161+18∗162=(3∗160+8∗161)∗160+(6∗160+6∗161)∗161+(2∗160+161)∗162=3∗160+14∗161+8∗162+1∗163
可得转换后的十六进制数为 18 e 3 18e3 18e3
我们总结一下,对于
n
n
n进制数(
n
∈
N
,
n
≥
2
n\in N,n \ge 2
n∈N,n≥2)
∀
m
∈
N
a
m
a
m
−
1
.
.
.
a
1
a
0
=
a
0
n
0
+
a
1
n
1
+
.
.
.
+
a
m
−
1
n
m
−
1
+
a
m
n
m
\forall m \in N \\ a_ma_{m-1}...a_1a_0 = a_0 n^0+a_1n^1+...+a_{m-1}n^{m-1}+a_mn^m
∀m∈Namam−1...a1a0=a0n0+a1n1+...+am−1nm−1+amnm
我们要将其转换为
n
′
n'
n′进制数(
n
′
∈
N
,
n
≥
2
n'\in N,n \ge 2
n′∈N,n≥2)
先列出下面的一串式子:
n
0
=
b
00
n
′
0
+
.
.
.
b
0
c
0
n
′
c
0
n
1
=
b
10
n
′
0
+
.
.
.
b
1
c
1
n
′
c
1
.
.
.
n
m
=
b
m
0
n
′
0
+
.
.
.
b
m
c
m
n
′
c
m
n^0 = b_{00}n'^0 + ...b_{0c_0}n'^{c_0} \\n^1 = b_{10}n'^0 + ...b_{1c_1}n'^{c_1} \\... \\n^m = b_{m0}n'^0 + ...b_{mc_m}n'^{c_m}
n0=b00n′0+...b0c0n′c0n1=b10n′0+...b1c1n′c1...nm=bm0n′0+...bmcmn′cm
然后我们将上面得式子代回
a
m
a
m
−
1
.
.
.
a
1
a
0
a_ma_{m-1}...a_1a_0
amam−1...a1a0中,得
d
0
n
′
0
+
d
1
n
′
1
+
.
.
.
d
m
′
−
1
n
′
m
′
−
1
+
d
m
′
n
′
m
′
d_{0} n'^0 + d_1n'^1+...d_{m'-1}n'^{m'-1}+d_{m'}n'^{m'}
d0n′0+d1n′1+...dm′−1n′m′−1+dm′n′m′
即进行转换后的数字为 d m ′ d m ′ − 1 . . . d 1 d 0 d_{m'}d_{m'-1}...d_1d_0 dm′dm′−1...d1d0 (超过十进制要进行对应字符替换)
虽然这种进制转换方法手算并不方便,效率也不算高,但对于字符串的进制转换来说,是比较有效的一个方法
代码实现
步骤:
- 实现将 n n n的任意次方分解为 n ′ n' n′的任意次方线性组合
- 将分解后的 n n n乘上系数,放到新的字符串中
- 得到进制转换后的字符串
C++代码如下:
- 头文件 SystemTransform.h
//SystemTransform.h
#ifndef _YYYCZ_SYSTEM_TRANSFORM_NUMBER_LIST
#define _YYYCZ_SYSTEM_TRANSFORM_NUMBER_LIST "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
#include<string>
namespace YYYCZ
{
//直接对字符串进行进制转换
//参数依次为 1.转换的字符串 2.原进制 3.新进制
//可转换的进制的范围为 2 - 62
//超出该范围不会进行转换,并返回原字符串
//转换后 0 - 62 对应字符依次为 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
std::string systemTransform(const std::string& num_str, char original_carry, char target_carry);
//使用提供的字符直接对字符串进行进制转换
//参数依次为 1.转换的字符串 2.原进制 3.新进制 4.新进制的字符 5.原进制的字符
//必须提供目标进制的转换字符,原进制可不提供
//注意:涉及到的进制转换不建议超过128进制,并且绝对不能超过256进制
//注意:进制数若超出对应字符数将不进行转换,并返回原字符串
std::string systemTransform(const std::string& num_str, char original_carry, char target_carry,
const char target_char_list[], const char char_list[] = _YYYCZ_SYSTEM_TRANSFORM_NUMBER_LIST);
}
#endif
- 源文件 SystemTransform.cpp
//SystemTransform.cpp
#include<vector>
#include "SystemTransform.h"
std::vector<uint16_t> indexMutiply(const std::vector<uint16_t>& _a, const std::vector<uint16_t>& _b, char _carry)
{
std::vector<uint16_t> result(_a.size() + _b.size() - 1, 0);
size_t index = 0;
char temp = 0;
for (auto itr = result.begin(); itr != result.end(); itr++, index++)
{
auto _aitr = _a.begin() + (index >= _b.size() ? index - _b.size() + 1 : 0);
auto _bitr = _b.begin() + (index - (index >= _b.size() ? index - _b.size() + 1 : 0) + 1);
for (size_t x = (index >= _b.size() ? index - _b.size() + 1 : 0); x <= std::min(_a.size() - 1, index); x++)
*itr += *(_aitr++) * *(--_bitr);
}
for (auto itr = result.begin(); itr != result.end(); itr++, index++)
if (*itr >= _carry && itr != result.end() - 1)
*(itr + 1) += *itr / _carry,
* itr %= _carry;
while (result.back() >= _carry)
temp = result.back() / _carry,
result.back() %= _carry,
result.push_back(temp);
return result;
}
bool systemTransform_toNum(char& _num, char _carry,const char _char_list[])
{
for (char i = 0; i < _carry; i++)
{
if (_char_list[i] == _num)
{
_num = i;
return true;
}
}
return false;
}
std::string YYYCZ::systemTransform(const std::string& _text, char original_carry, char target_carry,
const char target_char_list[], const char char_list[])
{
if (original_carry == 0 || original_carry == 1 || original_carry > strlen(char_list) ||
target_carry == 0 || target_carry == 1 || target_carry > strlen(target_char_list) ||
original_carry == target_carry)
return _text;
std::vector<uint16_t> original_split, act_split = { 1 }, temp_save;
char temp_num = original_carry;
uint16_t temp_unum = 0;
bool positive = true;
do
{
original_split.push_back(temp_num % target_carry);
temp_num /= target_carry;
} while (temp_num > 0);
for (auto i = _text.rbegin(); i != _text.rend(); i++)
{
temp_num = *i;
if (systemTransform_toNum(temp_num, original_carry, char_list))
{
if (act_split.size() > temp_save.size())
temp_save.resize(act_split.size(), 0);
auto temp_itr = temp_save.begin();
for (auto j = act_split.begin(); j != act_split.end(); j++)
{
*temp_itr += (uint16_t)(*j) * (uint16_t)temp_num;
if (temp_itr + 1 == temp_save.end())
{
while (temp_save.back() >= target_carry)
{
temp_unum = temp_save.back() / target_carry;
temp_save.back() %= target_carry;
temp_save.push_back(temp_unum);
}
break;
}
else
{
if (*temp_itr >= target_carry)
{
*(temp_itr + 1) += *temp_itr / target_carry;
*temp_itr %= target_carry;
}
temp_itr++;
}
}
act_split = indexMutiply(original_split, act_split, target_carry);
}
else
{
if (*i == '-')
positive = false;
break;
}
}
for (auto i = temp_save.begin(); i != temp_save.end(); i++)
*i = target_char_list[*i];
if (!positive)
temp_save.push_back('-');
std::string result;
result.resize(temp_save.size());
auto str_itr = result.rbegin();
for (auto i = temp_save.begin(); i != temp_save.end(); i++, str_itr++)
*str_itr = *i;
return result;
}
std::string YYYCZ::systemTransform(const std::string& num_str, char original_carry, char target_carry)
{
return YYYCZ::systemTransform(num_str, original_carry, target_carry, _YYYCZ_SYSTEM_TRANSFORM_NUMBER_LIST);
}
- 测试代码 main.cpp
//main.cpp
#include<iostream>
#include "SystemTransform.h"
using namespace std;
using namespace YYYCZ;
//将十进制数转换为2、4、8、16、26、32、36、52、58、62、64进制数
int main()
{
string d_num_str;
cout << "请输入一个十进制数:";
while (cin >> d_num_str)
cout << "进制转换后:" << endl,
cout << "二进制:" << systemTransform(d_num_str, 10, 2) << endl,
cout << "四进制:" << systemTransform(d_num_str, 10, 4) << endl,
cout << "八进制:" << systemTransform(d_num_str, 10, 8) << endl,
cout << "十进制:" << systemTransform(d_num_str, 10, 10) << endl,
cout << "十六进制:" << systemTransform(d_num_str, 10, 16) << endl,
cout << "二十六进制:" << systemTransform(d_num_str, 10, 26, "abcdefghijklmnopqrstuvwxyz") << endl,
cout << "三十二进制:" << systemTransform(d_num_str, 10, 32, "0123456789ABCDEFGHJKMNPQRSTVWXYZ") << endl,
cout << "三十六进制:" << systemTransform(d_num_str, 10, 36, "0123456789abcdefghijklmnopqrstuvwxyz") << endl,
cout << "五十二进制:" << systemTransform(d_num_str, 10, 52, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") << endl,
cout << "五十八进制:" << systemTransform(d_num_str, 10, 58, "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ") << endl,
cout << "六十二进制:" << systemTransform(d_num_str, 10, 62) << endl,
cout << "六十四进制:" << systemTransform(d_num_str, 10, 64, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") << endl,
cout << "\n请输入一个十进制数:";
return 0;
}
测试结果
针
不
戳
,
转
换
出
来
的
结
果
针
不
戳
针不戳,转换出来的结果针不戳
针不戳,转换出来的结果针不戳
可以看到十进制数
6371
6371
6371 转换为十六进制数结果为
18
e
3
18e3
18e3 ,与上面结果相同
对于超长整数也能进行正常的转换