为何浮点数不能精确表示?——浮点数在计算机中的存储方式

浮点数在计算机中的存储方式

在编程时,往往不能直接将两个浮点数进行大小比较,如下面的代码中num2 = 8.1/3按理来说应该等于2.7,然而程序却输出的是2.6999999999999997

double num1 = 2.7;
double num2 = 8.1/3;
System.out.println(num1);//2.7
System.out.println(num2);//2.6999999999999997

这就要讲到浮点数在计算机中是如何表示的了,在计算机中,浮点数是按照类似科学计数法来进行表示的。按照最常见的IEEE 754标准,浮点数在计算机内部存储时分为符号位(sign)、指数(exponent)、尾数(fraction)部分(以float为例):
为何浮点数不能精确表示?——浮点数在计算机中的存储方式_第1张图片

浮点数在存储时略去了第一个1,只存储小数点之后的数字即尾数,这样可以节省存储空间
指数是一个无符号整数,取值范围为0到255,但是指数可以是负的,所以规定在存入时在它原本的值加上127(使用时减去中间数127),但是指数全为1时有其特殊用途(无穷大),所以指数最大为 11111110,这样指数的取值范围为-127到127
(按照这个定义,数字 0 是无法表示的。所以 IEEE R32.24 标准强行规定,符号位,指数,尾数都为0 时,该数为0)
在这个规则下,浮点数的计算步骤如下:在尾数前加一位1,记作F;再将指数部分减去127,记作E;符号位记作S,则计算公式为: ( − 1 ) S × 2 E × F ( 2 进制) ( - 1 ) ^ { S } \times 2 ^ { E } \times F _ { (2进制) } (1)S×2E×F2进制)
当我们要存储十进制的小数,比如0.1时,首先将其化为二进制小数,我们发现,0.1化为二进制小数是无限循的0.0001100110011001100…,我们只能取23位尾数进行存储,这时便产生了误差,当我们再把它化为十进制小数时就发现它不是0.1了。

因此,我们不能使用 float 和 double 这样的浮点数来表示金额等精确的值,在JDK中有java.math.BigDecimal ,这个类可以表示任意精度的数字,在应用中我们可以使用它来表示精确值。

浮点数的范围及精度

对于float类型,最大为+1.1111111 1111111 11111111(二进制)×2^127。最小为-1.1111111 1111111 11111111(二进制)× 2^-127也即-3.4028235E38到3.4028235E38,(+1.1111111 1111111 11111111(二进制)约等于2)
浮点数的精度是由尾数的位数来决定的,故float类型的精度为2^-23。或者说,由于2^23 = 8388608,一共七位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效数字。

你可能感兴趣的:(学习,笔记)