5进制转换.docx
《5进制转换.docx》由会员分享,可在线阅读,更多相关《5进制转换.docx(27页珍藏版)》请在冰豆网上搜索。
5进制转换
第5章进制转换问题
基础知识
5.1.1相关概念
1.数制
数制是人们利用符号进行计数的一种科学方法。
数制也称为计数制,是用一组固定的符号和统一的规则来表示数值的方法。
2.进制
进制也就是进位制,是人们规定的一种进位方法。
对于任何一种进制——X进制,就表示某一位置上的数运算时是逢X进一位。
十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一。
3.数码
数制中表示基本数值大小的不同数字符号。
例如,十进制有10个数码:
0、1、2、3、4、5、6、7、8、9。
4.基数
数制所使用数码的个数。
例如,二进制的基数为2;十进制的基数为10。
5.位权
位权表示数的符号在不同的位置上时所代表的值是不同的。
也就是数制中某一位上的1所表示数值的大小(所处位置的价值)。
例如,十进制的123,1的位权是100,2的位权是10,3的位权是1。
5.1.2各种常见的进制
人们通常采用的进制有十进制、二进制、八进制和十六进制等。
1.十进制(Decimal)
十进制是人们日常生活中最熟悉的进位计数制。
在十进制中,数码共有0,1,2,3,4,5,6,7,8,9这十个符号。
计数规则是逢十进一。
2.二进制(Binary)
二进制是在计算机系统中采用的进位计数制。
二进制数有两个特点:
在二进制中,数码只有0和1两个符号。
计数规则是逢二进一。
为区别于其它进制数,二进制数的书写通常在数的右下方注上基数2,或在后面加上B表示。
例如:
二进制数可以写成()2,或写成B。
3.八进制数(Octal)
由于二进制数据的基数比较小,所以二进制数据的书写和阅读很不方便,为此,在小型机中引入了八进制。
八进制的基数R=8=23,有数码0、1、2、3、4、5、6、7,并且每个数码正好对应三位二进制数,所以八进制能很好地反映二进制。
八进制用下标8或数据后面加O表示例如:
二进制数据(11101010.010110100)2,对应的八进制数据8或。
4.十二进制(Duodecimal)
十二进制在生活中也是经常用到的,例如,长度单位一英尺等于12英寸,一先令等于12便士,就连足球比赛罚点球的英制长度也是12码。
此外还有一打12个,钟表转一圈12小时等等。
一般在十二进制中,10和11可用M和N表示,有时候也可用A和B表示。
5.十六进制(Hexadecimal)
十六进制是人们在计算机指令代码和数据的书写中经常使用的数制。
在十六进制中,由十六个字符0~9以及A,B,C,D,E,F(或a,b,…,f)组成(它们分别表示十进制数10~15)来描述。
计数规则是逢十六进一,即基数R=16=24,通常在表示时用尾部标志H或下标16以示区别。
例如:
十六进制数4AC8可写成(4AC8)16,或写成4AC8H。
6.六十进位制数(Sexagesimal)
古代人由于生产劳动的需要,要研究天文和历法,就牵涉到时间和角度了。
因为历法需要的精确度较高,时间的单位小时,角度的单位度都嫌太大。
必须进一步研究他们的小数。
它们的小数都具有这样的性质:
使1/2,1/3,1/4,1/5,1/6等都能成为他的整数倍。
以1/60作为单位,就正好具有这个性质。
譬如:
1/2等于30个1/60,1/3等于20个1/60,1/4等于15个1/60……这种小数的进位制在表示有些数时很方便。
例如常遇到的1/3,在十进位制中要变成无限小数,但在这种进位制中就是一个整数。
因此就出现了六十进制。
5.1.3进制转换
在实际运算中,我们经常用到各种不同的进制,这就需要在各种数制之间进行转换。
1.其他进制转换为十进制(按权求和)
方法是:
将其它进制按权位展开,然后各项相加,就得到相应的十进制数。
例1:
N=()B=()D
按权展开N=1*24+0*23+1*22+1*21+0*20+1*2-1+0*2-2+1*2-3
=16+4+2++=()D
例2:
(38A.11)16转换为十进制数
(38A.11)16
=3×162+8×161+10×160+1×16-1+1×16-2
=768+128+10++
=
2.十进制转换成其它进制
方法是:
分两部分分别进行的,即整数部分和小数部分。
(1)整数部分:
(基数除法)
把我们要转换的数除以新的进制的基数,把余数作为新进制的最低位;
把上一次得到的商再除以新的进制基数,把余数作为新进制的次低位;
继续上一步,直到最后的商为零,这时的余数就是新进制的最高位。
(2)小数部分:
(基数乘法)
把要转换数的小数部分乘以新进制的基数,把得到的整数部分作为新进制小数部分的最高位。
把上一步得的小数部分再乘以新进制的基数,把整数部分作为新进制小数部分的次高位;
继续上一步,直到小数部分变成零为止。
或者达到预定的精度要求或位数要求也可以。
3.二进制与八进制、十六进制的相互转换
二进制转换为八进制、十六进制:
它们之间满足23和24的关系,因此把要转换的二进制从低位到高位每3位或4位一组,高位不足时在有效位前面添“0”,然后把每组二进制数转换成八进制或十六进制即可。
八进制、十六进制转换为二进制时,把上面的过程逆过来即可。
也就是把一个八或十六进制位转换为3或4个二进制位。
例3:
N=(C1B)H=()B
(C1B)H=1100/0001/1011=()B
4.数制转换的一般化
(1)R进制转换成十进制
任意R进制数按权展开,相加即可得十进制数据。
例如:
N==1*23+1*22+0*21+1*20+0*2-1+1*2-2+0*2-3+1*2-4=8+4+0+1+0++0+=
N=5A.8H=5*161+A*160+8*16-1=80+10+=
(2)十进制转换R进制
十进制数转换成R进制数,须将整数部分和小数部分分别转换。
整数转换——除R取余法,规则:
1用R去除给定的十进制数的整数部分,取其余数作为转换后的R进制数据的整数部分最低位数字;
②再用R去除所得的商,取其余数作为转换后的R进制数据的高一位数字;
③重复执行②操作,直到商为0结束。
小数转换——乘R取整法,规则:
1用R去乘给定的十进制数的小数部分,取乘积的整数部分作为转换后R进制小数点后第一位数字;
②再用R去乘上一步乘积的小数部分,然后取新乘积的整数部分作为转换后R进制小数的低一位数字;
2重复②操作,一直到乘积为0,或已达到精度要求或位数要求为止。
解决数制转换问题时,如果所给的数值不是用十进制表示的,一般用一个字符型数组来存放。
数组的每个元素分别存储它的一位数字。
然后按位转换求和,得到十进制表示;再把十进制表示转换成所求的数制表示。
转换的结果也用一个字符型数组表示,每个元素表示转换结果的一位数字。
根据数制表示中相邻位的基数关系,可以把不同的数制分成两类。
一类数制表示中,相邻位的基数是等比关系,例如我们熟悉的十进制表示。
另一类数制表示中,相邻位的基数是不等比的。
例如在时间表示中,从秒到分采用60进进制;从月到年则采用12进制。
把一个数值从数制B的表示bmbm-1bm-2...b1转换成十进制表示dndn-1dn-2...d1比较简单。
假设数制B中,第i位的基数为basei(1<=i<=m),直接把basei与bi相乘,然后对全部乘积求和。
从十进制表示dndn-1dn-2...d1到bmbm-1bm-2...b1的转换需要分两种情况考虑:
数制B中相邻数字的基数是等比关系,即:
basei(1<=i<=m)可以表示成Ci-1,其中C是一个常量。
将dndn-1dn-2...d1除以C,余数即为b1;将dndn-1dn-2...d1和C相除的结果再除以C,余数即为b2;…;直至计算出为bm止。
数制B中相邻数字的基数不等比。
需要先判断dndn-1dn-2...d1在数制B中需要的位数m,然后从高位到低位依次计算bm、bm-1、bm-2、...、b1。
例5001特殊的四位数
(来源:
2405/2196)
问题描述:
找出并输出所有的4位数(十进制数)中具有如下属性的数:
四位数字之和等于其十六进制形式各位数字之和,也等于其十二进制形式各位数字之和。
例如:
十进制数2991,其四位数字之和2+9+9+1=21。
由于2991=1*1728+8*144+9*12+3,其十二进制形式为1893(12),其各位数字之和也为21。
但是它的十六进制形式为BAF(16),其各位数字之和等于11+10+15=36。
因此你的程序要舍去2991这个数据。
下一个数2992,其十进制、十二进制、十六进制形式各位数字之和均为22,因此2992符合要求,应该输出来。
(只考虑4位数,2992是第一个符合要求的数)
输入:
本题没有输入。
输出:
你的程序要求输出2992及其他更大的、满足要求的四位数(要求严格按升序输出),每个数占一行(前后都没有空行),整个输出以换行符结尾。
输出中没有空行。
输出中的前几行如输出样例所示。
输入样例:
本题没有输入。
输出样例:
2992
2993
2994
2995
2996
2997
2998
2999
...
解题分析:
该题在求解时要用到枚举的算法思想,即枚举所有的四位数(1000-9999),判断其是否满足十六进制、十二进制和十进制形式的各位数之和相等。
由于题目已经告诉你3000以内的所有满足条件的数,因此我们可以直接输出这些数,从3000开始枚举。
将一个十进制数N转换到B进制,其方法是:
将N除以B取余数,直到商为0为止,存储得到的余数,然后逆序输出余数即可得到B进制下的数,但由于此题只需要得到N在16、12和10进制下各位的和,所以不需要对余数逆序,直接累加其余数即可。
参考程序(zzg):
#include<>
#include<>
#include<>
intbase(intb,intn)
{
intsum=0;
while(n!
=0)
{
sum+=n%b;
n/=b;
}
returnsum;
}
intmain()
{
inti,a;
printf("2992\n2993\n2994\n2995\n2996\n2997\n2998\n2999\n");
for(i=3000;i<10000;i++)
{
a=base(12,i);
if(base(10,i)==a&&a==base(16,i))
{
printf("%d\n",i);
}
}
return0;
}
例5002进制转换
(来源:
2031)
问题描述:
输入一个十进制数N,将它转换成R进制数输出。
输入:
输入数据包含多个测试实例,每个测试实例包含两个整数N(32位整数)和R(2<=R<=16,R<>10)。
输出:
为每个测试实例输出转换后的数,每个输出占一行。
如果R大于10,则对应的数字规则参考16进制(比如,10用A表示,等等)。
输入样例:
72
2312
-43
输出样例:
111
1B
-11
解题分析:
这题就是考察十进制转换为其他进制的用法,由于需要转换的是整数,因此只需要把十进制整数除以R取余即可。
这里可以采用循环或递归来实现即可。
由于R不确定,因此我们可以编写个函数来实现十进制转换为R进制的功能。
参考程序(hxx):
#include<>
intTenToR(intnum,intr)
{
charm;
if(num==0)
return0;
TenToR(num/r,r);
m=(num%r>9num%r-10+'A':
num%r+'0');
printf("%c",m);
}
intmain()
{
intn,r;
while(scanf("%d%d",&n,&r)!
=EOF)
{
if(!
n)
printf("0");
elseif(n>0)
TenToR(n,r);
else
{
printf("-");
TenToR(-n,r);
}
printf("\n");
}
return0;
}
例5003skew数
(来源:
2973)
问题描述:
在skew二进制数表示中,第k位的值xk表示xk*(2k+1-1)。
每个位上的可能数字是0或1,最后面一个非零位可以是2,例如,10120(skew)=1*(25-1)+0*(24-1)+1*(23-1)+2*(22-1)+0*(21-1)=31+0+7+6+0=44.前十个skew数是0、1、2、10、11、12、20、100、101以及102。
输入:
输入包含一行或多行,每行包含一个整数n。
如果n=0表示输入结束,否则n是一个skew数。
输出:
对于每一个输入,输出它的十进制表示。
转换成十进制后,n不超过231-1=2147483647。
输入样例:
10120
0000000000000000000000
10
000000000000000000
11
100
0000
0
输出样例:
44
46
3
47
4
7
37
解题分析1:
由于n不超过231-1,因此可以直接用int类型来保存n,位权可以采用移位来实现。
参考程序1(hsl):
#include<>
#include<>
#include<>
intmain(){
charstr[1010];
while(scanf("%s",str)!
=EOF){
if(strcmp(str,"0")==0)break;
intl=strlen(str);
inti,j,ans=0,t1=1,t2;
for(i=l-1;i>=0;i--){
t1=t1<<1;
t2=t1-1;
ans+=(str[i]-'0')*t2;
}
printf("%d\n",ans);
}
return0;
}
解题分析2:
由于skew数位数比较多,超过了int的范围,因此我们只能采用字符数组的形式来接收输入。
这里,最大的skew二进制数对应到十进制数为231-1=47,对应的skew数为:
000000000000000000。
一共31位,因此采用长度为32的字符数组即可。
剩下的工作就是按位权展开求和就能得到想要的结果。
参考程序2:
#include<>
#include<>
#include<>
intmain()
{
charstr[32];//读入的每个skew二进制数
while(scanf("%s",str)!
=EOF)
{
intlen=strlen(str);
intnum=0;//对应的十进制数
if(len==1&&str[0]=='0')break;
intweight=2;//每位的权值为weight-1
inti;
for(i=len-1;i>=0;i--)
{
num+=(str[i]-'0')*(weight-1);
weight*=2;
}
printf("%d\n",num);
}
return0;
}
例5004周易
(来源:
2989)
问题描述:
有人说,中国古代的“周易”是二进制系统的起源,在该系统中,他们用“--”表示1,“---”表示0。
因此,二进制数字“011010”可以表述为“---\n--\n--\n---\n--\n---\n”(符号“\n”表示换行)。
现在的问题是如何把一个十进制数转换为“周易”中的二进制
输入:
文件中包含多组测试数据。
每个测试数据占一行,包括一十进制整数n(0<=n<=1000000)和表示二进制位数的k(0n=0,k=0表示输入结束。
输出:
对于每组测试数据,输出“周易”中对应的k行二进制数。
每组测试数据之间输出一个空行。
输入样例:
73
03
266
00
输出样例:
--
--
--
---
---
---
---
--
--
---
--
---
解题分析:
这题首先要把十进制数转换为二进制数,这个可以采用除2取余,再逆序输出即可。
其次就是如何输出k位,这里可能涉及到两种情况,一是k要大于实际二进制数的位数,那么前面需要用0来填补。
二是k小于实际的位数,那么需要在输出时控制只输出前k位(这里不会出现这种情况,因为题目中已经明确了n<2^k)。
由于k>0且k<=20,因此我们可以使用一个20位长的整数数组来存储转换后的二进制数,初始化时全部为0。
参考程序(hxx):
#include<>
#include<>
intmain()
{
inta[20];
intn,k;
inti;
while
(1)
{
scanf("%d%d",&n,&k);
if(n==0&&k==0)
break;
for(i=0;i<20;i++)
a[i]=0;
i=0;
while(n)
{
a[i++]=n%2;
n=n/2;
}
for(i=k-1;i>=0;i--)
{
if(a[i]==1)
printf("--\n");
else
printf("---\n");
}
printf("\n");
}
return0;
}
例5005奶牛计算器
(来源:
3191)
问题描述:
由于缺乏数学经验,奶牛想建立一个计算机器(它被称为Cowmpouter),使用二进制数字(基数为2),但它是建立在-2的基础上。
他们非常高兴,因为在-2进制表示的数字中不需要符号位。
你知道基数的权值都是从1开始的(0位),然后从右到左依次为基数1次方,基数2次方等等。
在-2进制中,其权值从右到左,依次为1,-2,4,-8,16,-32,…。
因此,从1计数依次是:
1,110,111,100,101,11010,11011,11000,11001等等。
很怪异的是,负数也那个用1和0表示,但没有符号位。
从-1向下计数依次为:
11,10,1101,1100,1111等等。
请帮助奶牛把普通的十进制整数(范围为:
-2,000,000,000到2,000,000,000)转换为-2进制对应的数。
输入:
输入只有一行,一个需要转换为-2进制的十进制整数。
输出:
对应的-2进制的数,没有前导0,0就表示0本身,只用1个0。
输入样例:
-13
输出样例:
110111
解题分析:
此题的解法基于以下几点:
(1)如果一个数是奇数,那么它的二进制形式的最后一位肯定是1,我们可以去掉此1,就是(x-1)/-2,进入
(2)。
(2)如果一个数的最后一位为0,我们可以把这个数右移(可以类比以2为基的二进制数的操作)一位,然后它的二进制的倒数第二个数就成了最后一个,就是x=x/-2,然后进入
(1)迭代,直到变为0。
参考程序(hxx):
#include<>
#include<>
intvalue;
charcache[100];
intcnt;
voidreverse()
{
inti;
chartmp;
for(i=0;i{
tmp=cache[cnt-i-1];
cache[cnt-i-1]=cache[i];
cache[i]=tmp;
}
}
intmain()
{
scanf("%d",&value);
if(value==0)
{
printf("0");
gotoend;
}
while(value!
=1)
{
if(abs(value)%2!
=0)
{
cache[cnt++]='1';
value=(value-1)/(-2);
}
else
{
cache[cnt++]='0';
value=value/(-2);
}
}
reverse();
cache[cnt]='\0';
printf("1%s",cache);
end:
;
return0;
}
例5006计算器设计
(来源:
1546/1334)
问题描述:
ReallyNeato计算器公司最近邀请你的团队为他们设计一款超级Neato一代计算器。
作为计算机科学家,你建议该计算器能够在各种进制之间进行转换。
他们认为这是一个很好的想法,并要求你的团队先给出实现进制转换的算法原型。
公司经理告诉你,该计算器应该具有以下一些特征:
(1)可以显示7位;
(2)按键除了数字0到9外,还包括大写字母A到F;
(3)支持2~16进制。
输入:
输入文件中的每行为一个进制转换,包括3个数,第1个数是原进制下的一个整数,第2个数就是原进制,第3个数是转换后的进制。
这3个数的两边可能有一个或多个空格。
输入数据一直到文件结尾。
输出:
实现所有的进制转换,转换后的数右对齐到7位显示。
如果转换后的数的位数太多,超过7位,则输出“ERROR”,也是右对齐到。
输入样例:
1111000210
1111000216
2102101310
2102101315
1231242
1A152
12345671016
ABCD1615
输出样例:
120
78
1765
7CA
ERROR
11001
12D687
D071
参考程序(zzg):
#include<>
#include<>
longb2ten(char*x,intb);
intmain()
{
charnumsrc[10],numdest[10];//用来存储读入的数和转换后的数
chartemp[10];
charerror[10]="ERROR";
longnum;
intsrc,dest;//转换前的进制和转换后的进制
inti,j;
//freopen("","r",stdin);
while(scanf("%s%d%d",numsrc,&src,&dest)!
=EOF)
{
//先把src进制的数转换为10进制数,存放到temp中
num=b2ten(numsrc,src);
if(dest==10)
{
if(num>9999999)
printf("%7s\n",error);
else
printf("%7d\n",num);
}
else
{
i=0;
while(num)