前言
此文章仅用于记录个人学习cs61c过程中对课程内容的理解,如果你在学习过程中遇到了困难可以参考参考,但是本文并不能充当原课程的替代品
由于水平有限/语文功底不行,文章可能存在诸多谬误,欢迎指正
另外,因为一些原因(懒/学过),稿主省略了部分内容
不推荐单纯的收藏/粘贴复制到笔记中,个人看来这样学习是效率最低的
浮点数
计算机可以利用n位表示2^n种事物,但对于非常大/小的数字又该怎么表示?如何表示浮点数?
先固定小数点位置试试
10.101 0 2 = 1 × 2 1 + 1 × 2 − 1 + 1 × 2 − 3 = 2.62 5 10 10.1010_2 = 1\times2^1 + 1\times2^{-1} + 1\times2^{-3} = 2.625_{10} 10.10102=1×21+1×2−1+1×2−3=2.62510
如果我们固定二进制数小数点的位置如上,那么一个六位的二进制数的表示范围为:0 to 3.9375
加法&乘法
规则照搬十进制的加法和乘法即可:
1. 5 10 + 0. 5 10 = 2. 0 10 1.5_{10}+0.5_{10}=2.0_{10} 1.510+0.510=2.010 也即 01.10 0 2 + 00.10 0 2 = 10.00 0 2 01.100_2+00.100_2=10.000_2 01.1002+00.1002=10.0002
1. 5 10 × 0. 5 10 = 0.7 5 10 1.5_{10}\times0.5_{10}=0.75_{10} 1.510×0.510=0.7510 也即 01.10 0 2 × 00.10 0 2 = 0000.11000 0 2 01.100_2\times00.100_2=0000.110000_2 01.1002×00.1002=0000.1100002
“浮点”数
为什么不固定小数点位置?——最有效地利用内存、精度更高…
对于 0.1640625 0.1640625 0.1640625 也即 . . . 00000.001010100000... ...00000.001010100000... ...00000.001010100000... 我们只需要传输10101和一个表示其浮点位置的参数即可——前后多余的零都不需要考虑
二进制数的科学计数法
规范化形式为 1. x x x x 2 × 2 y y y y y y 1.xxxx_2 \times 2^{yyyyyy} 1.xxxx2×2yyyyyy,利用指数来变更小数点的位置
浮点数表示
我们总可以把浮点数表示为上述科学计数法的形式
则一个32bit的浮点数的存储形式为:
符号(±) | 指数部分(y) | 小数部分/定点数(x) |
---|---|---|
1 bit | 8 bits | 23 bits |
——我们事实上并不存储1.xxx的1,因为他永远是1
指数部分采用补码的表示方式
其表示的正数范围为: 1.2 × 1 0 − 38 1.2 \times 10^{-38} 1.2×10−38 ~ 3.4 × 1 0 38 3.4 \times 10^{38} 3.4×1038
Overflow/Underflow
正负溢出,正负下溢
如何解决?更多的bit
IEEE 754 Floating Point Standard
基本内容
表示方法
1bit符号位(1负0正),8bits指数位,23bits小数位
指数
0无前导1,规定:全0表示0–0不唯一?bias notation
尾数/小数部分
省略了二进制科学计数法中的前导1,小数部分永远小于1大于0
bias notation
比较浮点数的时候我们不希望单独设计比较浮点数的电路,但是我们当前的表示方法下会出现这样的滑稽结果:
- 1/2>2,即0 1111 1111 000… 大于 0 0000 0001 000…
- 我们希望比较指数的时候,较为直接:小的数字二进制小,大的数字二进制大(无符号整数?)
- 怎么办?加个偏差bias
数字 | 原码 | bias 127 <无符号> |
---|---|---|
-128 | 1000 0000 | 1111 1111<保留作别的用途> |
-127 | 1000 0001 | 0000 0000<保留作别的用途> |
-126 | 1000 0010 | 0000 0001 |
… | … | … |
127 | 0111 1111 | 1111 1110 |
真实的表示范围为-126~127,则计算一个数的公式为:
- ( − 1 ) s i g n × ( 1 + S i g n i f i c a n d ) × 2 E x p o n e n t − 127 (-1)^{sign} \times (1 + Significand) \times 2^{Exponent-127} (−1)sign×(1+Significand)×2Exponent−127
如此,既不会出现±0的情况,也不会出现类似于1/2 < 2的情况
special numbers
正无穷负无穷?用最大的来表示:1111 1111
- 当然,尾数部分为全0:因为127.9999…再往上,自然是128.00000…
我们现在都得到了什么?
指数 | 尾数 | 表示对象 |
---|---|---|
0 | 0 | 0 |
0 | 非零 | ??? |
1-254 | xxxx | ±浮点数 |
255 | 0 | ±无穷 |
255 | 非零 | ??? |
NaN
计算中会有很多错误,如:0/0,sqrt(-4),即NaN,有 2 23 − 1 2^{23}-1 223−1 种可以被定义为NaN的类型——可以编码特定的错误类型,具体编码方式取决于硬件
任何和NaN进行的操作结果均为NaN——这意味着我们可以进行错误的传递
不均匀的浮点数&规范化导致的问题
规范化后,最小的正浮点数是多少?
a
=
1.000..
0
2
×
2
−
126
=
2
−
126
a=1.000..0_2 \times 2^{-126}=2^{-126}
a=1.000..02×2−126=2−126
第二小的?
b
=
1.0000...0
1
2
×
2
−
126
=
2
−
126
+
2
−
149
b= 1.0000...01_2 \times 2^{-126}=2^{-126} + 2^{-149}
b=1.0000...012×2−126=2−126+2−149
之后的每个数的间隔均为 2 − 149 2^{-149} 2−149,但0和最小的数之间却有道天堑
这是我们的前导1导致的问题,怎么办?
——Denorms
Denorms
—— 此处就可以用指数0,尾数非0的部分了
将前导1分解为2^23个均匀分布的数:
尾数有 2 23 − 1 2^{23}-1 223−1 个,无隐含前导1,隐含指数-126
最小的? 0.0000...0 1 2 × 2 − 126 = 2 − 149 0.0000...01_2\times2^{-126}=2^{-149} 0.0000...012×2−126=2−149
最大的? 0.1111...1 1 2 × 2 − 126 = ( 1 − 2 − 23 ) × 2 − 149 = 2 − 126 − 2 − 149 0.1111...11_2\times2^{-126}=(1-2^{-23})\times2^{-149}=2^{-126}-2^{-149} 0.1111...112×2−126=(1−2−23)×2−149=2−126−2−149
此处的最小间隔也为 2 − 149 2^{-149} 2−149 且最终也可以跨度到规范化的数字
总结
指数 | 尾数 | 表示对象 |
---|---|---|
0 | 0 | 0 |
0 | 非零 | Denorms |
1-254 | xxxx | ±浮点数 |
255 | 0 | ±无穷 |
255 | 非零 | NaN |
例子:1/3
由于 ∑ k = 1 ∞ 1 4 k = 1 3 \sum_{k=1}^{\infty}{\frac{1}{4^k}}=\frac{1}{3} ∑k=1∞4k1=31 ,即 0.01010101.. . 2 = 0.3333.. . 10 0.01010101..._2=0.3333..._{10} 0.01010101...2=0.3333...10,存储为0 01111101 010101…010
其他问题
不均匀精度
——因为总的来看,它的精度是不均匀的
0 ~ 2 − 125 2^{-125} 2−125的精度为 2 − 149 2^{-149} 2−149, 2 − 125 2^{-125} 2−125 ~ 2 − 124 2^{-124} 2−124的精度为 2 − 148 2^{-148} 2−148… 2 0 2^{0} 20 ~ 2 1 2^{1} 21的精度为 2 − 23 2^{-23} 2−23… 2 23 2^{23} 223 ~ 2 24 2^{24} 224的精度为 2 0 2^{0} 20——我们在将其指数等分为 2 23 2^{23} 223份
一个数字不可能同时很大,又有很小的精度——这就意味着很大的数在与小于其精度的数相加时,没有足够的bit,会丢失这个数:
– 1.5 × 1038 + ( 1.5 × 1 0 38 + 1.0 ) = 0.0 –1.5\times10{38} + (1.5\times10^{38} + 1.0)=0.0 –1.5×1038+(1.5×1038+1.0)=0.0
( – 1.5 × 1038 + 1.5 × 1 0 38 ) + 1.0 = 1.0 (–1.5\times10{38} + 1.5\times10^{38} )+ 1.0=1.0 (–1.5×1038+1.5×1038)+1.0=1.0
rounding
四舍五入
首先有个“有效位数”,假定为4
- 1.001 011 舍入结果为1.001
- 1.001 101 舍入结果为1.010
- 距离相等咋办?
- 1.001 100 舍入结果为1.010
- 1.000 100 舍入结果为1.001
如此,我们便得到均等机会的四舍五入
其他
永远向上/下/0舍入
0.1+0.2=0.3000000…04
精度问题嘛,0.1
浮点数加法
更加复杂:破坏规范化以匹配指数–相加尾数–得到一个共同的指数–规范化
转换&int
float to int:截断尾数
int to float:转换为最近的浮点数
int to float to int:gap够大(精度不够用了)时和原来的数不相等!双精度?双精度也不能解决这个问题,这个问题不可能解决——总存在这么一个数
其他精度
单精度:binary32/fp32
双精度:binary64
思想与单精度一样,更高的精度:1bit符号,11bits指数,52bits尾数,共64bits
表示范围:2.0 x 10-308 to almost as large as 2.0 x 10308(我懒得用latex语法了,将就着看吧)
binary128、256…
binary16/fp16
1/5/10
bfloat16
1/8/7——faster machine learning
U-bit!!!
指数位数、尾数尾数随意变…具体怎么设计的…请感兴趣的读者查阅更加深入的资料
——尚未被所有硬件支持
后记
稿主开始学习这部分内容的时候没想过要花这么长的时间…学到最后身心俱疲
看书看不懂,看ppt看不懂,听网课查资料又花了好久…毁灭吧,累了
再吐槽一句…csdn的md编辑器真难用,我从typora直接复制粘贴过来还得修修补补一些地方…csdn的文章标签也好难用,每次分享个笔记都要想想什么标签比较合适,不满3级不能自定义标签,现存的好多标签都没有…
总之,完结撒花~,欢迎大家交流