深入理解计算机系统--整形、浮点数

基础

 

信息在计算机中都是以0、1来表示的,这一点不用赘述。

 

bit:每一个表示0、1的内存位,叫做bit(位)。

 

byte:现代计算机大多用8位的内存块作为最小可寻址内存单位,叫做byte(字节)

 

 

十六进制表示法:

一般认为,以0X开头的数字常量是十六进制的值。进制对应关系如下:

 

 

数据寻址/字节顺序

 

虚拟内存:计算机程序会将内存视为一个非常大的连续的byte数组,这个byte数组就是虚拟内存。

数组里每一个byte都有一个唯一数字来标识,这个数字就是内存地址。

 

现实中,很多信息、变量都是大于一个byte的,无法用一个单纯的内存地址来表示。

因此,首先需要一个内存地址,在加上对应数据类型的偏移量,这样就可以明确这个信息对应的内存区域了。

 

然后还需要一个规定的存储顺序。最高有效位 -> 最低有效位 这种称为大端法,最低有效位 -> 最高有效位这种称为小端法。

 

举例:

 

十进制:2190,二进制:00001000 10001110,16进制:0x088e

这个如果用大端法表示,那就是 00001000 10001110;

如果用小端法表示,那就是 10001110 00001000

目前大多数操作系统都是用小端法表示的(Windows、Android、IOS)

 

提问:大端法、小端法有什么优缺?为什么会出现两种方式?为什么大多数计算机都采用了小端法?

 

位运算

布尔运算

假设有两个bit,值分别是p和q;

~:

非,NOT。

1010~ = 0101

 

&:

与,AND,p=1且q=1是才为1。

1010 & 1100 = 1000

 

|:

或,OR,p=1或q=1时为真。

1010 | 1100 = 1110

 

^:

异或,(p=1或q=1) 且 p!=q时为真。

 

1010 ^ 1100 = 0110;1100 ^ 1100 = 0000;

 

习题

1、判断数字奇偶性

2、一个集合里,有一个数字出现了一次,其他所有数字都出现了两次,求这个出现了一次的数字。

 

 

移位运算

位移描述的实际上是数学上的高位/低位的移位运动,不是指实际的内存移动。

 

例如,左移就是低位往高位移动。大端法是向左移动,小端法是向右移动。

右移反之。

左移:<<,移动后右侧补零;

算数右移:>>,移动后补最高有效位的值;

逻辑右移 >>>,移动后左侧补0:

 

 

数1

数2

原始值

0110 0011

1001 0101

x << 4

0011 0000

0101 0000

x >>> 4(逻辑右移)

0000 0110

0000 1001

x >> 4 (算术右移)

0000 0110 

1111 1001

 

 

 

左移 等于 乘以2;

右移等于 除以2;

 

为什么会有算术右移和逻辑右移?

 

 

 

 

 

整形表示

无符号(原码)

 

 

假设有一个整数数据类型有w位,我们可以将位向量写成,表示整个向量。

表示向量中的每一位。在这个编码中,每一位都取0或者1。

 

用一个公式(binary to unsigned,二进制转无符号数,长度为w)来表示:

 

这个公式就是二进制向无符号整形的转换计算过程。

 

下面说人话:

0000 1000 转化为无符号整形的过程:

 

 

意思就是 0000 1000 这个二进制byte在无符号整形表示法下,实际的值是 8 。

 

提问:如何表示负数?

 

 

 

 

有符号(补码)

顶一个一个函数:

 

对于向量:

 

 

说人话:

0000 1000:

 

 

 

1110 1000:

 

1111 1111 = -1;

1000 0000 = -128

 

 

 

除了负整数除以2等于其右移1位加1外,所有的整数除以2与右移1位等价。

 

浮点数

 

二进制小数

 

学习浮点数表示有一个前提,就是要明白二进制小数的含义。

 

一个形如:

 

 

的表示法,每一位的取值范围是0和1,这种表示法表示的数字b的定义如下:

 

 

说人话:

 

1001.0011 =  =

 

也就是9.1875。

 

小数点左移一位:100.10011 = 4.59375

 

小数点右移一位:10010.001 = 18.375

 

提问:小数点左移右移有什么含义?

 

 

IEEE浮点数

 

这个就不详细描述定义了,太复杂了。直接说人话。

 

大体就是把一个浮点数表示为尾数乘以2的指数次方再添上符号。float和double的规格如下:

 

符号位     阶码      尾数     长度

float           1           8         23       32
double        1          11         52       64

 

先解释一下这几个部分:

符号位s表示正负,0是正1是负;

尾数M表示的含义是一个形如 1.00110.....的二进制小数,整数位都是有且仅有1。因为每个尾数都是整数部分只有1,所以保存时去掉整数位的1,只保留小数点后面的部分。

 

阶码E表示的是,尾数M 需要乘以 2的E次幂,才能得到实际表示的值。E也不是直接存储的字面值,而是有一些隐含逻辑。

 

实例讲解:

 

1、求38414.4D的IEEE二进制表示法

 

此数是Double,64位,阶码11位,尾数有52位。

 

符号位s:正数,为0;

尾数M:38414.4,用二进制表示是:0.4=0.5*0+0.25*1+0.125*1+0.0625*0+……

 

这个永远也写不完,这时候就只取53位(尾数可以放52位,最前面一位可以省略)

38414.4(10)=1001011000001110.0110011001100110011001100110011001100(2)

 

=1.001011000001110 0110011001100110011001100110011001100(2) *

 

标红部分S就是存到尾数M里的数据;

 

这时候来算阶码E:

在算尾数时,后面的2^15就是算阶码的关键。阶码的作用就是把尾数还原成二进制小数。如果想把S转换成实际的二进制小数,则需要1.S * 2^15次方,而E存储的就是这个15次幂这个信息。

 

Double的阶码有11位,可以保存-1024 ~ 1023这个范围的指数。因为指数是可以为负的,为了方便保存、计算,这里并没有采用补码来保存阶码,而是用移码,也就是实际指数 + 1023。这样做的好处是可以方便的比较浮点数大小,提升效率。11位无符号可以表示0-2047范围的数字。

 

那么15对应的阶码E就是15+1023 = 1038,二进制:100 00001110;

那么38414.4D在内存中的存储就是:

0 10000001110 0010 11000001 110 01100  11001100  11001100  11001100  11001100

 

问题1:如果表示0?如何表示无穷大?

 

问题2:阶码移码的表示范围?

 

用阶码全0 尾数全0表示0,用阶码全1尾数为0表示无穷大;

 

11为阶码能表述的无符号数范围就只剩下1-2046这个范围了,减去1023,则就对应的实际指数表示范围就是-1022~1023这个范围。

 

 

 

 

csonezp@gmail.com
原文地址:https://www.cnblogs.com/csonezp/p/14927124.html