alwaystest / Blog

24 stars 2 forks source link

Folat 不能精确表示小数 #59

Open alwaystest opened 7 years ago

alwaystest commented 7 years ago

Folat 不能精确表示小数

标签(空格分隔): 基础


计算机界流传着这么一个区别AI与人类的方法:

问: 0.2 + 0.1 = ?

如果是AI,答案就不是刚刚好0.3。

当然,不是说用电脑的计算器程序算这个结果,而是在编程的时候直接输出0.1 + 0.2

大学学基础课的时候曾经提到过这一点,当时也没有仔细研究,就当是基础概念记住了,小数在计算机中存储会有误差,有些小数不能准确表达。

目前的计算机是使用二进制来存储和表达数据的,十进制的数据在计算机中会被转换为二进制的数据。

整数部分,十进制能表示的最小有效单位是1,二进制也是,我们可以用几个1来表达整数部分,

比如十进制的123,用十进制表达,就是 1 * 10^2 + 2 * 10^1 + 3 * 10^0

用二进制表示:1 * 2^6 + 1 * 2^5 + 1 * 2^4 + 1 * 2^3 + 0 * 2^2 + 1 * 2^1 + 1 * 2^01111011

所以整数表达不存在二进制没办法准确表示十进制的数值。

但是小数部分就不一样了。

同样是3位小数,十进制可以表示的最小单位是 0.001, 二进制可以表示的最小单位是 0.001 转换成十进制就是2^-3 == 0.125

这样,能表达的数就成了这样,十进制可以表示1000个值,二进制只能精确表示8个值,这8个值都是可以表达的最小单位的整数倍。比如0.5就是4 * 0.125,所以0.5这个值是可以用3位精度的二进制小数精确表达的,而0.1,0.2,0.3等等不是0.125整数倍的小数就无法使用三位精度的二进制小数来精确表达的。

扩展到float,哪怕它使用了比3位更大的小数精度来表示一个数字,但是很遗憾即使是这么小的单位,也不能整除0.2,0.3这些数值,所以也就无法精确表示这些值,所以在代码中计算0.1 + 0.2的结果就没办法精确的表示位0.3,只能取一个最近似的数来表示。