嗨玩手游网

用C语言实现BCD解密,明白十进制、二进制、十六进制的转换过程

今天这道题目呢,与前天讲的“龟兔赛跑”都是从PAT的基础编程题目中节选过来的。

难度不是很大,但是特别基础,复习到了基础知识,也就是二进制、十进制两者之间的相互转换。

我们先来看看这道题目的要求:

BCD数是用一个字节来表达两位十进制的数,每四个比特表示一位。

所以,如果一个BCD数的十六进制为0x12,那么它的十进制也是12。

此时有一位小伙伴并不知道BCD数的运算规则,直接把0x12当作二进制来转换成十进制,那就会得到18。

现在呢,我们就期望能把这个错误得到的十进制,转换成我们期望得到的十进制数值。

给定的这个错误十进制范围为[0,153]。

题目要求呢我们都清楚了,接下来就是如何解决这个问题。

这里呢,主要涉及到的是十六进制和十进制之间以及二进制和十进制之间的转换。

但我呢,好像把这道题目给想复杂了emm,结果导致简单问题复杂化,实在是不应该啊。

理清逻辑,画出流程图,这是十进制转换为二进制再进行BCD解密

程序要写正确的话,流程图用来帮助理清逻辑非常好用,这张流程图画的有些小,真的有些不好意思。

可以从这张流程图中看出来,我的逻辑就是:

把该同学输入的整数先转换为二进制数,比方说给定的十进制数为18。

那么转换成的二进制数则为00010010。

之后再把二进制数转换为十六进制的形式则为0001和0010。

之后分别转换为十进制得到1和2。

然后求和1*10+2*1=12,最终得到结果。

我的代码部分:

注意,这里我用到了一个pow函数,这是一个求幂次方的函数,在用这个函数的时候,需要调用库#include<math.h>。

#include<stdio.h>#include<math.h>int main(){ int number = 0;//初始化定义需要输入的十进制数 int store[8] = {0}; int mod = 0; int mild1 = 0;//求和 int mild2 = 0;//求和 scanf("%d", &number); for(int i = 0; i < 8; i++){ mod = number%2; number = number/2; store[i] = mod; } for(int i = 7; i >= 4; i--){ if(store[i]==1){ mild1 = mild1+pow(2,i-4); } } for(int i = 3; i >= 0; i--){ if(store[i]==1){ mild2 = mild2+pow(2,i); } } printf("%d", mild1*10+mild2); printf("\n");}测试结果:

提交PAT测试结果:

但是呢,我在思考,这道题目有没有更快的方法了。

毕竟这样从二进制开始写,十进制转化为二进制,然后再转化为十六进制,然后分开二进制转化为十进制的确麻烦了些。

于是,我再来认真地读了一遍这道题。

读来读去,只发现这道题是只需要我们直接把十进制转化为十六进制即可!然后再直接计算不就行了么。

BCD太迷惑人了!

十进制转化为十六进制的流程:

给定一个数18,18除以16等于1取余数得到2,再把1除以16等于0取余数得到1。

1和2组合起来,不也能得到最终结果吗?

流程图,这是十进制转换为十六进制再进行BCD解密

我的代码部分

#include<stdio.h>int main(){ int number = 0;//初始化定义需要输入的十进制数 int store[8]; int mod = 0; scanf("%d", &number); for(int i = 0; i < 8; i++){ mod = number%16; number = number/16; store[i] = mod; } printf("%d",store[1]*10+store[0]);}测试结果

提交PAT测试结果

总结

在做这道题目的时候,我遇到了很多很多问题。

比方说逆序输出的时候,我直接把1和2按照顺序打出,但这样的话就会产生问题,最小值该如何判断。

还有要用到pow函数,这个可不能忘了。

总的来说,这道题呢,关键还是考我们对十进制、二进制和十六进制之间的转换是否熟悉。

如果很熟悉的话,这道题目直接十进制与十六进制转换一下就做出来了。

没必要像我最开始写的那样兜一个大圈子。

码制——BCD码(详细,通俗易懂)

太多事情要忙,都好久没更新了,废话不多说开始吧!!!!

阅读本文所需知识:进制数转换及运算。

图片来源于网络

BCD码的概念

百度定义:BCD码(Binary-Coded Decimal‎)亦称二进制十进制或二-十进制代码。用4位二进制数来度表示1位十进制数从16位组合中取出的0~9这10个数码。

例如:十进制28用BCD码表示(0010 1000) ps:0010(2)1000(8)概念一目了然

它的作用是什么?

BCD码是二进制和十进制相互转换编码,这使二进制与十进制的转换更加便捷,同时保存数值的精确度,避免电脑作浮点运算所耗的时间。

因为计算机中数据都是用二进制进行存储,所以二进制和十进制需要相互转换,它们转换是比较麻烦的,然而BCD码正好解决了这个问题。BCD码把十进制每一位用4位二进制来表示。上面那个例子就是证明。

BCD码分类压缩码和非压缩码

压 缩 码:用4位二进制数来表示一位十进制数(例如:2(0010))

非压缩码:用8位二进制数来表示1位十进制数(例如:2(0000 00010))

那么问题来了,为什么不直接使用压缩码? 高效又节省空间。

ps:因为一个字节是8位,而且每个数据所表示的长度不同。

