惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
博客园 - Franky
博客园 - 司徒正美
Stack Overflow Blog
Stack Overflow Blog
GbyAI
GbyAI
Y
Y Combinator Blog
Microsoft Azure Blog
Microsoft Azure Blog
Blog — PlanetScale
Blog — PlanetScale
博客园 - 叶小钗
罗磊的独立博客
The GitHub Blog
The GitHub Blog
H
Help Net Security
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Engineering at Meta
Engineering at Meta
Martin Fowler
Martin Fowler
Spread Privacy
Spread Privacy
Google DeepMind News
Google DeepMind News
AWS News Blog
AWS News Blog
N
Netflix TechBlog - Medium
T
The Exploit Database - CXSecurity.com
云风的 BLOG
云风的 BLOG
小众软件
小众软件
aimingoo的专栏
aimingoo的专栏
Cyberwarzone
Cyberwarzone
T
Threatpost
T
Threat Research - Cisco Blogs
Recent Announcements
Recent Announcements
T
Tor Project blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Last Week in AI
Last Week in AI
L
Lohrmann on Cybersecurity
量子位
V
V2EX
V
Vulnerabilities – Threatpost
L
LINUX DO - 热门话题
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Proofpoint News Feed
I
Intezer
Schneier on Security
Schneier on Security
雷峰网
雷峰网
B
Blog RSS Feed
Jina AI
Jina AI
爱范儿
爱范儿
Attack and Defense Labs
Attack and Defense Labs
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Palo Alto Networks Blog
美团技术团队
博客园 - 【当耐特】

熊言熊语

