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

浮点数运算丢失精度

作者头像
烟草的香味
发布于 2021-01-06 02:16:21
发布于 2021-01-06 02:16:21
99000
代码可运行
举报
文章被收录于专栏:烟草的香味烟草的香味
运行总次数:0
代码可运行

浮点数运算丢失精度

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
print(sys.float_info.max - 1.0)
print(sys.float_info.max)

结果如下:

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
浮点数精度问题透析:小数计算不准确+浮点数精度丢失根源
之前自己答的不是满意(对 陈嘉栋的回答 还是满意的),想对这个问题做个深入浅出的总结
周陆军
2019/05/17
3K0
什么是浮点数?
简单回顾一下,简单来说,用定点数表示数字时,会约定小数点的位置固定不变,整数部分和小数部分分别转换为二进制,就是定点数的结果。
_Kaito
2021/03/23
1.4K0
什么是浮点数?
浮点数在计算机中的精度问题
不论大家使用的是什么编程语言想必都知道浮点数在计算机中存在一定的精度问题,特别是有float类型的编程语言中,大部分编程都是建议直接使用更高精度的double类型。下面我做的示例都以python为主。
不知名小白
2025/01/09
1570
浮点数的秘密
我们在学习 C 语言时,通常认为浮点数和小数是等价的,并没有严格区分它们的概念,这也并没有影响到我们的学习,原因就是浮点数和小数是绑定在一起的,只有小数才使用浮点格式来存储。
C语言与CPP编程
2020/10/20
6130
连科班生都少有关注的【浮点数】问题!
但用定点数表示小数时,存在数值范围、精度范围有限的缺点,所以在计算机中,我们一般使用「浮点数」来表示小数。
程序视点
2023/12/06
3550
连科班生都少有关注的【浮点数】问题!
浮点数比较的精度问题
如果变量 a , b 换 0.75 , 0.5 可以看出运行出 c == 1.25 ,说明浮点数运算是不稳定的。
C语言与CPP编程
2020/12/02
1.7K0
浮点数比较的精度问题
常用的数学函数以及浮点数处理函数
在编程中我们总要进行一些数学运算以及数字处理,尤其是浮点数的运算和处理,这篇文章主要介绍C语言下的数学库。而其他语言中的数学库函数的定义以及最终实现也是通过对C数学库的调用来完成的,其内容大同小异,因此就不在这里介绍了。 C语言标准库中的math.h定义了非常多的数学运算和数字处理函数。这些函数大部分都是在C89标准中定义的,而有些C99标准下的函数我会特殊的说明,同时因为不同的编译器下的C标准库中有些函数的定义有差别,我也会分别的说明。
欧阳大哥2013
2018/08/22
2.6K0
常用的数学函数以及浮点数处理函数
图解计算机中的数值范围和浮点数运算
作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址:
冰河
2021/02/05
1.2K0
图解计算机中的数值范围和浮点数运算
浮点数与IEEE 754标准浅谈
浮点数是一种用于表示实数的数值表示形式,它使计算机能够处理非常大的或非常小的数值。例如,在科学计算中,我们经常需要处理像 6.022 × 10^23 这样的数字,使用浮点数表示可以极大地提高计算的灵活性和效率。
一条晒干的咸鱼
2024/11/19
4660
浮点数与IEEE 754标准浅谈
ieee754标准一个浮点数由什么组成_某数采用ieee754单精度浮点数格式
FBI WARNING:鄙人首个开源电子书 《Go 编码建议》已经上线啦,欢迎各位大佬斧正指导,协同共建。
全栈程序员站长
2022/11/03
1K1
深入理解C++中的浮点数:内存模型、精度损失原理与提升方法
浮点数(float 和 double)在C++中被广泛用于处理需要小数表示的计算问题。然而,由于浮点数基于二进制表示,存在许多容易被忽略的陷阱,比如精度损失和比较问题。本文将详细介绍浮点数的内存模型、精度损失的根源、浮点数比较技巧以及提高精度的实用方法。
码事漫谈
2024/12/26
2880
深入理解C++中的浮点数:内存模型、精度损失原理与提升方法
IEEE754浮点数的表示方法
浮点数(Floating-point Number)是一种对于实数的近似值数值表现法,由一个有效数字(即尾数)加上幂数来表示,通常是乘以某个基数的整数次幂得到。以这种表示法表示的数值,称为浮点数。表示方法类似于基数为10的科学计数法。利用浮点进行运算,称为浮点计算,这种运算通常伴随着因为无法精确表示而进行的近似或舍入。
恋喵大鲤鱼
2018/08/03
3.2K0
IEEE754浮点数的表示方法
Java细节:浮点数精度丢失问题的原因
我们知道整数类型没有精度丢失的问题,但是浮点数有精度丢失的问题,下面我们来探究一下其精度丢失的原因所在。
鲲志说
2025/04/07
1330
Java细节:浮点数精度丢失问题的原因
浮点数详解
        关于浮点数,很多人只是知道浮点数就是小数,简单来说,因为所有的小数都可以用科学计数法来表示,而小数点可能也会随之发生“浮动”,故称之为浮点数。举个例子,有这样一个数字:1999.99,如果用科学计数法表示则为1.99999*10^3,在这个过程中我们很明显地看到了小数点发生了“浮动”,浮点数的名字也由此得来。
用户11070251
2024/04/11
2K0
浮点数详解
理解浮点数
相信大家在平常的 JavaScript 开发中,都有遇到过浮点数运算精度误差的问题。
QQ音乐前端团队
2018/12/09
2.6K0
理解浮点数
JavaScript 浮点数之迷:0.1 + 0.2 为什么不等于 0.3?
“0.1 + 0.2 = ?” 这个问题,你要是问小学生,他也许会立马告诉你 0.3。但是在计算机的世界里就没有这么简单了,做为一名程序开发者在你面试时如果有人这样问你,小心陷阱喽! 你可能在哪里见过
五月君
2020/02/19
4.2K0
整数和浮点数在内存中的存储​(大小端详解)
在讲解操作符的时候,我们就讲过了下面的内容: 整数的2进制表示方法有三种,即 原码、反码和补码​ 三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位最 高位的一位是被当做符号位,剩余的都是数值位。 正整数的原、反、补码都相同。
走在努力路上的自己
2024/01/26
9920
整数和浮点数在内存中的存储​(大小端详解)
[六]基础数据类型之浮点数简介
Java中,基本数据float 和double的包装类Float和Double都是浮点类型
noteless
2018/10/11
6510
[六]基础数据类型之浮点数简介
浮点数的运算精度丢失
1/5,使用小数表示为0.2,但是1/3,使用小数表示就是一个无限循环小数:0.3333333, 也就是说,分数的 1/3+1/3=2/3,但如果使用小数:0.3333+0.3333=0.6666, 结果只会无限接近2/3,而不会等于2/3
烟草的香味
2019/10/29
2K0
对浮点数的一些理解
相比int等整型,float等浮点类型的表示和存储较为复杂,但它又是一个无法回避的话题,那么就有必要对浮点一探究竟了。在计算机中,一般用IEEE浮点近似表示任意一个实数,那么它实际上又是如何表示的呢?
编程珠玑
2019/09/04
5520
对浮点数的一些理解
相关推荐
浮点数精度问题透析:小数计算不准确+浮点数精度丢失根源
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验