“进制”只是表示“量”的一种方式
关于进制转换,我们首先要理解“进制”的概念。
“进制”只是表示“量”的一种方式,同一个“量”用不同的“进制”表示,发生的应当是“等量的转换”
百度百科:“数制”只是一套符号系统来表示指称“量”的多少。我们用“1”这个符号来表示一个这一“量”的概念。自然界的“量”是无穷的,我们不可能为每一个“量”都造一个符号,这样的系统没人记得住。所以必须用有限的符号按一定的规律进行排列组合来表示这无限的“量”。符号是有限的,这些符号按照某种规则进行排列组合的个数是无限的。十进制是10个符号的排列组合,二进制是2个符号的排列组合。
在进行进制转换时有一基本原则:转换后表达的“量”的多少不能发生改变。二进制中的111个苹果和十进制中的7个苹果是一样多的。
举例:
量的计算公式:
量 = Xi * base^i (因为这里使用10进制作为中间量, 所以Xi表示某个位上的10进制数)
同一个量的衡量:
16 (10进制数) = 6 * 10^0 + 1 * 10^1 (使用10进制衡量)
进制转换分2个流程
进制转换的工作流程分为2个要步骤:
1. 从 源文本(源进制)→ 10进制数值
2. 从 10进制数值 → 目标文本(目标进制)
注:为了方便起见,我们假设“任意进制”指2到16进制中的任何一个进制。(对于10进制以上的进制, 如16进制, 需要额外指定1个字符集来标明指定的值,如A = 10, B = 11等等)
中间的10进制数 便是衡量量的一个中介值,利用该数值完成进制转换。
我们所需要完成的函数原型:
void transX2X(char src[], int srcBase, int destBase, char dest[]); // char src[]: 源文本 // int srcBase: 源进制 // char dest[]: 目标文本 // int destBase: 目标进制
利用10进制数作为中介的任意进制转换
#include#include #include #include #pragma warning (disable:4996) #define scale 1024 using namespace std; int getSrcNum(int srcBase, char num) { if (srcBase >= 2 && srcBase <= 10) { return num - '0'; } return 10 + (num - 'A' + 1); } char getDestChar(int num) { // 数字 if (num >= 0 && num <= 9) { return '0' + num; } // 字母 return 'A' + (num - 10); } void translateMagicNum(int magicNum, int destBase, char dest[]) { // Translate int i = 0; while (magicNum > 0) { int curDestNum = magicNum % destBase; char curDestChar = getDestChar(curDestNum); magicNum /= destBase; dest[i] = curDestChar; i++; } // Reverse. reverse(dest, dest + strlen(dest)); } void transX2X(char src[], int srcBase, int destBase, char dest[]) { // Calc MagicNum. reverse(src, src + strlen(src)); int magicNum = 0; for (int i = 0; i < strlen(src); i++) { int curSrcNum = getSrcNum(srcBase, src[i]); magicNum += curSrcNum * (pow(srcBase, i)); } // Translate translateMagicNum(magicNum, destBase, dest); } int main() { // I. char src[scale] = { 0 }; char dest[scale] = { 0 }; printf("请输入待转换数据:\n"); scanf("%s", &src); int src_base, dest_base; printf("请输入待转换数据的进制数:\n"); scanf("%d", &src_base); printf("请输要待转换数据的进制数:\n"); scanf("%d", &dest_base); // A. transX2X(src, src_base, dest_base, dest); printf("转换后的结果为:\n"); printf("%s\n", dest); // O. return 0; }
充分利用C语言的标准库!
由于进制转换的核心流程主要是2个步骤:
1. 将 源文本(源进制) 转换为 10进制数
2. 将 10进制数 转换为 目标文本(目标进制)
所以,我们不妨试试下面这2个C语言函数.
strtol() 将 任意进制的文本 转换为 10进制数
itoa() 将 10进制数 转换为 任意进制文本
将strtol()和iota()进行组合, 即可完成任意进制转任意进制。
利用strtol()与itoa()完成任意进行转化
// 只需要1行代码的任意进制转换. void transX2X(char src[], int srcBase, int destBase, char dest[]) { itoa(strtol(src, 0, srcBase), dest, destBase); }
到此,只需要用我们新写的transX2X()替换原来的transX2X()即可.
不妨测试几组数据叭,可以看出,这个函数工作地非常好,确实给出了正确的结果。
顺便说一下,使用strtol()和itoa()完成的任意进制转换函数,实际上不仅仅支持2-16进制的转换。它可以支持到2-36进制之间的任意转换哦。
来试试Problem1647和Problem1659叭
SOJ1647 进制转换(一) AC.c
r[];main(n,b){scanf("%d %d",&n,&b);puts(itoa(n,r,b));}
SOJ1659 进制转换(二) AC.c
a[];main(b){scanf("%s%d",&a,&b);printf("%d",strtol(a,0,b));}