数制和编码
十进制数转成二进制
十进制转二进制,整数采用“整除取余,上右下左”,而小数部分则是“乘基取整,上左下右”,例子:
十进制的100转成二进制是:1100100
十进制的1.875转成二进制步骤如下:
1、整数部分是1,转成二进制是1
2、 小数部分是0.875
0.875 * 2 = 1.75 ... 取1
0.75 * 2 = 1.5 ... 取1
0.5 * 2 = 1.0 ... 取1
因此小数部分转成二进制是从上往下以此 0.111,故十进制的1.875转成二进制是1.111。
这就是大体的步骤,网上也有很多相似的博客,我就写得简单一点。
细心的同学可能会发现,假如小数最后一位不是5的小数转成二进制是无法准确表示的,比如1.3。其实,根本的原因是 1/(2^n)的最后一位必定是5,如1/8 = 0.125 1/32 = 0.03125 等等。
那么如果二进制数转成十进制呢?也很简单,就不写了
补码与转换
众所周知,整数都采用补码的形式存储(正整数原码补码一致),这里说下负数的补码表示:
如:十进制的-125,假设机器数是8位,则 125 = 127 - 2 = 1111 1101B 125的二进制表示
[-125]补码 = 2^8 - 1111 1101B = 1111 1111B - 1111 1101B +1B = 0000 0011B
0000 0011B 符号位置为1 即变成 1000 0011B,即为十进制-125的补码表示
那么如果知道补码,如何求真实值(即现实世界中的数值)呢?
很简单,例如(假设机器数是8位): 看符号位,最高位如果为1,则表示负数,则
1000 0011B的真实值 = -2^7 + 2^1+1 = -128 + 2 + 1 = -125
如果补码是0000 0011B呢?
0000 0011B的真实值 = 2+1 = 3
浮点数
任何实数都可以用一条公式来表示:
X = (-1)^S * M * R^E
R是基数(如2、8、10、16),M是一个二进制定点小数,称为X的尾数,E是二进制定点整数,称为指数或阶,S是符号位。只要确定S、M、E三个数,这样的X就称为浮点数。
一般来说,偏置常数的取值是 2^(n-1),或者是2^(n-1)-1 (n是机器位数),比如8位机器数,偏置常数就是2^7 = 128或者是127,而IEEE754标准规定单精度32位浮点数的偏置常数是127,双精度64位浮点数偏置常数是1023。
IEEE754标准规定单精度浮点数是由32位组成,其中包含1位符号位,8位移码(移码就是补码符号位取反,移码用来表示浮点数的阶),以及23位尾数。(M表示小数部分,计算真值的时候需要记得加上隐含的1)
机器数转真值
具体用一个例子来说明: 如:浮点数的机器值的16进制表示为BEE00000H,则求它的真是值
BEE00000H = 1011 1110 1110 0000 0000 0000 0000 0000B
则套用公式 X = (-1)^S * M * R^E R是基数2
S是首位 1 移码是除了首位后面取8位,也就是 01111101,这是E的值, 01111101B = 125(十进制),所以 浮点数的指数 = 125 - 127(偏置常数)= -2 所以指数的值是-2 M是剩下的 110 0000 0000 0000 0000 0000 = 1 * 2^-1 + 1 * 2^-2 = 0.75,别忘了隐含的1,所以M的值是1+0.75 = 1.75,因此
X的真值 = (-1)^1 * 1.75 * 2^-2 = -0.4375
反之如何求值?真值如何求机器数?
例如:
-0.4375转成二进制得:-0.0111 = -1.11 * 2^(-2) (转成标准格式)
负数因此 S是1
指数为-2,则移码为 127(偏置常数)+(-2) = 125,二进制表示为 01111101,即为E的值
M值为小数部分,所以是 11(省略了前面的1,这个1是隐含的),在补上剩下的21个0即可,
也即:1 01111101 11000000000000000000000
数值比较?
C语言中,若同时出现无符号数和带符号数,则C编译器会将带符号数转成无符号数再进行比较。 如:
-1 < 0 带符号数比较,结果为true
-1 < 0U 转成无符号数比较 -1的二进制表示为
11...1(n个1),转成无符号数之后,就变成2^n - 1的值了,因此比0大,所以结果为false
又如:
2147483647 > (int)2147483648U 结果是false
因为2147483648 转成带符号数比较,2147483648等于2^31,由于最高位是1,所以最终被转成 -2147483648 与 2147483647 比较,因此结果为false
另外,需要注意的是对于计算机 ISO C90 与ISO C99的表示数值方式有点区别:
在C90 的机器中, 0 - 2^31-1 为int类型 与C99一致 然而,2^31 - 2^32 -1 区间的值会被转成unsigned int 无符号数,因此在C90的机器中,会出现
-2147483648 < 2147483647 结果为false
因为-2147483648会被转成无符号数(32位无符号数区间为0到4294967295),而-2147483648的二进制表示为 100...0(共31个0),因此转成无符号数的十进制值是2147483648,是正数,比2147483647大 ,因此结果为false.
结语:纯一字字敲出来,如果有误,欢迎各位斧正!