有权码和无权码

有权码:8421码、2421码、5421码

无权码:余三码、余三循环码、格雷码

图片来源于网络

有权码

8421码

8421码是BCD码最常用的编码方式,也被称为BCD码。

位权如名:8、4、2、1 (表示范围:0~9(0000~1001),禁用码:10~16(1010~1111)

例如:543D = 0101 0100 0011B (ps:D表示十进制数;B表示二进制数)

8421码对应ASICC码的第四位相同,这特点有利于简化输入输出过程中BCD码和字符代码的转换。

2421码(自补特性)加权码

位权:2、4、2、1

例如:642D=1100 0100 0010B

问题来了,仔细观察位权里有两个2,这样就会重复问题,比如说:0101和1011都对应5。

所以做出规定:0101~1010不许用

禁用码:0101、0110、0111、1000、1001、1010

2421码是对9的自补代码(自补性)

即每一个2421码只要与自身按位取反,便可得到该数9的补数的2421码。

例如:0100(4)即各位取反后正好为该数9的补码1011(5)。

而0101取反后1010对应十进制10显然不满足自补码的要求。

好处:给运算带来方便,因为可以利用其对9的补数将减法运算转变为加法运算

(0000)和(1111)、 (0001)和(1110)、 (0010)和(1101)、 (0011)和

(1100)、 (0100)和(1011)互为反码,仔细观察它们具有反射特性

做加法是若两个数之和为10正好等于二进制的16(0001+1111=16),于是便能高位自动产生进位信号。

5421

位权:5、4、2、1

注意位权不同表示的数也不同,看上面的例子相信你们也能理解了。

禁止码:0101、0110、0111、1101、1110、1111

5421码同样也有2421码的自补性。

真值表

无权码余三码

余三码是在8421码基础上+0011(3)(比如:8421码0+0011(3)=0011)

表示范围:3~12(0011~1100)

禁 用 码 :0~2(0000~0010)、13~16(1101~1111)

那么它的作用及特点是什么?

余三码同样也有对9的自补性,0和9, 1和8,…..5和4的余3码互为反码,这在求对于10的补码很方便。

两个余3码表示的十进制数相加时,能产生正确的进位信号,但对“和”必须修正。

修正方式:如果有进位信号则结果+0011(3),如果没有进位信号则结果减0011(3)

例如:

有进位需修正 所以结果0010+ 0011(余三码3)= 2(转换十进制) 2+上进位10=12(结果正确)

ps:当两个十进制数的和是10时,相应的二进制编码正好是16,于是可自动产生进位信号,而不需修正,余3码常用在BCD码运算电路中。

不懂的看下面的真值表对应,理解格雷码再理解余三循环码。

格雷码

8421>>>格雷码

推理方式:异或法(相同为0,相异为1)如图

特点:任何两个相邻的码字仅有一位不同(不懂看真值表)

作用:虽然自然二进制码可以直接由数/模转换器转换成模拟信号,但在某些情况,例如从十进制的3转换为4时二进制码的每一位都要变,使数字电路产生很大的尖峰电流脉冲。但是如果只有一个触发器发生改变的话,那么这些模糊状态就不会出现。

比如:数字7(0111)转8(1000),二进制要每一位都要改变,而格雷码的话只需要改变一位7(0100)转8(1100)。

格雷码是一种具有反射特性和循环的单补自补代码,可靠性编码,使错误最小化的编码方式

循环和单步特性消除了随机取数时出现重大错误的可能。

反射和自补特性使得对其进行求反操作也非常方方便。

仔细观察格雷码的编码方式,查看其最大数码和最小数码,它们两者仍然具有“两个码字中仅有一位代码不同”的特点,那么也可以认为它们也是相邻的,因此,格雷码也称为循环码。(变权码)

仔细观察16个4位格雷码

从上往下依次读出格雷码的最后一位:0110 0110 0110 0110;

再从上往下依次读出格雷码的倒数第二位:0011 1100 0011 1100;

再从上往下依次读出格雷码的正数第二位:0000 1111 1111 0000;

看出规律了吗?它这种特性称为“反射特性”

Ps:数据(0、1)在计算机中都是由存储器进行存储又被称为寄存器,寄存器一般情况下触发器来存储,一个触发器只能存储一个二进制数(0和1),也就是说如果需要存储四位格雷码就需要四个触发器进行存储。

余三循环码(变权码)

8421码>>格雷码>>>余3循环码(余3码基础上)

取自4位典型格雷码的3~12这10个代码(即0~9的余3循环码0010~1010),此乃“余3”之意

仍具有格雷码的优点:两个相邻的代码只有一位码元改变(大大减低错误的概率)。

注意:同一个8位二进制代码表示的数,当认为它表示的是二进制数和认为它表示的是二进制编码的十进制数时,数值是不相同的。

例如:00011000,当把它视为二进制数时,其值为24;但作为2位BCD码时, 其值为18。

BCD码与二进制之间的转换不是直接进行的, 当需要将BCD码转换成二进制码时,要先将BCD码转换成十进制码,然后再转换成二进制码; 当需要将二进制转换成BCD码时,要先将二进制转换成十进制码,然后再转换成BCD码。

如果有错误的地方望指出,一起交流学习讨论。