浮点数相关问题简记
浮点数的基本问题
用于表示不定精度的有符号小数,使用科学计数法,即:
x
=
(
s
i
g
n
)
×
2
e
x
p
×
b
a
s
i
n
x=(sign)\times 2^{exp}\times basin
x=(sign)×2exp×basin
一个典型的浮点数包括符号,阶码,basin的尾数。
float
类型32位,8位阶码;double
类型64位,11位阶码
浮点数的表示
表示公式如上。在IEEE754标准中,阶码为带符号的整数,并且以移码(该数补码的符号位取反)的形式表示;basin强制为1.xxxxxxx
的形式,因此在尾数部分仅有xxxx的值。
Example
对于一个float 00000010100000000001110111100000
:
- Split:
sign=0
,exp_raw=00000101
,basin=(1.)00000000001110111100000
- Analysis:
- 正数
- 阶码为
00000101
,补码为10000101
,恢复原码为11111011=-1111011=-123
basin=1.00000000001110111100000
- Merge:表示的数为 1.00000000001110111100000 × 2 − 123 1.00000000001110111100000\times 2^{-123} 1.00000000001110111100000×2−123
浮点数的临界问题
移码的数值域只有7位(1位是符号位),因此能表示的最小数为-127 。而basin强制大于等于1,因此最接近0的浮点数为 ± 2 − 127 × 1.0000... \pm2^{-127}\times 1.0000... ±2−127×1.0000...
特殊规定:阶码全为1,尾数全为0时表示 ± ∞ \pm\infin ±∞。
浮点数的加减运算
Tips:上面是IEEE754的表示方法,这里用到的浮点数表示法如下:
2位阶符(双符号位)+阶码+2位数符+尾数(0.xxxxx,用的补码)
例如:
X = 2 010 × 0.11011011 , Y = 2 100 × ( − 0.10101100 ) X=2^{010} \times0.11011011, Y=2^{100}\times (-0.10101100) X=2010×0.11011011,Y=2100×(−0.10101100)
的浮点表示为:
阶符 | 阶码 | 尾数符 | 尾数 | |
---|---|---|---|---|
X | 00 | 010 | 00 | 11011011 |
Y | 00 | 100 | 11 | 01010100 |
这里是补码 | 这里也是补码 |
那么有下面的加减流程:
-
对阶:为避免truncate,小阶应向大阶对齐,basin算术右移一位并且阶数+1
-
按照定点加法加basin。注意是用basin的补码做加法运算。 a − b = a + ( − b ) a-b=a+(-b) a−b=a+(−b)
-
整理(规格化):
根据规格化浮点数的定义,当尾数用二进制补码表示时,规格化浮点数的尾数形式为00.1××…××或11.0××…×× 否则就是溢出了。若浮点数的尾数不是这两种形式,则称之为非规格化浮点数,需进行浮点数的规格化。
若浮点数的尾数形式为00.0××…××或11.1××…××,应利用向左规格化使其变为规格化浮点数,尾数每算术左移1位,阶码减1,直到浮点数的尾数变成规格化形式。
若浮点数的尾数形式为01.××…××或10.××…××,表示尾数求和的结果发生溢出,应利用向右规格化使其变为规格化浮点数,尾数算术右移1位,阶码加1,此时浮点数的尾数就变成了规格化形式。
在对阶或向右规格化时,尾数都要进行算术右移操作,为了保证运算结果的精度,运算过程中需保留右移中移出的若干位数据,称为保护位。在运算结果进行规格化后再按照某种规则进行舍入处理以去除这些数据。舍入处理就是消除保护位数据并按照某种规则调整剩下的部分,舍入处理总要影响到数据的精度。舍入处理的方法通常选用“0舍1入”法。
人话版本:
尾数的。双符号位的补码加减情况下,如果两个符号位不同,则发生了溢出,需要进行右规格化,即运算结果右移一位,阶码+1;
如果符号位和尾数补码的最高位相同(想一想两种该情况,11-1和00-0,翻译成原码应该是±0.0xxxx,属于浪费了尾数的位数),就要进行左规格化,尾数左移并阶码-1直到没有尾数的浪费,即尾数补码的最高位和符号位不同。最后补0.
-
舍入:在对阶和右规的时候会造成有效位被扔出去(超出了尾数的位数范围),在实际加减中应该保留这些位,在这一步集中处理。有两种处理方案:
- 0舍1入。如果右移时被扔出去的最高(这里看例题)位为0,则不管;为1,则给剩下尾数+1,尽管这会造成溢出。
- 置1法。强制尾数的最后一位为1
-
溢出处理:尾数加减出溢出并不代表溢出,此时应该进行右规格化。当规格化完毕时,如果阶码的符号位出现异常,则出现溢出。符号位为01为上溢(01=00+1),10为下溢,此时认为是结果是0(因为阶码已经是-128以下了)
Example
X = 2 010 × 0.11011011 , Y = 2 100 × ( − 0.10101100 ) X=2^{010} \times0.11011011, Y=2^{100}\times (-0.10101100) X=2010×0.11011011,Y=2100×(−0.10101100)
求 x + y x+y x+y,舍入采用0舍1入法。
- 对阶:x右规范化, x = 2 8 × 00.00001101 ( 1011 ) x=2^8\times 00.00001101(1011) x=28×00.00001101(1011)(带括号的四位留中), y = 2 8 × 11.01010100 y=2^8\times 11.01010100 y=28×11.01010100(注意这里11和00是符号位,不是整数部分)
- 加减: x + y = 2 8 × 11.10001010 ( 1011 ) x+y=2^8\times 11.10001010(1011) x+y=28×11.10001010(1011)
- 整理:
- 没有发生溢出,不需要右规范化。如果这里发生了右规范化,那么留中的数位要更多。
- basin部分的最高数值位和符号位相等,即原码的basin为0.0xxx,考虑进行左规格化(shrink)。
- 调整为 2 7 × 11.00010101 ( 011 ) 2^7\times 11.00010101(011) 27×11.00010101(011)注意:这里留中的4位回了一位进去,所以说一开始不能随便截取,要到这里统一处理
- 截取:剩下的留中为011,最高位是0,因此直接discard。
- 最后答案为 2 7 × 11.00010101 2^7\times 11.00010101 27×11.00010101
References
https://blog.csdn.net/qq_40663469/article/details/89061612
https://www.jianshu.com/p/af8b7329ec20