- 首先,计算机中如何存储小数是一个叫做IEEE标准决定的
- Java中float占32位,其中第三十一位为符号位 s, 第三十位到第二十三位为指数位,,剩余第二十二位到 第一位为有效数字位,也就是说,一个小数用IEEE浮点标准表示为
-
- 理解:因为M表示的是11001这样子的零一序列
- M * 2^E 其实就是把M这些数字序列往做或者往右挪动E位
- 有一句话是: 浮点数只是对小数的粗糙近似,而不是其完全刻画
- 在任何两个不相等的实数中,存在着无数个两两不等的实数,但是这一点在浮点数中无法体现
-
- 在这两个浮点数中间 01111110100000000000000000000001 和 01111110100000000000000000000000的差值高达1.014 * 10的31次方他们中间应该存在着无数个实数
- 但是在浮点数中,他们是相邻的,两者间不存在任何数
- 这就是计算机中存在的浮点数问题
- 继续看一个十进制小数转换为二进制小数的例子,二进制和十进制小数的表示存在相同点也存在不同点,二进制小数点后表示的是2的负幂,十进制小数表示的是10的负幂 比如78.375
- 整数部分
-
- 小数部分
-
- 所以 78.375的二进制形式就是1001110.011
- 然后,根据符号位,尾数,阶码的表示方式,就有了
- 那么就有一个问题:因为第三点提到的精度问题,在第四点中的小数转换部分,会不会有可能出问题?换句话说,因为浮点数无法完全刻画所有小数,那就是说有的小数无法在浮点数中找到对应的表示方式?
- 答案是肯定的
- 这就可以解释java中使用小数进行加减乘除有时候出现的“奇怪的问题了”
- 可能是等号左边的参数本身无法用浮点数进行完全刻画
- 可能是计算结果无法用浮点数完全刻画
- 或者都是