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

浮点数原理与精度损失问题

作者头像
TOMOCAT
发布2020-10-29 11:14:43
2.7K0
发布2020-10-29 11:14:43
举报

写在前面

碰巧最近定义接口的时候碰到了浮点数精度的问题,稍微整理了浮点数的一些知识点:

  • 浮点数的底层表示
  • 浮点数的精度损失问题
  • 浮点数的表示范围和精度

小数的二进制表示

指数部分决定了数的大小范围,有效数字部分决定了数的精度。

举两个简单的例子:

十进制

二进制

二进制科学计数法

S

E

M

3.0

11.0

1.1 x 2^1

0

1

1.1

-5.0

-101.0

-1.01 x 2^2

1

2

1.01

浮点数在计算机底层的存储机制

double类型和float类型(可能还有long double类型)在计算机的底层存储结构都是一致的,唯一的不同在于float是32位而double是64位的。

无论什么数据,在计算机内存中都是以01存储的,浮点数也不例外。

0. 定点数

计算机中小数的表示按照小数点的位置是否固定可以分为浮点数和定点数。为了方便和float32浮点数做对比,我们构造一个32位精度的定点数,其中小数点固定在23bit处:

定点数的底层表示

从定点数的存储上看,它表示的数值范围有限(以小数点在23bit为例,整数部分仅有8位,则整数部分取值范围是0~255),但好在处理定点数计算的硬件比较简单。

1. IEEE 754x浮点数

以32位浮点数为例,最高一位是符号位s,接着的8位是指数位E,最后的23位是有效数字M。double64最高一位是符号位,有11个指数位和52个有效数字位。下图展示了float32类型的底层表示:

float的底层表示

其中IEEE 754的规定为:

  • 因为M的取值一定是
1\leq M<2
1\leq M<2

,因此规定M在存储时舍弃第一个1,只存储小数点之后的数字,这样可以节省存储空间(以float32为例,可以保存23位小数信息)

  • 指数E是一个无符号整数,因此它的取值范围为0到255,但是指数可以是负的,所以规定在存入E时在它原本的值加上127(使用时减去中间数127),这样E的取值范围为-127到128
    • E不全为0,不全为1:正常的计算规则,E的真实值就是E的字面值减去127(中间值),M加回1
    • E全为0:指数E等于1-127为真实值,M不加回1(此时M为0.xxxxxx),这样是为了表示0和一些很小的数
    • E全为1:M全为0表示正负无穷大(取决于S符号位);M不全为0时表示不是一个数(NaN)
2. 具体例子

以78.375为例,它的整数和小数部分可以表示为:

(78)_{10} = (1001110)_{2} \\ (0.375)_{10} = \frac{3}{8} = \frac{1}{4} + \frac{1}{8} = 2^{-2} + 2^{-3} = (0.01)_2 + (0.001)_2 = (0.011)_2
(78)_{10} = (1001110)_{2} \\ (0.375)_{10} = \frac{3}{8} = \frac{1}{4} + \frac{1}{8} = 2^{-2} + 2^{-3} = (0.01)_2 + (0.001)_2 = (0.011)_2

因此二进制的科学计数法为:

(78.375)_{10} = (1001110.011)_2 = 1.001110011 \times 2^6
(78.375)_{10} = (1001110.011)_2 = 1.001110011 \times 2^6

按照前面IEEE 754的要求,它的底层存储为:

3. 精度损失

十进制中的0.5(代表分数1/2)表示二进制中的0.1(等同于分数1/2),我们可以把十进制中的小数部分乘以2作为二进制的一位,然后继续取小数部分乘以2作为下一位,直到不存在小数为止。以0.2这个无法精确表示成二进制的浮点数为例:

0.2 \times 2 = 0.4 \rightarrow 0 \\ 0.4 \times 2 = 0.8 \rightarrow 0 \\ 0.8 \times 2 = 1.6 \rightarrow 1 \\ 0.6 \times 2 = 1.2 \rightarrow 1 \\ 0.2 \times 2 = 0.4 \rightarrow 0 \\ ...... \\ (0.2)_{10} = (0.00110...)_{2}
0.2 \times 2 = 0.4 \rightarrow 0 \\ 0.4 \times 2 = 0.8 \rightarrow 0 \\ 0.8 \times 2 = 1.6 \rightarrow 1 \\ 0.6 \times 2 = 1.2 \rightarrow 1 \\ 0.2 \times 2 = 0.4 \rightarrow 0 \\ ...... \\ (0.2)_{10} = (0.00110...)_{2}

因此十进制下的0.2无法被精确表示成二进制小数,这也是为什么十进制小数转换成二进制小数时会出现精度损失的情况。

浮点型表示精度和范围

Reference

[1] https://q.115.com/182920/T1268124.html

[2] https://blog.csdn.net/u014470361/article/details/79820892

[3] https://www.cnblogs.com/wangsiting1997/p/10677805.html

[4] https://blog.csdn.net/u014470361/article/details/79820892

[5] https://www.cnblogs.com/yiyide266/p/7987037.html

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

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