【1031 | Day57】灵魂拷问:为什么「0.1+0.2!=0.3」,而「0.1+0.3==0.4」?

我们都知道潮汐现象,上学的时候老师多半简单解释一句「月球引力所致」就算了,而我们也都觉得自己明白了,但是凡事就怕琢磨。

老友记表情包

如果涨潮仅仅是月球对地球万有引力的作用结果的话,那么每天同一个地点,应该仅仅在距离月球最近引力最强的时候有一次涨潮才对,但是住在海边的人都知道,同一个地点,每天会有两次涨潮,为什么

我抛出这个问题并不是我转行搞物理学了,而是我发现很多司空见惯的问题,如果深究的话,你就会发现很多人根本就没搞懂。

浮点数运算就是这样一个问题,每个人都知道浮点数运算有精度损失,但是为什么「0.1+0.2!=0.3」,而「0.1+0.3==0.4」?

img

除了含含糊糊的精度损失,你能给出更有营养的解释么?

让我们看看到底是为什么!

老友记表情包 请开始你的表

- 首先!!!

回顾一下二进制和十进制转换:

  • 十进制「13」:1*(10^1) + 3*(10^0) = 10 + 3 = 13
  • 二进制「1101」:1*(2^3) + 1*(2^2) + 0*(2^1) + 1*(2^0) = 8 + 4 + 0 + 1 = 13

接着,让我们再举一个小数的例子,比如:

  • 十进制「0.625」:6(10^-1) + 2(10^-2) + 5*(10^-3) = 0.625
  • 二进制「0.101」:1(2^-1) + 0(2^-2) + 1*(2^-3) = 5/8 = 0.625

最重要的一点是你要明白计算机是如何表示小数的:

  • 比如二进制的「0.1111111」,无非就是十进制的「1/2 + 1/4 + 1/8 + 1/16 + 1/32 + 1/64 + 1/128」。

  • 不过细心的你可能已经发现问题了,计算机这种处理小数的方式存在精度损失的。

  • 比如一个十进制的「0.1」,换算成分数的话就是十进制的「1/10」。

  • 对比前面的结果,你会发现计算机没办法精确表示它,只能近似等于二进制的「0.00011」,也就是十进制的「1/16 + 1/32 = 3/32」,当然二进制小数点后可以多取几位。

可惜结果是只能无限趋近,但永远不可能等于。

最近上新

下面看看为什么「0.1 + 0.2 != 0.3」,而「0.1 + 0.3 == 0.4」。

既然存在精度损失,那么「0.1 + 0.2 != 0.3」也说得过去,我们推算一下为什么「0.1 + 0.3 == 0.4」:

  • 十进制的「0.1」近似等于二进制「0.00011」
  • 十进制的「0.3」近似等于二进制「0.01001」
  • 十进制的「0.4」近似等于二进制「0.01100」

于是,十进制的「0.1 + 0.3」也就是二进制的「0.00011 + 0.01001」:

  0.00011
+ 0.01001
---------
  0.01100

不多不少,答案正好是 0.4!

也就是说,虽然有精度损失,但是刚刚好碰巧抵消了彼此的误差。

希望大家阅读完本文之后,能够彻底搞清楚浮点数运算的相关问题。

如果还有不清楚的地方,推荐阅读:IEEE 754THE FLOATING-POINT GUIDE

觉得不错的话,记得点赞哦 ( ^_^)/

表情包

猜你喜欢

转载自www.cnblogs.com/fxyadela/p/11772730.html