4. 五种异常
无效运算 > 上溢 > 除以零 > 下溢 > 不精确,前三个一旦出现很少被忽略
IEEE 754 定义了五种基本的浮点异常,分别是:无效运算、除以零、上溢(指数太大)、下溢(指数太小)和不精确。前三个一旦出现很少被忽略,后两个通常可以安全地忽略(尽管不总是)。
异常的优先顺序是:无效运算 > 上溢 > 除以零 > 下溢 > 不精确。能够在单个运算中同时发生的标准异常只有不精确的上溢和不精确的下溢这两种组合。
示例:0/0, 0*∞, ∞/∞, 负数的平方根, NaN 参与的任何运算, 无效转换
0 / 0; // NaN
0 / -0; // NaN
-0 / 0; // NaN
-0 / -0; // NaN
0 * Infinity; // NaN
0 * -Infinity; // NaN
-0 * Infinity; // NaN
-0 * -Infinity; // NaN
Infinity / Infinity; // NaN
Infinity / -Infinity; // NaN
-Infinity / Infinity; // NaN
-Infinity / -Infinity; // NaN
Math.sqrt(-1); // NaN
NaN + 1; // NaN
parseInt("hello") + 1; //NaN
parseInt("hello"); // NaN
parseInt(NaN); // NaN
parseInt(Infinity); // NaN
原因:针对有限操作数执行运算时,生成精确的无穷大结果
原因:正确舍入的结果的指数,超过了能表示的最大指数值,即指数 > emax。
双精度示例:21024,e709.8, MAX_VALUE*2
缺省结果:取决于舍入模式和中间结果的符号。四种舍入方向:
向最接近的可表示的值舍入:当有两个最接近的可表示的值时,首选“偶数”值
原因:精确结果或正确舍入的结果的绝对值,比能表示的最小正“正规数”小,即 |结果| < 最小正“正规数”。
双精度示例:2−1074,2−1075
下溢,也称浮点下溢/算术下溢。在《1. 双精度浮点数》中我们有提到,IEEE 754 binary64(双精度浮点数)实际存储的有效数是经过规范化处理的。正规数,就是规范化处理后的有效位表示,其有效数的默认前导位是 1。
次正规数是介于最小正规数和零之间的数,它通过调整指数(将指数位全置为 0)来去除有效数的前导 1,以此来表示比最小的正规数更接近 0 的数字。这样就能填补浮点运算中 0 附近的下溢间隙了,进而避免“即使两个数值不相等,减法 a - b 会发生下溢进而产生 0”的情况(达到下溢时,会丢弃所有有效数字,然后就突然变 0 了)。所以,次正规数也被称为逐渐下溢,因为它允许(值非常小的)计算结果慢慢地失去精度。
最小的正“正规数”应该是:正数即符号位为 0,11 位指数是“全 0+1”,52 位有效数是“全 0”。也就是说其 binary64 的内存存储为 0x0010000000000000,如下:

真实值就是:(−1)0∗1.00...00(2)∗21−1023=1∗2−1022≈2.2250738585072014e−308
最大“次正规数”应该是:正数即符号位为 0,11 位指数是“全 0”,52 位有效数是“全 1”。也就是说其 binary64 的内存存储为 0x000FFFFFFFFFFFFF,如下:

真实值就是:(−1)0∗0.11...11(2)∗2−1022
= 11...111(2)∗2−1022−52
= (252−1)∗2−1022−52
= 2−1022−2−1074
最小“次正规数”应该是:正数即符号位为 0,11 位指数是“全 0”,52 位有效数是“全 0+1”。也就是说其 binary64 的存储存储为 0x0000000000000001,如下:

真实值就是:(−1)0∗0.00...01(2)∗2−1022
= 1∗1(2)∗2−1022−52
下溢的缺省结果:返回次正规数或 0。示例如下:
原因:有效运算的舍入结果和无限精确结果不相等,即精度被裁剪了。实际上,大多数浮点运算都会导致“不精确”异常,详见《2. 精度损失》。