zoukankan      html  css  js  c++  java
  • 【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

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

    表情包
  • 相关阅读:
    在Centos7下源代码安装配置Nginx
    mysql5.7.21源码安装
    数据库设计三大范式
    电商项目中使用Redis实现秒杀功能
    PHP和Redis实现在高并发下的抢购及秒杀功能示例详解
    PHP面向对象(抽象类与抽象方法、接口的实现)
    php面向对象 封装继承多态 接口、重载、抽象类、最终类总结
    利用VHD虚拟文件加密自己的个人信息
    Chrome常用快捷键
    stl本子
  • 原文地址:https://www.cnblogs.com/fxyadela/p/11772730.html
Copyright © 2011-2022 走看看