前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浮点数运算丢失精度

浮点数运算丢失精度

作者头像
烟草的香味
发布2021-01-06 10:16:21
9070
发布2021-01-06 10:16:21
举报
文章被收录于专栏:烟草的香味烟草的香味

浮点数运算丢失精度

今天碰到了这样一个情况, 使我又去翻阅了原来课本, 在Pthon中如果输入下面这段程序:

代码语言:javascript
复制
print(sys.float_info.max - 1.0)
print(sys.float_info.max)

结果如下:

结果发现, 这数字根本没有变化. 本来这没什么, 看这数字, 10的308次方, 也就是说, 减去的1是在308位之后了, 这里没有变化很正常嘛.

但是下面的现象就不能解释了:

代码语言:javascript
复制
a = sys.float_info.max - 1.0
b = sys.float_info.max
print(a == b)

结果显示, 两个数字完全一样, 这这这, 不行, 我得去回顾一下浮点数的表示.

小数的存储

如果要存储小数, 一般来说又两种保存方式.

1. 固定位数

将小数进行放大, 进行整数化, 然后保存整数. 如果固定知道是两位小数的话, 那么将小数乘以100, 就得到了一个对应的整数.

这种方式的前提是需要确切的知道小数的位数, 但是好在精度高, 在运算的时候不会造成误差. 比较适合保存金额等.

同时, 因为固定了位数, 不管你有没有小数, 都需要占用位数, 所以就导致在位数一定的情况下, 能够存储的最大值变小了.

2. 浮点数

但是, 在正常使用的时候, 通常是不知道小数的确切位数, 怎么办呢? 科学记数法想必都不陌生 a*b^n, 浮点数其实就是根据它来, 其存储结构如下(64位):

  • 符号位: 标识数字的正负
  • 指数: 2^n. 其中这个指数是分正负的哦, 也可以理解为小数点偏移量.
  • 基数: 规定基数是一个大于等于1, 小于2的数字, 也就是基数前面有一个隐含的默认1, 基数标识小数点后面的内容

那么问题来了, 基数隐含了一个默认的1, 那浮点数如何表示0呢?

  • 当指数为全0的时候, 若基数为全0, 则表示0.
  • 当指数为全1的时候, 表示无穷大.

同时, 因为位数的限制, 并不能保存无穷大的数字, 包括无限小数, 就比如0.1

简单回顾一下, 足够解释今天的奇怪现象了.

再看

回顾了小数的保存之后, 再来回看之前的, 为什么浮点数最大值, 减去1之后, 本身没有任何变化呢?

要回答这个问题, 还需要知道两个浮点数在计算机中是如何进行计算的. 在两个浮点数进行运算的时候, 要先将指数部分保持一致, 然后再进行相应的运算, 也就是说:

1.0*10^4 + 1.0*10^2 要转换成: 1.0*10^4 + 0.01*10^4

如此, 上面的最大值, 其指数部分为 2^1023. 所以, 要将浮点数1.0进行转换, 而这个数字要想转换成相同指数的话, 其基数部分就要后移1023位, 导致溢出, 就变成0了. 所以就相当于和0做运算, 其结果不变.

如此说来, 浮点数的指数在进行转换的时候, 岂不是很容易丢失精度? 还真是, 看这个例子:

代码语言:javascript
复制
a = 1.0
b = 0.12345678
c = 0.11111111

s = 0.0
s += a
s += b
s += c

print(s)

s +=  10000000.0
s += -10000000.0
print(s)

可以看到, 在开始数字之间相差不大的时候, 结果还是正确的. 但是之后只是对同一个数字做了一次加减, 就导致发生其精度丢失了. 其原因同样是因为在计算中对指数部分统一导致的.

为了验证我的猜想, 只要将计算顺序修改, 当 s 变量还没有小数部分, 不至于丢失精度的时候进行大数的运算:

代码语言:javascript
复制
a = 1.0
b = 0.12345678
c = 0.11111111

s = 0.0
s += a
s +=  10000000.0
s += -10000000.0
s += b
s += c

print(s)

这时, 计算结果印证了之前的讨论. 如此说来, 小数在两个相差很多的数字之间进行运算的时候, 也容易导致丢失精度.

同时, 因为浮点数能表示的范围比整数要大, 在转整数的时候, 也可能会造成丢失.


最终搞懂了这个看似奇怪的现象, 唉, 基础还是不够啊.

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-01-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 烟草的香味 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 浮点数运算丢失精度
  • 小数的存储
    • 1. 固定位数
      • 2. 浮点数
      • 再看
      相关产品与服务
      对象存储
      对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档