传闻: 浮点数变量不仅仅可以存储数字还可以存储一些异值
正确性: 正确
正如前面解答所说,标准中保留了指数的最大值和最小值来存储特殊的数。(注意在内存中这些指数的值分别存储为“全0”和“全1”。)
零(Zero)
当我们谈起符号-尾数-指数的表示时,实际上指的是任何非0数字可以用此方式进行表示。0并不能用这种方式直接表示。为了表示0,我们使用指数和尾数部分全0这样一个特殊的值来表示。注意-0和+0是两个不同值,尽管他们比较时是相等的。
这里有必要注意一下如果memset()用0来对一个浮点数的数组进行填充,那么存储的数将为0。同样的,由于C++中的全局变量初始化为0的位形式,因此全局的浮点数变量也被初始化为0。
这里有关于负0的相当一部分狡猾的陷阱。例如,如果x=0.0,表达式"0.0 - x"和"-x"并不是等价的,前面表达式的值是0.0,后面则是-0.0。
我对这个问题的看法是:负0能够“制造一个学习体验的机会”,当他们像以往一样打印出"-0"或者"-0.0"(这里“学习体验”指的是你花费在学习为什么得到这些奇怪值的时间和精力)。
无穷数(Infinities)
正无穷大和负无穷大对应于指数全1和尾数全0。符号位决定负无穷和正无穷。能够将无穷大表示成一个值是非常有用的因为
它们允许操作能够在越过溢出的情况下继续执行。
不是一个数字(Not a Number)
值NaN(Not a Number)被用来表示一个值不是实数。NaN被表示成一个指数全1,尾数非0的位形式。有两类NaN: QNaN (Quiet NaN) and SNaN (Signaling NaN)。
QNaN指的是尾数设置了最高有效位的NaN。QNaN通常出现在数学运算中。当结果在数学中没有定义时,通常产生这些QNaN值。(例如,3*sqrt(-1.0)就是一个QNaN)
SNaN指的是尾数清除了最高有效位的NaN。它用来标记操作时引发的异常。SNaN可以很容易的被指派给一个未初始化的变量来捕获一些不正确的使用。
【译者注:最高有效位(MSB) -- 指二进制中最高值的比特。例如,在十进制的15389这一数字中,相当于万位上的数字(1)对数值的影响最大。比较与之相反的“最低有效位”(LSB)。】
如果一个返回值是QNaN,那么意味着无法得知操作的结果,而SNaN则意味着操作本身是非法的。
低能数(Subnormal numbers)
我们始终没有使用指数全0和尾数非0的情况。我们有这些值存储和0非常近的数字。
这些数字被叫做“低能的”,因为他们比通常能够表示的数字要小。这里我们假定二进制小数点前面开头没有1。如果符号位是s的话,指数部分全0并且尾数为m,那么这个存储的值为(-1)^s*0.m*2^(-q),这里对于单精度数q是126,对于双精度数是1022。(注意0仅仅是低能数的一个特例。但我们仍然将它独立表示。)
总结所有可能的值(Summary of all possible values)
在下面的表中,b是用来存储指数部分时的偏移量,也就是..单精度时是127,双精度时是1023.
| sign s | exponent e | mantissa m | represented number |
| 0 | 00...00 | 00...00 | +0.0 |
| 0 | 00...00 | 00...01 to 11...11 | 0.m x 2-b+1 |
| 0 | 00...01 to 11...10 | anything | 1.m x 2e-b |
| 0 | 11...11 | 00...00 | +Infinity |
| 0 | 11...11 | 00...01 to 01...11 | SNaN |
| 0 | 11...11 | 10...00 to 11...11 | QNaN |
| 1 | 00...00 | 00...00 | -0.0 |
| 1 | 00...00 | 00...01 to 11...11 | -0.m x 2-b+1 |
| 1 | 00...01 to 11...10 | anything | -1.m x 2e-b |
| 1 | 11...11 | 00...00 | -Infinity |
| 1 | 11...11 | 00...01 to 01...11 | SNaN |
| 1 | 11...11 | 10...00 to 11.11 | QNaN |
对所有特殊的数进行操作(Operations with all the special numbers)
所有上述能够表示的特殊数字都是定义好的。这意味着你的程序不会仅仅因为某一个计算出来的值超过可以表示的范围而崩溃。但这仍然是一个不期望看到的情况,如果它发生了,你应该在你的程序中进行检查并且当它出现时进行处理。
所有的操作都是以直觉的方式定义的。任何有NaN参与的 操作将会产生NaN的结果。一些其他的操作见下表。(在表中,r是一个可以被表示的正数。∞是无穷大数,÷是平常的浮点数除法。)一个完整的列表可以在标准中或者你的编译器文档中查找到。注意甚至于这些值的比较操作都进行了定义。这个话题超过了本篇文章,如果你感兴趣的话,可以浏览文章末尾的参考。
| operation | result |
| 0 ÷ ±∞ | 0 |
| ±r ÷ ±∞ | 0 |
| (-1)s∞ x (-1)t∞ | (-1)st∞ |
| ∞ + ∞ | ∞ |
| ±r ÷ 0 | ±∞ |
| 0 ÷ 0 | NaN |
| ∞ - ∞ | NaN |
| ±∞ ÷ ±∞ | NaN |
| ±∞ x 0 | NaN |
