1、Jsoi2008 春季函授(B1)- 1 -进制转换及应用常州市第一中学 林厚从一、引言计算机的一个重要理论基础就是二进制思想。任何信息最终都是以二进制数的形式存储在计算机中的,在计算机中有时还用到十六进制和八进制。所以,在实际应用中,经常需要将一个十进制数转换成二进制、八进制或十六进制的数,有时又需逆向转换,将二进制、八进制或十六进制的数转换成十进制数,有时还需要在二进制、八进制和十六进制数之间进行相互转换(2,8,10,16 等一般称为“基” ) 。不同进制数之间转换的基本算法是:(1) 十进制整数转换成 n 进制数的方法:将十进制整数不断除以 n 取余,最后反序输出即可。(2) n 进制
2、数(整数、实数都可以)转换成十进制数方法:按“权 n”展开,即表示成若干项形如 ai*ni的累加和即可。(3) 二进制、八进制、十六进制之间的转换方法:利用 3 位二进制表示 1 位八进制数,4 位二进制数表示 1 位十六进制数的基本思想,3 位一段(或 4 位一段)分别转换即可。注:一般 2n16,十进制以上、十六进制以下的数制除了 09 十个字符外,还用到A、B、C、D、E、F 几个字符,分别表示 1015。对于十进制,我们称它的基数为 10,而二进制的基数就是 2,十六进制的基数就是 16。对于十进制数 1234.56,我们可以表示成1*103+2*102+3*101+4*100+5*1
3、0-1+6*10-2,我们把 10i称之为十进制各个位的 “权” 。对于二进制数11001.01001,我们也可以类似地表示成 1*24+1*23+1*20+1*2-2+1*2-5,即二进制各个位的权为 2i。这一方法(按权展开)同样可以用在任意 n 进制中。二、不同进制数之间的相互转换1、十进制正整数转换成任意 n 进制数方法介绍就是模拟小学学过的除法运算,比如要把十进制整数 39 转换成二进制数,则转换方法如下左图,即不断除以 2,直到商为 0,再倒序输出即可,结果一般表示为(39) 10 =(100111) 2 。而要把十进制整数 245 转换成八进制数,方法一样,只要不断地除以 8 即
4、可,如下右图所示,结果可以表示为:(245) 10 = (365) 8。一定要注意的是“倒序输出” 。图 1 十进制整数转换成 n 进制方法示意图算法描述设十进制数为,要转换成 n 进制,用数组 a 存放最后的转换结果,i 为数组下标,则算法描述如下: i:=0;重复做:Jsoi2008 春季函授(B1)- 2 -i:i1;ai:= mod n:= div n直到为止。依次输出最高位 ai到最低位 a1。参考程序 将十进制整数 Y 转换成任意 n 进制数(设 n n then 判断输入的数是否合法beginwriteln(input error! );exit;end;weight:=weig
5、ht*n; 累乘计算出每一位的权total:=total+ai*weight; 按权展开每一位,累加求和end;writeln(total,)10);readlnend.程序样例输入:2100110输出:(100110)2=(38)10思考练习如果 n 超过了十进制,则程序怎么修改呢? 这个方法也适用于把任意 n 进制小数转换成十进制小数,方法基本一样。因此,我们对一个 n 进制的实数,就可以把整数和小数部分截取出来后,分别进行转换,最后再加起来输出即可。请大家完成。3、将十进制小数转换为其它进制的小数方法介绍将十进制小数转换为其它进制的数,其基本算法是:将小数乘以待转换的进制数,正向取整。例
6、如Jsoi2008 春季函授(B1)- 4 -把(0.325) 10转换成二进制小数的过程如下图 2 所示: 图 2 十进制小数转换成其它进制小数方法示意图所以,运算结果是:(0.325) 10 (0. 0101) 2大家发现,这种转换有时是一个近似值。思考:为什么?参考程序程序请大家完成。对于一个十进制的实数,我们就可以把整数和小数分解出来,分别转换成其它进制的整数和小数,最后再加起来输出结果。4、二进制和十六进制之间的转换如要把二进制数(1111011001.01111) 2转换成十六进制数,则我们以小数点为准,向前 4 位一段转换整数部分,不足则高位补 0;再向后 4 位一段转换小数部分
7、,不足则低位补 0。如下图,最后相加输出即可得到答案:(3D9.78) 16。图 3 二进制数转换成十六进制数的方法示意图反之也一样,如要把十六进制数(A1F5.2) 16二进制数,则结果为(1010 0001 1111 0101.0010)2。注意:一定要补齐 4 位,为什么?参考程序程序请大家完成。三、进制转换原理的应用在有些实际问题中,巧妙地应用“进制转换”思想,可以起到很好的效果,下面举例说明。例 1、用质量为 1,3,9,27 和 81 的五种砝码各 1 个(假如单位为克)称物体的质量,最大可称 121,在实验室我们一般要求“物左砝右” 。如果砝码允许放在天平的两边,编程输出称不同质
8、量(1121)物Jsoi2008 春季函授(B1)- 5 -体时,砝码应该怎样安排?例如要称一个 m=14 克的物体,我们知道 14=27-9-3-1,即 14+9+3+1=27。所以我们可以把天平一端放置该和 9、3、1 的砝码,而另一端放 27 的砝码,这样即可称出。问题分析被称物体的质量计算的数学原理:设被称物体 m 放在天平左边,根据天平平衡原理,左边质量应等于右边质量。问题关键在于算法中如何体现砝码放在天平左边、右边或没有参加称量。这里可以用-1、1、0 表示砝码放在天平左、右和没有参加称量,再没有其它数,所以称为三进制数,每个砝码都有这样的三种状态。被称物体质量计算为: = a*8
9、1 + b*27 + c*9 + d*3 + e。这里 a,b,c,d,e 分别表示 81,27,9,3,1 克的砝码是放在天平的左边、右边或是没用。参考程序Program ex3(input,output);var a,b,c,d,e,m:integer;Beginfor m:=1 to 121 dofor a:= 0 to 1 dofor b:= -1 to 1 dofor c:= -1 to 1 dofor d:= -1 to 1 dofor e:= -1 to 1 doif m = a*81+b*27+c*9+d*3+e thenbeginwrite(m,=,a*81);if bi d
10、obeginbi:=0;bi+1:=bi+1+1;i:=i+1endend;writelnend.程序样例输入:4输出:1 2 3 4 1 2 4 3 1 3 2 4 1 3 4 2 1 4 2 3 1 4 3 2 2 1 3 4 2 1 4 3 2 3 1 4 2 3 4 1 Jsoi2008 春季函授(B1)- 9 -2 4 1 3 2 4 3 1 3 1 2 4 3 1 4 2 3 2 1 4 3 2 4 1 3 4 1 2 3 4 2 1 4 1 2 3 4 1 3 2 4 2 1 3 4 2 3 1 4 3 1 2 4 3 2 1 例4、已知x的值和系数a 0,a 1,an,计算y=
11、a nxn+an-1xn-1+an-2xn-2+a1x+a0的值。问题分析该问题看似很容易。其实随着n越大,计算量也越大,乘积和累加的次数也愈多,这里的n就是“问题的规模” 。在此,我们想通过这个例子说明一些“算法复杂度”的问题,同时使大家认识到:一些看似简单的问题,其实是可以做很多优化的。 算法设计算法1:y=a0;for k:=1 to n do begins:=ak;for j:=1 to k do s:=s*x y:=y+s;end;writeln (y=,y );该运算中用到的存储单元有a0,a1, ,an,以及固定的几个简单变量,所以其空间复杂性与规模n成正比,即为O(n) 。而时
12、间复杂性是内循环乘法计算和外循环的累加计算,计算y共用乘法次数是:1+2+3+n=n(n+1)/2, 加法仅n次,而在计算机内部实现乘法要比加法花费更多的时间,所以该算法的时间复杂性为O(n(n+1)/2)O(n*n/2)O(n2) 。算法2:算法1中的乘法运算有重复计算:x k不需要每次从1,x, x 2,x 3, , xk乘法去实现,只要在原先x k-1基础上再做一次乘法就可以得到x k 的结果,多用一个b数组存放1,x, x 2,x 3, , xn,该问题的空间复杂性为O(2n)O(n)。b0:=1;for k:=1 to n do bk:= nk-1*x;y:=a0;for k:=1
13、to n do y:=y+ak*bk;writeln(y=,y);此算法用了两次单循环命令,共用了2n次乘法和n次加法,时间复杂性为O(2n)O(n)。算法3:利用我国古代数学家秦九邵提出的一个公式(秦九邵公式) ,将y 的计算公式改写为:y=(an*x+an-1)*x+an-2) +a1)*x+a0 a0,a1,an存放系数,x为初始数据,则其程序为:y:=an;for k:=n-1 downto 0 do y:=y*x+ak;writeln(y=,y);该算法所用的存储空间为n个单元,即空间复杂性为O(n) ,而只用了n次乘法和n次加法,所以时间Jsoi2008 春季函授(B1)- 10
14、-复杂性为O(n) 。由此,我们可以看到,在以上 3 个求多项式值的算法中,算法 3 可以获得最好效果。四、作业(只要交源程序)1、N 进制乘法口诀表(table.pas,table.in,table.out)从 table.in 中读入一个自然数 N(2N16) ,打印出 N 进制乘法口诀表,输出到 table.out 中。请注意格式(大写字母、右对齐,除了最左列外,每个数据项占 4 列) ,以下是 N=16 时的结果:* 0 1 2 3 4 5 6 7 8 9 A B C D E F0 01 0 12 0 2 43 0 3 6 94 0 4 8 C 105 0 5 A F 14 196 0
15、 6 C 12 18 1E 247 0 7 E 15 1C 23 2A 318 0 8 10 18 20 28 30 38 409 0 9 12 1B 24 2D 36 3F 48 51A 0 A 14 1E 28 32 3C 46 50 5A 64B 0 B 16 21 2C 37 42 4D 58 63 6E 79C 0 C 18 24 30 3C 48 54 60 6C 78 84 90D 0 D 1A 27 34 41 4E 5B 68 75 82 8F 9C A9E 0 E 1C 2A 38 46 54 62 70 7E 8C 9A A8 B6 C4F 0 F 1E 2D 3C 4B
16、 5A 69 78 87 96 A5 B4 C3 D2 E12、波浪数(num.pas,num.in,num.out)波浪数是在一对数字之间交替转换的数,如 1212121,双重波浪数则是指在两种进制下都是波浪数的数,如十进制数 191919 是一个十进制下的波浪数,它对应的十一进制数 121212 也是一个波浪数,所以十进制数 191919 是一个双重波浪数。类似的可以定义三重波浪数,三重波浪数在三种不同的进制中都是波浪数,甚至还有四重波浪数,如十进制 300=606(七进制)=363(九进制)=454(八进制)=1A1(十三进制) 。你的任务就是在指定范围内找出双重、三重、四重波浪数。输入
17、格式:输入文件 num.in 中仅包含一行,包含五个用空格隔开的十进制整数,前两个数表示进制的范围(232) ,第三与第四个数表示指定的范围(11000000) ,第五个数为 2,3,4 中的一个,表示要找的波浪数的重数。输出格式:输出文件 num.out 包括若干行,每行一个数,从小到大,以十进制形式输出指定范围内的指定重数的波浪数。样例输入:10 11 190000 960000 2Jsoi2008 春季函授(B1)- 11 -样例输出:191919383838575757767676959595作业说明:1、请在 3 月 31 日之前提交作业,否则按“未交”处理;2、本次作业只要交两个编程题的源程序,请严格按照题目规定的程序名、输入输出文件名、输入输出格式要求做,只要交源程序即可。3、提交作业时,要把自己的两个源程序放在一个文件夹里(文件夹的名字为“层次+市+学生姓名” ) ,压缩成一个压缩文件后通过 JSOI 网站上的“上传作业”提交。如常州市正衡中学的邹晨同学,提交的压缩文件应该是:B 常州邹晨.rar,解压后得到的文件夹应该是“B 常州邹晨” ,里面有 num.pas 和table.pas 两个文件。4、作业要独立完成,一旦发现雷同,则雷同的人全部按 0 分处理。可以在JSOI 论坛上讨论、交流,方法思路一样没什么,但程序必须要自己独立完成。