焦虑的反面是具体:用3年AI实践和你分享这份AI科研心得指南 | 熊言熊语 因为 AI 终于我可以尝试把自己最好的东西给你 | 熊言熊语 Guardant Shield 获批:详谈这5年你该了解的按部就班、跌跌撞撞 、布局和野望 | 熊言熊语 除了E人变I,断网半年后我的3个感悟和1个项目 | 熊言熊语 同源重组修复缺陷HRD :产品总览 | 熊言熊语 同源重组修复缺陷HRD:临床验证 | 熊言熊语 同源重组修复缺陷HRD:从无到有 | 熊言熊语 聊肿瘤生物标志物时我们在聊什么 | 熊言熊语 肿瘤组织和液体活检结果不一致,好事还是坏事 | 熊言熊语 肿瘤精准治疗究竟多难 看这7个临床实践障碍 | 熊言熊语 关于wolai被钉钉收购:多研究些问题少谈些逻辑 | 熊言熊语 MSKCC 尚待解决的肿瘤基因组检测临床应用问题 | 熊言熊语 不要错过的14档肿瘤研究专业相关播客 | 熊言熊语 从靶向治疗耐药机制到联合用药策略(下篇) | 熊言熊语 那些获得FDA突破性设备认证的多癌种早筛公司 | 熊言熊语 2022的混乱和坚持 2023的困难和勇敢 | 熊言熊语 从靶向治疗耐药机制到联合用药策略(上篇) | 熊言熊语 和头部肿瘤早筛公司 GRAIL CEO 学写年终工作总结 | 熊言熊语 2022年肿瘤精准治疗进展回顾 看OncoKB和FDA审批就够了 | 熊言熊语 Foundation Medicine 42万例样本库分析KRAS泛癌种突变特征得出了这些结论 | 熊言熊语 从2002年的Nature论文到2022年的亿元营收 | 熊言熊语 肿瘤NGS行业新人如何构建自己的知识体系 | 熊言熊语 Nature Genetics:低TMB患者福音 肿瘤非整倍体可预测泛癌免疫治疗疗效 | 熊言熊语 Nature Cancer:高度非整倍体非小细胞肺癌 放疗同步免疫治疗更敏感 | 熊言熊语 Nature Reviews Cancer:未来10年肿瘤精准治疗的6个未解之谜 | 熊言熊语 通过一份会议日程多了解点液体活检 | 熊言熊语 找到一种和这个世界沟通的方式 | 熊言熊语 跨越60年的癌症靶向治疗里程碑 | 熊言熊语 同样做肿瘤NGS检测,美股上市的9家公司近况如何 | 熊言熊语 30 岁,让我们成熟和改变的不是生日而是生活 | 熊言熊语 ctDNA系列之一:ctDNA的生物学特征、检测技术问题和临床应用方向 | 熊言熊语 在《Google软件工程》里了解如何在团队内进行学习和分享 | 熊言熊语 如何衡量个人在团队项目中的贡献 | 熊言熊语 万字长文|染色体不稳定性,凭什么2022年还能用TCGA数据发Nature | 熊言熊语 FDA发布ctDNA应用于早期实体瘤药物开发的指导意见 | 熊言熊语 单平台文章阅读量超过100万,我可能做对了三件事。 | 熊言熊语 Gitee图床被禁?云对象存储配合CDN方案以及图片批量迁移方法 | 熊言熊语 别再用DEseq2和edgeR进行大样本差异表达基因分析了 | 熊言熊语 春天来了,但你得准备好继续过冬 | 熊言熊语 任务如何才能按时完成 | 熊言熊语 从肿瘤突变列表到辅助临床决策 | 熊言熊语 半年毕业 半年工作 我的2021年度总结 | 熊言熊语 你也可以在学术报告中讲好一个引人入胜的故事 | 熊言熊语 OncoSearch 肿瘤研究必备(自用)聚合搜索工具 | 熊言熊语 读陌生领域文献,我劝你别读正文 | 熊言熊语 准备两个版本的PPT | 熊言熊语 通往更好的决定 | 熊言熊语 更多地写 但是写的更短 | 熊言熊语 问题出现我再告诉大家 | 熊言熊语 重做新人 NGS肿瘤领域可以学些什么 | 熊言熊语 新手和专家的区别以及如何看待学习 | 熊言熊语 完成这个需要多长时间 | 熊言熊语 从 MacBook Pro M1 安装编译 R 踩坑想到的 6年硕博生活的6条心得-生活成长篇 | 熊言熊语 面对职业教育缺失,在科研行业的我们能做什么 | 熊言熊语 全球顶尖科学家榜单 | 熊言熊语 构建自己的数字花园-工具篇 | 熊言熊语 使用R语言分析上海地铁好位置周边的二手房价格 | 熊言熊语 熊言熊语会员通讯 4321X 第5期 | 熊言熊语 关于 wolai 这款工具的观察与困惑 | 熊言熊语 关于个人的认知不确定性 | 熊言熊语 需要时刻留心的24个生物信息学提示 | 熊言熊语 要不要读博(答读者信) | 熊言熊语 熊言熊语会员通讯 4321X 第3期 | 熊言熊语 用三个问题回顾 2020(全员协作版) | 熊言熊语 熊言熊语会员通讯 4321X 第2期 | 熊言熊语 熊言熊语会员通讯 4321X 第1期 | 熊言熊语 熊言熊语会员通讯 4321X 第0期 阅读与分享 | 熊言熊语 有备而来的 4321X | 熊言熊语 macOS big sur 升级后编译 R 的问题 你的实验伴侣摸鱼首选和通勤第一品牌 | 熊言熊语 如何帮助别人 | 熊言熊语 21天日记挑战-5分钟日记法 | 熊言熊语 使用 Zotero 在 Markdown 中优雅地处理参考文献 三个 Linux 文件高频小操作 | 熊言熊语 VS Code 代码编辑器入门指南下篇-场景化应用介绍 | 熊言熊语 VS Code 编辑器入门指南上篇-核心概念与组件 | 熊言熊语 把 Markdown 模板做成 VSCode 插件 简书这些年 | 熊言熊语 靠谱熊的每周分享 第4期 | 熊言熊语 靠谱熊的每周分享 第3期 | 熊言熊语 非蠢既坏 别这么想 | 熊言熊语 靠谱熊的每周分享 第2期 | 熊言熊语 R 的 20 年 | 熊言熊语 靠谱熊的每周分享 第1期 | 熊言熊语 停课不停学 推荐 7 门有趣实用的线上课程 | 熊言熊语 在家复工,学生党如何使用学术资源 | 熊言熊语 跨平台协作,让飞书实时接收语雀更新提醒 | 熊言熊语 特殊时期假期返程实录 | 熊言熊语 需要远程办公,不妨用 Trello 进行组织和协作 | 熊言熊语 学习素材共享小组V2.0(已停止招募) | 熊言熊语 Trello 看板内容太多,飞书表格帮你自动整理 | 熊言熊语 把飞书融入日常学习流程:一个人的飞书也挺好 | 熊言熊语 人究竟怎样才算来过又怎样才算离开 | 熊言熊语 使用 VSCode 愉快地进行远程 R 开发 给一年前自己的一封信-2019 | 熊言熊语 如何简快好省的使用图床 | 熊言熊语 这三个网站让我摸鱼都从容了 | 熊言熊语 我目前的云存储方法 | 熊言熊语
眼见不为实:为什么29不等于29 | 熊言熊语
2019-12-19 · via 熊言熊语

