既然浮点数据类型不精确,那么浮点数存在的意义在哪?

2021-03-18 14:20:45 +08:00
 xiaokongwu

既然二进制无法精确的表示小数,那么为什么设计浮点数(float/double)这种不精确的格式,而不直接设计一种基础的,可以精确表示小数的基础数据类型呢?

IEEE 虽然规定了浮点数的格式,但这种浮点数格式仍然是不精确的,为什么不直接规定一种精确的存储格式呢? 比如整数小数分开存储,前 N 位是整数,后 N 位是小数,再来几位存 scale/precision 之类的设计,就像 Java 里的 BigDecimal 一样

9821 次点击
所在节点    Java
83 条回复
ho121
2021-03-18 18:01:34 +08:00
实际上基本不需要 100%精确的计算,比如 NASA 他们π 一般也就用 15 位小数 https://www.jpl.nasa.gov/edu/news/2016/3/16/how-many-decimals-of-pi-do-we-really-need/
yolee599
2021-03-18 18:51:04 +08:00
在汇编的世界里,没有浮点数,没有负数
AoEiuV020
2021-03-18 19:13:02 +08:00
省空间,想想 4 个字节的 float 比 int 范围大多少,
favourstreet
2021-03-18 19:14:29 +08:00
楼主听说了定点数的误差和( dsp 里的那种)计算,怕不是还会问为什么会有定点数这种东西……浮点数的运算误差是比较容易分析的,大部分计算不需要特别精确,只要误差在一个范围内就可以了……
capti0n
2021-03-18 20:18:02 +08:00
来你来表示下 1/3
xuanbg
2021-03-18 20:47:36 +08:00
@xiaokongwu 浮点数的优势是计算快。

其实很多地方不需要精确!例如在工程上,所有的图纸都是允许一定的误差的。你计算结果的误差只要在允许的范围内,就可以认为是精确的。而且,例如 1 米长的材料 3 等分这种事情,你怎么可能精确?

需要精确计算的应用,反而是少数派。但常人接触比较多的,恰恰是这个少数派。
touchwithe
2021-03-18 20:57:42 +08:00
@capti0n 你和楼上说圆周率的同学都误会楼主了。楼主想问的是有限小数,比如 0.1+0.2 在 js 中是不等于 0.3 的。浮点数是 IEEE754 标准制定的,有限的位数必定会导致精度丢失。IEEE 标准不仅用于软件领域,也会用在硬件领域。我猜想硬件方面应该很难去实现 java 中的 decimal 。
walsh
2021-03-18 22:40:03 +08:00
冯诺依曼数字计算机存储的信息是离散的,与非门本来就是无法表示大部分连续的小数的值的,PI 这样的小数只能像存储矢量图那样用一个代号或者一个无限循环的计算算法代指
lxilu
2021-03-18 23:49:17 +08:00
@yolee599 #42 这啥年代的事了?
@touchwithe #47 楼上也有多人提到:二进制有限小数
ryd994
2021-03-19 00:17:29 +08:00
@touchwithe 既然你明白有限位数会导致精度丢失,那你在硬件里实现个无限位数的出来?
做个减法,小于某个限度就算相等。
科学计数法的计算结果应该用科学的方法读。你输入只有 1 位有效数字,加法的输出就只有 1 位有效数字,你应该只取有效数字进行比较。计算机的比较就是减法,所以两者相减小于某个限度就可以说是相等。
msg7086
2021-03-19 02:41:29 +08:00
十进制的 0.1+0.2,在计算机的世界中,0.1 不是有限位数小数,0.2 也不是。

比如 0.1 转成十六进制是 0x0.1999999999999999999...。
0.2 是 0x0.3333333333333333333...。
最终结果 0.3 则是 0.4CCCCCCCCCCCCCCCCCC...。
他们都不是有限位数小数,所以会变得不精确。

至于为什么不内置更复杂的数据结构。
当然是因为浮点速度更快咯。
早期的计算机资源有限,很多计算和存储都会取巧,能省则省。比如年份只存两位(所以有千年虫 bug ),时间戳只存 int32 (所以有 2038 问题),IP 地址只有 4 字节(然后现在被人抢光了),还有一个著名的取巧就是容量计算,为了节约除法的几次 CPU 周期计算,用 1024 代替 1000 来计算估计值,然后现在大家都默认用 1024 代表 1000 了,以至于很多人以为用 1024 计算才是准确值。
在一个每字节内存都要花不少钱的年代,你搞个 bigdecimal 会被人打死的。大多数计算用 float 已经很精确了,再不行就上 double 或者 quadruple 。quadruple 能支持 33 位有效数字,就算是日常科研用也已经很精确了。
xuegy
2021-03-19 06:08:06 +08:00
你可以用 mathematica 啊,无限精度符号计算包你满意,代价是速度慢若干个数量级。
xuegy
2021-03-19 06:10:47 +08:00
@ho121 难道不是因为 15 位正好是 double 的有效数字?
ho121
2021-03-19 07:16:33 +08:00
@xuegy 15 位小数加前面一个 3,一共 16 位有效数字吧
yolee599
2021-03-19 08:15:45 +08:00
@lxilu 我的意思是浮点数仅仅是方便编程人员使用而已,对于硬件来说,浮点数是一个极其复杂的东西
wanguorui123
2021-03-19 08:34:14 +08:00
float/double 的运算和存储效率应该很高才对,有些地方不需要那么精确的计算,比如:GPU 图形计算,用其他类型反而影响效率。
sutra
2021-03-19 08:48:26 +08:00
说来说去,你想要一个字面上( literally )看起来像原始类型( primitive type )的 BigDecimal 。
但是又提供不了获取精度,计算时指定 rouding mode 等方法 的无用的东西。
ssshooter
2021-03-19 08:53:27 +08:00
简单来说浮点可以在内存不多的情况下表示 123456789 和 1.23456789,不是浮点内存不知道要多少了
Mohanson
2021-03-19 09:04:26 +08:00
1/3 在十进制下是无限循环小数,但在 3 进制下却是精确值。浮点数在二进制下是精确表示的,在 10 进制下会有进制转换的损失(极端例子 pi 在 10 进制是无限不循环小数,但 pi 在 pi 进制下是 1)。先把 ieee754 看一遍再去思考为什么半个世纪前的人为什么做了这个选择,事实上当时有很多小数表示规范…
Carlgao
2021-03-19 09:13:53 +08:00
计算机系统结构里面说得很清楚,浮点数下溢的处理方法,如何把一个浮点数存到规定长度的二进制里面,其中实数和虚数是放在一起的,这样的话一定有精度丢失,丢失精度后采取的方法是查表法,如果分开存储那 cpu 作运算需要取两次数据,这样可能会产生数据相关,对并行性能有损耗。

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

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

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

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

© 2021 V2EX