这篇文章与一道题有关:
/*
* floatScale2 - Return bit-level equivalent of expression 2*f for
* floating point argument f.
* Both the argument and result are passed as unsigned int's, but
* they are to be interpreted as the bit-level representation of
* single-precision floating point values.
* When argument is NaN, return argument
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
unsigned floatScale2(unsigned uf) {
return 2;
}
题目来自于CMU15-213/lab/datalab。
浮点数的表示方法
在上面的题目中没有使用float作为类型传参,而是使用的unsigned,该类型和float一样,都是32字节的,现在我们将重心放回float的表示中:
- 符号位:1bit
- 指数部分:8bit
- 尾数部分:23bit
对于double,其实原理也是一样的:
看完了上面这个描述,想必心中会有很多的疑问,接下来慢慢说。
格式化数
在浮点数的存储中,数字通常是格式化的,什么是格式化的呢?格式化的有什么要求呢?
- 符号位(s):跟先前的一样,0表示正数,而1表示负数。
- 指数部分(exp):该部分使用移码进行表示。在格式化数中,指数部分不能全为1,它拥有一个计算公式:
E = E x p − B i a s E = Exp - Bias E=Exp−Bias
其中,Exp就是相对应的十进制表示,而Bias也有一个计算公式:
B i a s = 2 k − 1 − 1 Bias = 2^{k - 1} - 1 Bias=2k−1−1
这个k,就是在该浮点数中,exp部分有多少个bit表示。Bias的作用就是将浮点数的表示区间进行一个划分,使其在正数和负数区域都有相同的表示范围。 - 尾数部分(frac,M):该部分表示浮点数的有效数字部分,它默认会有一个隐含的1(前导1,这个前导1是二进制而不是十进制!),也就是说,这部分实际上是1.xxxxxxx
至此,我们就能够给出浮点数的计算公式:
v
a
l
=
(
−
1
)
s
×
M
×
2
E
val = (-1)^s×M×2^E
val=(−1)s×M×2E
来个例子:
非格式化数
对于非格式化数,它的区别就是在exp(指数部分)上:先前提到,在格式化数中,指数部分不能全为1,而在非格式化数中,它全为0,因此,在浮点数计算公式中,E的计算也改变了:
E
=
1
−
B
i
a
s
E = 1 - Bias
E=1−Bias
下面这张PPT说的很清楚:
上面提到了,在浮点数表示法中,存在“-0”和“+0”,但是,实际上它们在计算时被认为是相等的。
在格式化数中,会有个隐含的前导1,而非格式化数中没有这个。
特殊值
在这种情况下,exp不全为1的条件被打破,并且变为了exp全为1:
PPT中也说的很全了:
- exp=111…1,frac=000…0,表达无穷大、溢出
- exp=111…1,frac≠000…0,表示1非数(NaN)