2019-12-19, 1703 words, 7 min read

浮点数计算和比较的坑

29 怎么会不等于 29

今天有一个小伙伴给我发来了一个截图如下。我下意识的说了一句:0.58*50 不等于 29。

感概,有时候,眼见也不一定为实。这就是一个浮点运算导致的「算不准」问题。

在历史上,其实已经有过类似因为浮点运算导致的事故。

1994 年,英特尔的奔腾微处理器芯片的浮点计算单元出现了一个 Bug。在某些情况下,浮点除法并不能返回正确的结果。例如 4195835.0/3145727.0 产生的是 1.33374 而不是 1.33382。虽然这个 Bug 可能对绝大多数人没有影响,但是市面上 500 万左右流通的芯片都存在该缺陷,随着整个事件的发酵,最终这个 Bug 给 intel 造成了 4.75 亿美元的损失。这次事件也被称为「Pentium FDIV bug」而载入了 Bug 史册。

R 语言中的实际示例

我们分别在 R 中计算 0.58*50,0.29*100,然后让他们和 29 互相比一比。

(a=29)
(b=0.58*50)
(c=0.29*100)
a==c
a==b
b==c

结果如下所示:

> (a=29)
[1] 29
> (b=0.58*50)
[1] 29
> (c=0.29*100)
[1] 29
> a==c
[1] FALSE
> b==c
[1] TRUE
> a==b
[1] FALSE

我们看到屏幕上显示的 a , b 和 c 都是 29,但是如果用==进行一下比较,发现0.58*500.29*100竟然都不等于 29。嗯,很迷。

浮点数的精度和计算问题,在任何编程语言里都类似。

浮点数在计算机中不能以任意精读存储,都会有一个准确性的限制,通过有限的连续字符来保存浮点数。

目前常见的浮点格式包括:单精度,双精度和扩展双精度。他们的准确性从前到后依次提高,其中单精度可以用于一般计算,双精度用于科学计算。在 R 中就是采用了双精度来对浮点数进行保存。如下所示:

> (d <- 10)
[1] 10
> class(d)
[1] "numeric"
> typeof(d)
[1] "double"

我们让 d 等于 10,通过 class 可以看出它是一个数值型变量,如果用 typeof 查看,就会发现他的存储模式(storage mode)是一个双精度浮点型数字。

这里又涉及到了存储模式和类型的问题。在 R 中class返回的是一个对象的高级类,而typeof返回的是对象的内部低级类。如果用calss查看一个数据框,其返回结果就是他的类(calss)为数据框,如果使用typeof查看,返回的结果就是内部类型为列表,如下所示。(嗯,想起了果子老师课上讲的,data.frame 就是一种特殊的 list)

> class(iris)
[1] "data.frame"
> typeof(iris)
[1] "list"

