浮点数表⽰⽅法
之前的⼀些⼯作当中碰到了很多有关浮点数的问题,⽐如浮点数的表达范围、表达精度、浮点数的存储⽅式、浮点数的强制类型转换等等,因此感觉有必要系统了解⼀下有关浮点数的问题。
浮点数表⽰
浮点数是⼀种 公式化 的表达⽅式,⽤来近似表⽰实数,并且可以在表达范围和表⽰精度之间进⾏权衡(因此被称为浮点数)。
浮点数通常被表⽰为:
N=M×R^E
⽐如: 12.345=1.2345×10^1
其中,M(Mantissa)被称为浮点数的 尾数 ,R(Radix)被称为阶码的 基数 ,E(Exponent)被称为阶的 阶码 。计算机中⼀般规定R为2、8或16,是⼀个确定的常数,不需要在浮点数中明确表⽰出来。
因此,在已知标准下,要表⽰浮点数,
⼀是要给出尾数M的值,通常⽤定点⼩数形式表⽰,它决定了浮点数的表⽰精度,即可以给出的有效数字的位数。
⼆是要给出阶码,通常⽤定点整数形式表⽰,它指出的是⼩数点在数据中的位置,决定了浮点数的表⽰范围。因此,在计算机中,浮点数通常被表⽰成如下格式:(假定为32位浮点数,基为2,其中最⾼位为符号位)
浮点数的规格化表⽰
按照上⾯的指数表⽰⽅法,⼀个浮点数会有不同的表⽰:
0.3×10^0;0.03×10^1;0.003×10^2;0.0003×10^3;
为了提⾼数据的表⽰精度同时保证数据表⽰的唯⼀性,需要对浮点数做规格化处理。
在计算机内,对⾮0值的浮点数,要求尾数的绝对值必须⼤于基数的倒数,即|M|≥1/R。
即要求尾数域的最⾼有效位应为1,称满⾜这种表⽰要求的浮点数为规格化表⽰:把不满⾜这⼀表⽰要
求的尾数,变成满⾜这⼀要求的尾数的操作过程,叫作浮点数的规格化处理,通过尾数移位和修改阶码实现。
⽐如,⼆进制原码的规格化数的表现形式:(0正1负)
正数 0.1xxxxxx
负数 1.1xxxxxx
注意,尾数的最⾼位始终是1,因此我们完全可以省略掉该位。
⾄此,我们引⼊IEEE754 标准,该标准约束了浮点数的⼤部分使⽤设置:(尾数⽤原码;阶码⽤“移码”;基为2)
(1) 尾数⽤原码,且隐藏尾数最⾼位。
原码⾮0值浮点数的尾数数值最⾼位必定为 1,因此可以忽略掉该位,这样⽤同样多的位数就能多存⼀位⼆进制数,有利于提⾼数据表⽰精度,称这种处理⽅案使⽤了隐藏位技术。当然,在取回这样的浮点数到运算器执⾏运算时,必须先恢复该隐藏位。
(2) 阶码使⽤“移码”,基固定为2
如下图的32bit浮点数和64bit浮点数,从最⾼位依次是符号位、阶码和尾数
于是,
⼀个规格化的32位浮点数x的真值为:
x=(−1)^s×(1.M)×2E^−127
⼀个规格化的64位浮点数x的真值为:
x=(−1)^s×(1.M)×2E^−1023
下⾯举⼀个32位单精度浮点数-3.75表⽰的例⼦帮助理解:
(1) ⾸先转化为2进制表⽰
−3.75=−(2+1+1/2+1/4)=−1.111×2^1
(2) 整理符号位并进⾏规格化表⽰
−1.111×2^1=(−1)^(1)×(1+0.1110 0000 0000 0000 0000 000)×2^1
(3) 进⾏阶码的移码处理
(−1)^(1)×(1+0.1110 0000 0000 0000 0000 000)×2^1
=(−1)^(1)×(1+0.1110 0000 0000 0000 0000 000)×2^(128−127)
浮点数的基数什么意思于是,符号位S=1,尾数M为1110 0000 0000 0000 0000 000
阶码E为12810=1000 00002
,则最终的32位单精度浮点数为
1 1110 0000 0000 0000 0000 000 1000 0000
浮点数的表⽰范围
通过上⾯的规格化表⽰,我们可以很容易确定浮点数的表⽰范围:
既然有表⽰范围,那肯定也有不能表⽰的数值:
⾸先来说明溢出值,如下图:
(1)⽆穷值:
如果指数E=11111111(2)=255(10)
且尾数M=0
,则根据符号位S分别表⽰+∞
和−∞
。因此,⼀个有效的32位浮点数其指数最⼤只能为254。
此外,⽆穷具有传递性,⽐如
(+∞) + (+7) = (+∞)
(+∞) × (−2) = (−∞)
(+∞) × 0 = NaN
(2)零值:
如果指数E=0
且尾数M=0
时,表⽰机器0.需要注意的是,这⾥的0也是有符号的,在数值⽐较的时候 +0=−0
; 但在⼀些特殊操作下,⼆者并不显相等,⽐如log(x), 1/+0≠1/−0。
此外,处于负下溢出和负上溢出之间的数值会被直接归为0。
(3)NAN:
如果E=0,且尾数M≠0,则表⽰这个值不是⼀个真正的值(Not A Number)。NAN⼜分成两类:QNAN(Quiet NAN)和
SNAN(Singaling NAN)。QNAN与SNAN的不同之处在于,QNAN的尾数部分最⾼位定义为1,SNAN最⾼位定义为0;QNAN⼀般表⽰未定义的算术运算结果,如0/0, ∞×0, sqrt(−1);SNAN⼀般被⽤于标记未初始化的值,以此来捕获异常。
浮点数的表⽰精度
⼀般提到浮点数的精度(有效位数)的时候,总是会出现 float的有效位为6~7位, double的有效位为15~16位 。
下⾯以float为例,解释⼀下有效位数是怎样来的。
有效位数只和规格化浮点数的尾数部分有关,⽽尾数部分的位数是23位,因此我们⾸先列出下表
由上⾯的表格可以看出:
2^−23 和 2^−22 之间是存在间隔的,即0.0000001和0.0000002之间的⼩数我们是没有办法描述的,因此23位尾数最多只能描述到⼩数点后第7位;此外,我们通过四舍五⼊可以很容易发现0.0000003=0.0000004=2^−23+2^−22
, 这表明第7位有效数字只是部分准确。⽽第6位及之前的都是可以准确描述的,因此我们说float的有效位为6~7位。
参考资料