前言
本文针对的是IEEE 754标准,同时测试使用的是遵循IEEE 754标准的Java语言。
问题
也许你在Java中使用浮点数时也碰到了这样的情况:
+0.0 + -0.0 = +0.0
+0.0 - -0.0 = +0.0
-0.0 + -0.0 = -0.0
-0.0 - -0.0 = +0.0
-1.5 * +0.0 = -0.0
+1.5 * -0.0 = -0.0
“-0.0”是哪里来的?实际上不只是”-0.0”,Java(IEEE 754)还定义了诸如NaN(Not a Number)、正无穷、负无穷的特殊值。这些值是随着浮点数的表示标准而产生的,但也遵循了一定的数学意义。
本文将初步探讨浮点数的表示、舍入,以及浮点数运算的数学属性。
IEEE 754 浮点数表示
IEEE 754标准是20世纪实际80年代推出的,实际上浮点数运算通常不会太多地关注运算的精确性,而把实现速度和简便性看得更重要。
十进制与二进制
我们都知道计算机的浮点数不能精确表示某些小数,但这究竟是为什么?
这当然不是所谓的“二进制表示法的缺陷”。回想一下,1/3在十进制中如何表示?0.3333….?
任何进制都有小数表示的限制,如十进制所能描述的数值d定义如下:
d=∑i=−nm10i∗di
仅考虑有限长度的编码,十进制表示法不能准确表达如1/3,1/7这样的数。同样,小数的二进制表示法也只能表示那些能够被写成 d=x∗2y
的数。由于我们习惯于日常使用的十进制表示法,于是对程序中的浮点数也经常会带有很多错误的偏见。为什么我在这2货程序里无法精确表示0.1这样简单的小数?你应该认识到你面对的就是”2”进制系统。
浮点数表示
位表示
IEEE浮点标准用 V=(−1)S∗M∗2E 的形式来表示一个数:
- S(符号):决定数的正负,但对于数值为0的浮点数,符号位解释为特殊情况处理。
- M(尾数):是一个二进制小数,它的范围是 1 ~ 2 - ϵ 或 0 ~ 1 - ϵ 。其中的 ϵ 表示一个极小的数,如