嵌入式C语言教程(9)---整数数字表示
时间:2010-05-21 来源:bluedrum
首先某个基本类型占用宽度是确定的.在32 位CPU下,unsigned char /char占一个字节,unsigned int /int 占四个字节,unsigned long /long 也是占用四个字节.
因为数字编码是二进制表示的.(0,1),某一个类型的数就是内存中以二进制来表示.
我们正整数为例,以unsigned char 型的数18为例.
18 (10) =00010010 (2)
在内存即用上述00010010表示
这种按原始的二进制表示称为原码。是无符号整数(即正整数主要表达方法),这样unsigned char 能表示最大数字是 256(即的2的8次方),2个byte的unsigned short最大值是 65,536.4个byte的unsigned int 最大值是4,294,967,296.2.负整数的表示 对于负整数的表示,即对于有符号数数据类型,如int,long,short,char等.最高位用于表示符号位.符号位上为0表正数,1表示负数. 2.1 原码表示法 因此,负数的表示,最容易想到最高位置1,剩下的用原码来表示。,这称为原码表示法.因为少一位,所以可表达的数值,比有符号位要少一半。
在数值前直接加一符号位的表示法
l [+7]原= 0 0000111 B
l [-7]原= 1 0000111 B
– 0就有两个表达方法
l [+0]原=00000000B [-0]原=10000000B
– 8位二进制原码的表示范围:-127~+127
这种方法直观易懂,又好理解。但是最大问题出在硬件加法器的设计上。为了硬件设计简单,在硬件加法器不管符号位,整体做位运算的。
l 带符号位的原码进行乘除运算时结果正确,而在加减运算的时候就出现了问题 .
– 正确结果
– 1 (10)- 1 (10) = 1 (10) + ( -1 )(10) = 0 (10)
– 用原码运算的结果
– (00000001)原 + (10000001)原 = (10000010)原 = ( -2 ) 显然不正确.
2.2 反码表示法
l 为解决原码的运算错误,人们提出了反码表示法
– 正数:正数的反码与原码相同。
– 负数:负数的反码,符号位为“1”,数值部分按位取反。
– 反码表示例子
l [+7]反= 0 0000111 B
l [-7] 反= 1 1111000 B
– 0也有两种反码表示
l [+0]反=00000000B
l [- 0]反=11111111B
– 8位二进制反码的表示范围:-127~+127
反码表示法的缺点
l 反码运算例子1
– 1(10) - 1(10)= 1(10) + (-1)(10)= ( 0 )(10)
– (00000001) 反+ (11111110)反 = (11111111)反 = ( -0 ) 有问题.
l 反码运算例子2
– 1(10) - 2(10) = 1(10) + ( -2 ) (10) = (-1) (10)
– (00000001) 反+ (11111101)反 = (11111110)反 = ( -1 ) 正确
问题出现在(+0)和(-0)上,在人们的计算概念中零是没有正负之分的 .
2。3 补码表示法
l 为了解决上述问题,人们最终采用补码表示法
– 正数:正数的补码和原码相同。
– 负数的补码则是符号位为“1”,数值部分按位取反后再在末位(最低位)加1。也就是“反码+1”。
– 例子
l [+7]补= 0 0000111 B
l [-7]补= 1 1111001 B
– 在补码中用(-128)代替了(-0),所以补码的表示范围为:(-128~0~127)共256个.
l (-128)没有相对应的原码和反码, (-128) = (10000000)
l 已知原码,求补码。
– 问:已知某数X的原码为10110100B,试求X的补码和反码。
– 解:由[X]原=10110100B知,X为负数。求其反码时,符号位不变,数值部分按位求反;求其补码时,再在其反码的末位加1。
– 故:[X]补=11001100B,[X]反=11001011B。
–
l 已知补码,求原码。
– 问:已知某数X的补码11101110B,试求其原码。
– 解:由[X]补=11101110B知,X为负数。求其原码表示时,符号位不变,数值部分按位求反,再在末位加1。
3.常见补码的求值
3.1 0取反的值是多少?
printf("%d",~0);
0取反.即全1.是一个负数.将其当成补码,减去1后再取反,得到1.上述打印值是-1
3.2 -1 取反的值是多少?
printf("%d",~(-1));
-1的补码是 全1.取反后是0.因此其取反是输出是0
3.3 问:printf(“%d”,~2)输出?
– ~是表示位取反,%d表示按有符号输出即这个数的每一位都由0变1,1变0,本题问的2取反后,新的有符号数的值是什么?
l 解:2是正数 ,采用原码表示10B,%
4.BCD码 4.1 BCD码定义 BCD全称Binary-Coded Decimal.与二进制位串不同,这种编码方式.是把每一个十进制数不考虑进位关系,每一个数字都折分成一个4位的二进制数.这种转换关系非常简单实用. 为什么用4位呢,因为0-9的10个数字必须要4位二进制位足够表达.但是4位二进制能表示16个数字.因此在BCD还因为如何从16个数字选择10个数字,还细分多种表示方法. 4位二进制数码有16种组合,原则上可任选其中的10种作为代码,分别代表十进制中的0,1,2,3,4,5,6,7,8,9 这十个数字。如何选择10个数字,BCD细分为多种编码, 最常用的BCD码称为8421码.即用就是使用"0"至"9"这十个数值的二进码来表示.8.4.2.1 分别是4位二进数的位取值. 即有如下对应关系. 0=00001=0001
2=0010
3=0011
4=0100
5=0101
6=0110
7=0111
8=1000
9=1001 常见BCD编码有 除了8421.还有5421码 2421码 余3码 余3循环码.它们跟数字对应关系有 4.2 BCD码与十进制转换关系 BCD码与十进制数的转换.关系直观,相互转换也很简单.直接将对位数字换成对应BCD编码即可. 3 2 1(10) = 0011 0010 0001 (bcd) BCD还能表示小数,它一般用指定位宽来规定小数.以小数位为2位来算. 75.4= 0111 0101.0100 0000 85 = 1000 0101.0000 0000 这种称为定点小数,既可保存数值的精确度,又可免却使电脑作浮点运算时所耗费的时间。缺点就是不能表示过大或过小的数字. 注意一个同一个unsigned char 中00011000,当把它视为二进制数时,其值为24;但作为2位BCD码时, 其值为18。 完全看是如何理解的. 4.3 压缩BCD码和非压缩BCD码 一个ASCII码占8bit,其中'0'~'9'的值低4位正好跟8421码相等。有,时为了处理方法,还有一种用8bit表示BCD数字,其高4位总为0.这种编码称为非压缩BCD码(Unpacked BCD),而用4bit表示的BCD称为压缩BCD吗(packed BCD)
Decimal | Binary | BCD | |
---|---|---|---|
Unpacked | Packed | ||
0 | 0000 0000 | 0000 0000 | 0000 0000 |
1 | 0000 0001 | 0000 0001 | 0000 0001 |
2 | 0000 0010 | 0000 0010 | 0000 0010 |
3 | 0000 0011 | 0000 0011 | 0000 0011 |
4 | 0000 0100 | 0000 0100 | 0000 0100 |
5 | 0000 0101 | 0000 0101 | 0000 0101 |
6 | 0000 0110 | 0000 0110 | 0000 0110 |
7 | 0000 0111 | 0000 0111 | 0000 0111 |
8 | 0000 1000 | 0000 1000 | 0000 1000 |
9 | 0000 1001 | 0000 1001 | 0000 1001 |
10 | 0000 1010 | 0000 0001 0000 0000 | 0001 0000 |
11 | 0000 1011 | 0000 0001 0000 0001 | 0001 0001 |
12 | 0000 1100 | 0000 0001 0000 0010 | 0001 0010 |
13 | 0000 1101 | 0000 0001 0000 0011 | 0001 0011 |
14 | 0000 1110 | 0000 0001 0000 0100 | 0001 0100 |
15 | 0000 1111 | 0000 0001 0000 0101 | 0001 0101 |
16 | 0001 0000 | 0000 0001 0000 0110 | 0001 0110 |
17 | 0001 0001 | 0000 0001 0000 0111 | 0001 0111 |
18 | 0001 0010 | 0000 0001 0000 1000 | 0001 1000 |
19 | 0001 0011 | 0000 0001 0000 1001 | 0001 1001 |
20 | 0001 0100 | 0000 0010 0000 0000 | 0010 0000 |
解决的办法是对二进制加法运算的结果采用"加6修正,这种修正称为BCD调整。即将二进制加法运算的结果修正为BCD码加法运算的结果,两个两位BCD数相加时,对二进制加法运算结果采用修正规则进行修正。 修正规则:
(1)如果任何两个对应位BCD数相加的结果向高一位无进位,若得到的结果小于或等于9,则该不需修正;若得到的结果大于9且小于16时,该位进行加6修正。
(2)如果任何两个对应位BCD数相加的结果向高一位有进位时(即结果大于或等于16),该位进行加6修正.
(3)低位修正结果使高位大于9时,高位进行加6修正。
下面通过例题验证上述规则的正确性。
用BCD码求35+21 BCD码求25+37 用BCD码求38+49 用BCD码求42+95
用BCD码求91+83 用BCD码求94+7 用BCD码求76+45 关于BCD码,参见如下文章了解更多。http://academic.evergreen.edu/projects/biophysics/technotes/program/bcd.htm 练习 1.printf("%d",(unsigned int)~2); 输出结果 2.写一个ASCII数字串转换成非压缩BCD码的转换算法 void BcdToAscii (char *ascii_buf, const BYTE *bcd_buf, int len)
{
int i;
char ch;
for (i=0; i<len; i++)
{
if (i & 1) ch = *(bcd_buf++) & 0x0f;
else ch = *bcd_buf >> 4;
ascii_buf[i] = ch + ((ch > 9)? ''A''-10 : ''0'');
}
}