Skip to content

Latest commit

 

History

History
230 lines (160 loc) · 5.54 KB

369-532046-[专业选修]浮点运算误差.sy.md

File metadata and controls

230 lines (160 loc) · 5.54 KB
show version enable_checker
step
1.0
true

浮点运算误差

回忆

  • 浮点数的单词来自于float
    • float 的意思是 浮动
    • 浮动的东西是小数点
    • 浮点数 就是 小数点可以浮动的 类型

图片描述

  • 浮点数 是 如何进行运算 的呢?🤔

小数细节

  • 小数使用基本上是 ok 的
    • 可以观察到1/3的结果
      • 被截取了小数

图片描述

  • 后面的计算结果没有问题
    • 但有时候也会出问题

观察

图片描述

  • 这显然不对!
  • 观察数据类型

图片描述

0.1

  • 3 个 $0.1$ 相加等于 $0.30000000000000004$
  • 观察 $0.1$

图片描述

  • 这个字节状态存储的0.1算出来
    • 确实比 $0.1$

图片描述

  • 加在一起确实超过 $0.3$🤪

双精度

图片描述

  • 这里我们使用的是
    • 双精度浮点数
    • double
    • 8-byte

图片描述

  • 我们先来看看
    • 和 的 双精度二进制形态

和的形态

  • $0.1+0.1+0.1$ 的双精度字节形态
    • \x34\x33\x33\x33\x33\x33\xd3\x3f
    • 8-byte

图片描述

  • \x34\x33\x33\x33\x33\x33\xd3\x3f 对应十进制
  • $0.30000000000000004$
  • 前后都能说通
  • 可是,这个和 $0.1$ 到底是怎么加的呢?

计算

  • 首先获得 $0.1$ 的双精度浮点型的二进制形态

图片描述

  • 刨去前面的符号位和指数部分
    • 还剩下总共 52 位 2 进制数
      • 如上图选中的数字部分
  • $1001100110011001100110011001100110011001100110011010$
    • (可复制到剪切板)

补位

  • 分成两部分

    • 有效数字
    • 指数
  • 有效数字

    • 前面有个缺省的 1
    • 把这 52 位 2 进制数前面补 1
    • 并加上小数点
      • $1.1001100110011001100110011001100110011001100110011010$

图片描述

  • 指数部分
    • -4
  • 综合起来就是
    • $1.1001100110011001100110011001100110011001100110011010$ x 2-4

运算

图片描述

  • 0.1原来的有效数字 乘以 3
    • 得到新的 有效数字
    • 此时的数值是原来的3倍
    • 大致是0.3
    • 数量级和原来差22

图片描述

  • ieee-754要求第1位必须有个缺省的1

    • 所以小数点要向左移动2位
    • 由于是2进制数
    • 小数点向左移动2位就相当于要除以 4
  • 综合起来就是

    • 要对有效数字
      • 先✖3
      • 再÷4

运算

  • 先算有效数字
    • 先粘贴有效数字部分
    • 再✖3÷4
    • 结果向上(ceil)取整
    • 并转化为2进制(binary)
    • 有效数字是(1.)0011001100110011001100110011001100110011001100110100
    • 去掉红框中的1
    • 保留后面的有效数字
    • 然后转化为 16 进制
      • $0x3333333333334$
    • 依然是 52 位 2 进制数
    • 共 13 位 16 进制数

图片描述

  • 指数部分 加2
    • 从3FB变成3FD
  • 整体是
    • 00111111 11010011 00110011 00110011 00110011 00110011 00110011 00110100
    • 0x3FD3333333333334

图片描述

  • 可复制出来去binaryconvert.com验证

验证

  • 通过系统中的字节状态进行验证

图片描述

  • $0.1+0.1+0.1$ 得到的 $0.30000000000000004$

图片描述

  • 结果和0.3在尾数上差一

直接对比

  • 对比直接进行的二进制编码

图片描述

  • 确实出现了误差

图片描述

  • 可以手算这个过程么?
  • 说干就干,走起来~

手算

图片描述

  • 把后 52 位复制出来

计算过程

  • 先移位
    • 相当于 乘以2
  • 在 与原数相加
    • 相当于 三次累加

图片描述

  • 第一步是移位
    • 两个一样的数相加
    • 左移 1 位
  • 然后再加上自身
    • 得到结果是尾数
  • 尾数以 $1.xxx$ 开头
    • 向右移动 2 位
    • 去掉开头的 1
  • 结尾多出两位
    • 有进位
    • 保持 52 位 尾数
  • 运算结果一致!!!

总结

  • 这次了解浮点类型变量
  • 有两种表示法
    • float 4-byte 单精度浮点型
    • double 8-byte 双精度浮点型
  • 浮点型特点
    • 第一位都是符号
    • 小数点都浮动
    • 浮动程度由指数部分决定
    • 尾数部分默认 1 开头
    • 后面的小数部分是有效数字
  • 这就是浮点类型的数据
  • 为什么 会有 float和double
    • 这样 存储数字的方法 呢?
  • 整体是如何进化的呢?🤪
  • 下次再说 👋