继续回来说浮点数的比较。因为精度问题,在 R 语言中使用 == 进行浮点数的比较是非常危险的。

就像文章开头的例子,此时假设你有一个 if 语句,想进行一下结果的判断。如果判断条件是 0.29*100 == 29,就会返回 F。因为 0.29*100 的实际值在计算机中比 29 要小一些。当你使用 as.interger去处理的时候,结果为 28。

> as.integer(0.29*100)
[1] 28

这也就是为什么rep(1,29)有 29 个数字,但是rep(1,0.29*100)有 28 个数字。

如何避免浮点数计算的坑

如何解决这个问题呢?在 R 语言中有一个函数叫做 all.equal,虽然名字是 equal,但是他其实是 almost equal。

这让我不禁想到了一款果子和洲更(当然还有我)都在用全面屏 Almost 手机。

all.equal() 的功能是 Test If Two Objects Are (Nearly) Equal。也就是它可以略微忍受两个对象之间有一丢丢差别。如下所示:

> (a=29)
[1] 29
> (b=0.58*50)
[1] 29
> (c=0.29*100)
[1] 29
> a==b
[1] FALSE
> all.equal(a,b)
[1] TRUE
> a==c
[1] FALSE
> all.equal(a,c)
[1] TRUE

你可能会问,这个一丢丢究竟是多少呢?

通过帮助文档,我们可以发现这个一丢丢实际是tolerance = sqrt(.Machine$double.eps)。如果实际运行一下会发现.Machine$double.eps 等于 2.220446e-16,那么sqrt(.Machine$double.eps)就是 1.490116e-08。

这里的.Machine是一个存储了 R 正在运行机器的数值特性的变量,其中包括了最小正浮点数(double.eps)。因此,以后想进行类似的比较,记得使用all.equal()。另外,多说一句,在 if 判断中不要直接使用它,而是写成 isTRUE(all.equal(....))

回到最开始的问题,如果确实需要 rep(1,rep(1,0.29*100))返回 29 个数字,就可能需要用到取整。

在 R 中有 3 种常见的取整,分别是:

  • 向下取整:floor()
  • 向上取整:ceiling()
  • 四舍五入:round()

此外还有一种不常用的「向 0 看齐」取整方法trunc()

他们的差别如下:

> ( x1 <- seq(-2, 4, by = .5) )
 [1] -2.0 -1.5 -1.0 -0.5  0.0  0.5  1.0  1.5  2.0  2.5  3.0  3.5  4.0
> floor(x1)
 [1] -2 -2 -1 -1  0  0  1  1  2  2  3  3  4
> ceiling(x1)
 [1] -2 -1 -1  0  0  1  1  2  2  3  3  4  4
> round(x1)
 [1] -2 -2 -1  0  0  0  1  2  2  2  3  4  4
> trunc(x1)
 [1] -2 -1 -1  0  0  0  1  1  2  2  3  3  4

因此通过rep(1,round(0.58*50))就可以得到和rep(1,29)一致的结果了。

写到这里并没有结束,因为如果用 python 算一下,就会发现 0.58*100 真的不等于 58。感觉 R 语言的对于浮点运算结果的展示还是有点问题?同时,0.58 和 0.59 还是不一样。

>>> 0.58*100
57.99999999999999
>>> 0.59*100
59.0
>>> 0.57*100
56.99999999999999
>>> 0.56*100
56.00000000000001

看来,要知其所以然,还得再仔细学习一下浮点精度和计算的实质。


参考资料:
R FAQ 7.31


本文作者:思考问题的熊

版权声明:本博客所有文章除特别声明外,均采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (CC BY-NC-ND 4.0) 进行许可。

如果你对这篇文章感兴趣,欢迎通过邮箱订阅我的 「熊言熊语」会员通讯,我将第一时间与你分享肿瘤生物医药领域最新行业研究进展和我的所思所学所想点此链接即可进行免费订阅。

· 分享链接 https://kaopubear.top/blog/2019-12-19-rfloat/