正确理解浮点数

April 25, 2021

首先,浮点数是一种数字的表示方式,而不是指小数

很多人一提到浮点数,就说是小数,这是不对的。浮点数只是一种数字的表示方式,数字是多少就是多少,它就在那里不会改变,改变的只是人类表示它们的方式。

比如给定一个数 10,能确定它是浮点数还是定点数吗?

不能!我们必须知道这个数是如何存储的,即底层是如何来表示这个数的,才能说它是定点数还是浮点数。

这其实类似于十进制中的科学计数法,比如 1234.5678这个数,这个数本身不会改变,是多少永远是多少,变的是表示它的方式,我们可以以多种不同的方式来表示这个数:

  • $1.2345678 \times 10^3$
  • $123.45678 \times 10$
  • $0.12345678 \times 10^4$
  • $12345678 \times 10^{-4}$

可以看到,小数点的位置是浮动的,这才是浮点数名字的由来。再次强调,浮点数指的是表示数字的方式,而不是数字本身

至于大家常提到的IEEE754,它是一个标准,即规定了大家统一采用哪种方式来表示和存储数据,它规定尾数部分格式为 1.xxxx,具体存储时1省略,其他细节不再赘述。

为什么要使用浮点数

简单来说,同样的位数,浮点数表示的范围更大

比如 int 和 float 同是 32bit

int的最大值为 $2^{31}-1 = 2.147483647E9 = 2147483647$

float的最大值为 $(2-2^{23})\cdot2^{127} = 0\mbox{x}1.fffffeP+127f = 3.4028235E38f$ 这表示范围可比 int 大多了

为什么float的精度是6~7位?

因为float的尾数部分有23位,即可以用23位二进制来表示一个数,指数部分不影响精度,只影响范围,因为有效数字是从第一个非0位算起。

事实上还要加上规格化尾数省略的1,所以问题就变成24位二进制位可以表示多少位十进制?

\[\begin{align*} 2^{24} &= 10^x\\ x &= {log_{10}2^{24}} = 24 \cdot log_{10}2 = 7.22471989594 \end{align*}\]
1
2
float f = 0.123456789f;
System.out.println(f); // 0.12345679  只能保证7位精度