说来惭愧,作为计算机科班出身的人,计算机基础知识掌握并不扎实,这里的基础指的是计算机体系结构中的内容,诸如数据的表示和处理,如float的表示和运算等。看《CSAPP》方知人家老外把这个东西当成重中之重,大量详细的原理介绍,并配套大量例题。当初本科学的时候,很简单的了解了下概念而已,所以应该直接将《CSAPP》当做教材来用,里面习题全做,这样CS出来的基本知识将掌握的很扎实。
学艺不精的后果就在于:学而不思则罔。圣人太厉害了,总结得很到位。比如最近项目中涉及到浮点和定点的转换,自己就有点蒙,边看边实验,还算理解了,作文以记之。
一直以来,程序中接触的数据类型都是int整型,char字符型,float单精度浮点型,double双精度浮点型。看到浮点和定点一直不知道如何划分这个概念的范畴。以为浮点就是float表示小数,定点就是int可表示整数而已。经过学习明白了显然是错误的。应该是这样划分的:
有了这个认识,后面的讨论就可以开始了。
浮点数以float为例讨论。
规定浮点数格式为: V = ( − 1 ) s × M × 2 E V = (-1)^s×M×2^E V=(−1)s×M×2E
将其封装到32位的字中:
符号位 | 阶码 | 尾数 |
---|---|---|
1 | 8 | 23 |
根据32位数计算为十进制: V = ( − 1 ) s × ( 1. M ) × 2 ( E − 127 ) V = (-1)^s×(1.M)×2^{(E-127)} V=(−1)s×(1.M)×2(E−127)
可以得出以下结论:
我们说浮点数的小数点不是固定的,是浮动的,那么如何理解?通过例子可直观体验。
符号 | 阶码 | 尾数 |
---|---|---|
0 | 0111 | 001 |
这个浮点数表示十进制的1.125
符号 | 阶码 | 尾数 |
---|---|---|
0 | 0111 | 010 |
若阶码不变,尾数加1,则表示十进制的1.25
符号 | 阶码 | 尾数 |
---|---|---|
0 | 1000 | 001 |
若尾数不变,阶码加1,则表示十进制的2.25
对于计算机来说,浮点定点的概念是看不见的,因为它只能看到:0…00001110,至于它表示多少,是逻辑层面的设置。你如果让它是int那就按照int表示法对每个位赋予意义,如果你让它是float就按照float表示法赋予意义。
对于 00011100 00011100 00011100表示的定点数:
可以看到:
以8位为例,最高位为符号位:
这来源于项目中神经网络的需求,网络中大量的参数,如果全部用F32表示,一是占用空间大,二是读取效率不高。
如果我们可以将某些浮点数转换为定点数表示,在接受精度损失的前提下,每次就可以读取多个进行运行,可显著提高运算效率。
举例来说,我们用8位定点数,1个符号位,4个整数位,3个小数位,则其可表示范围是-16.00~15.875,最大精度0.125。
有几个浮点数:0.145,1.231,2.364,7.512,每个需要32bit表示。
如果我们将每个量化成一个8位定点数,比如通过某种方法得到:1,10,19,60
此时每个数需要8bit表示。那么读一个浮点数,可以同时读4个定点数,且计算效率可以提高。当然这样做是有风险的:
我们用8位定点数,1个符号位,4个整数位,3个小数位。这个3称为量化系数。该过程称为量化。
(我们总是将非离散值量化到离散值空间,处理更为简单)
i n t 8 = f l o a t 32    ∗    2 ( 3 ) int8 = float32 \,\,* \,\, 2^{(3)} int8=float32∗2(3)
如: i n t 8 ( 10 ) = f l o a t 32 ( 1.231 )    ∗    2 ( 3 ) int8(10) = float32(1.231) \,\,* \,\, 2^{(3)} int8(10)=float32(1.231)∗2(3)
该过程称为反量化。
f l o a t 32 = i n t 8    /    2 ( 3 ) float32 = int8 \,\,/ \,\, 2^{(3)} float32=int8/2(3)
如: f l o a t 32 ( 1.250 ) = i n t 8 ( 10 )    /    2 ( 3 ) float32(1.250) = int8(10) \,\,/ \,\, 2^{(3)} float32(1.250)=int8(10)/2(3)
可以这样理解:量化系数 n n n 决定了我们逻辑上认为01序列中可表示的单位值 1 / ( 2 n ) 1/{(2^n)} 1/(2n),CPU读取的数字表示有多少份单位值。
举例来说,对于固定的01序列值:0001,1100
量化系数 | CPU读取值 | 单位值 | 表示逻辑值 |
---|---|---|---|
3 | 28 | 0.125 | 3.5 |
2 | 28 | 0.250 | 7.0 |
同样的int8数,因为量化系数的不同,代表着不同的f32值。
还有个note:
可以看到: