浮点运算结果不准确算不算是 bug?任何人都不想得到不准确的结果吧

2020-01-11 22:29:43 +08:00
 litianyou

最近开发时遇到一个问题就是关于“浮点运算结果不准确”的问题,很多开发语言中都有这个问题,进而衍生出了一些类库去专门解决浮点运算偏差。

我很好奇,开发人员应该没有人希望得到一个不稳定、不准确的结果,那么保留这个“浮点运算不准确”的特性有什么特殊意义吗?如果没有特殊意义,那么“浮点运算结果不准确”是不是 Bug 呢?如果是 Bug 的话为什么至今仍然有很多开发语言有这个问题呢?

请各位有经验的大佬说说原因?

8597 次点击
所在节点    程序员
81 条回复
mxT52CRuqR6o5
2020-01-12 00:25:31 +08:00
@lance6716 宁觉得楼主所说的浮点运算不准指的是这个吗?楼主说的解决浮点运算偏差的类库是可以解决 sqrt(2)没法准确表达的?
Sketch
2020-01-12 00:37:47 +08:00
是的,我清楚本贴的原意是指类似这些有理数的运算,我只是想反驳“二进制浮点数的精确表达”这一点。但同时,即使在二进制下,我们依然无法通过有限位数精确表示 1/3,1b/11b 的值,0.01010101...b,而只能获取一个近似值,即浮点运算结果的不准确
@ljpCN
@mxT52CRuqR6o5
Vegetable
2020-01-12 01:06:32 +08:00
服了,还有拿无理数出来讨论的,我怕一会儿虚数什么的都出来了
lance6716
2020-01-12 01:11:31 +08:00
@mxT52CRuqR6o5
> 宁觉得楼主所说的浮点运算不准指的是这个吗?
是的。加法,乘法,整数次幂,有理数次幂,都是“运算”
> 楼主说的解决浮点运算偏差的类库是可以解决 sqrt(2)没法准确表达的
没读懂。宁给我断断句?
Raymon111111
2020-01-12 01:27:31 +08:00
?

上课好好听课
mxT52CRuqR6o5
2020-01-12 01:42:10 +08:00
@lance6716
@litianyou
楼主能说一下标题所说的浮点运算结果不准确指的是 0.1+0.2≠0.3 还是指上面这位兄弟说的 sqrt(2)算不准
feather12315
2020-01-12 01:47:00 +08:00
这个问题用数学集合相关的概念解释啊。
不是进制的问题,核心在与:同#5 的解释 -- 数是无限的,但是用于表示的东西是有限的。自然数扩充为整数,整数加上有限小数是有理数,有理数加上无理数是实数,实数之外还有虚数。

一个数轴,自然数都表示不全,指望着表示所有的实数?更何况还有虚数。

数学 /物理中有个概念:误差。在使用小数进行计算的时候,会要求误差控制在多少个小数点后面。高中物理都有,分别对比保留到保留小数点后面 M / N 位的误差。求小数点 N 位的时候,不都是在计算过程中使用 N+1,或者 N+位计算,甚至分数么?

使用小数计算,人为都做不到 100%精确,怎么到计算机这就是个 bug 了?
mxT52CRuqR6o5
2020-01-12 02:05:44 +08:00
@feather12315 0.1+0.2≠0.3
mxT52CRuqR6o5
2020-01-12 02:09:30 +08:00
@lance6716 sqrt(2)的结果你也没法用一个十进制数准确表达,这又不是计算机产生的问题,想要准确表达 sqrt(2)在 X 进制表数法下只能保留根号
lance6716
2020-01-12 02:14:35 +08:00
@mxT52CRuqR6o5 等一下,有的语言 0.1+0.2≠0.3,sqrt(2)^2≠2。有的语言(库) 0.1+0.2=0.3,sqrt(2)^2=2。人是“后者那种语言”,因为人是按照“符号”计算的,可以避免好多“精度丢失”,一般的程序语言在原理上都属于前者。
完了 Jojo 看多了真喜欢用引号
lance6716
2020-01-12 02:17:58 +08:00
@mxT52CRuqR6o5 sqrt(2)的结果确实没法用一个十进制数准确表达,但是我们都知道 sqrt(2)^2=2。这应该跟 0.1+0.2=0.3 是同一个问题吧
feather12315
2020-01-12 02:18:21 +08:00
@mxT52CRuqR6o5 #29 等不等于,这个得看误差的范围。在数学的意义上,0.9999… (无限循环)等价于 1.0,可以被证明。
msg7086
2020-01-12 02:19:14 +08:00
因为浮点数记录的是数字立即量本身,而立即量只能精确存储有限不循环小数(且精度受限)。

十进制本身也不能在有限精度内做循环小数运算。
比如三分之一,取 3 位小数是 0.333 ,乘上 3 以后是 0.999 ,一样会产生 0.001 的误差。

要精确计算循环小数需要用比例类型,存储 1 和 3 而不是 0.333 。
msg7086
2020-01-12 02:31:30 +08:00
再换一种说法,二进制中浮点数是无法存储 0.1 和 0.2 的。你看到的 0.1 和 0.2,他们其实是:

0.1000000000000000055511151231257827021181583404541015625

0.200000000000000011102230246251565404236316680908203125

他们相加以后就会变成:
0.3000000000000000444089209850062616169452667236328125
(这里由于精度损失所以加出了 444 而不是 166。)

而真正的 0.3 应该是:
0.299999999999999988897769753748434595763683319091796875

前者比后者大了整整:
0.000000000000000055511151231257827021181583404541015625

因此造成了计算误差。
502badgateway
2020-01-12 02:34:56 +08:00
0.5,0.25,0.125,0.0625……还有他们的和是能准确表示的啊……有的就不能,这不就是二进制的限制么?现代计算机的基础就是门电路,等量子计算机出来了就不存在这个问题了(雾
msg7086
2020-01-12 02:42:12 +08:00
至于精确运算,一般就交给大整数或者大实数类库来做。
一般用浮点而不用高精度运算主要还是为了效率,毕竟大多数人并不在意小数点后 10 位的误差。
大数运算相比硬件浮点,即使是最快的类库也要比 double 慢一倍,所以还是让程序员主动选用为主。
tianshilei1992
2020-01-12 03:40:35 +08:00
有一个本质是,整数只要有 1,就可以表示任何数字,因为 1 是整数的最小不可分单元。而小数却不存在这个东西,你可以任意指定一个很小的数。因此小数就有了精度这个东西了,然后一个很自然的 trade off 就出现了:性能 vs 精度。这么多年 IEEE 一直没有推出更高精度的浮点数,反而 FP16 却被硬件更多的支持,这就是一个*大家需要的*精度 vs 运算速度的 trade off。甚至是,现在各大硬件厂商都在专门做 int8 的指令,一个原因就是,大家发现,ML/DL 很多时候 int8 也就够了…
itskingname
2020-01-12 08:09:16 +08:00
楼上各位认真解释的同学,你们知道鸽子为什么这么大的梗吗?不要给他们解释了。他们不想听真正正确的答案。
churchmice
2020-01-12 09:48:11 +08:00
@litianyou 好好看看计算机组成就不会问这么多问题了,也不用浪费时间在发帖扯蛋上面了

看书十分钟,论坛吹水一整天
conn4575
2020-01-12 09:50:52 +08:00
要不你来开发一个可以准确计算浮点数且性能和现在的浮点数计算差不所的系统?其中包括重新设计二进制、CPU、所有的 IO 等等

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/637166

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX