V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xiaokongwu
V2EX  ›  Java

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

  •  
  •   xiaokongwu · 2021-03-18 14:20:45 +08:00 · 9069 次点击
    这是一个创建于 1354 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    83 条回复    2021-03-21 16:26:08 +08:00
    lithiumii
        1
    lithiumii  
       2021-03-18 14:26:12 +08:00
    需要精确的时候,用你的语言里已经实现或者自己实现啊
    Kr98
        2
    Kr98  
       2021-03-18 14:28:46 +08:00 via Android   ❤️ 1
    你想精确到多少位都可以,但总要有个限制吧,硬盘不是无限大的。
    Kasumi20
        3
    Kasumi20  
       2021-03-18 14:33:40 +08:00
    0.99999999 === 1
    ysc3839
        4
    ysc3839  
       2021-03-18 14:46:01 +08:00 via Android
    关键就在于“浮动”吧,精度可以随数值而变化。
    至于为什么没把别的小数存储方案进行标准化,我也不知道。
    across
        5
    across  
       2021-03-18 14:48:31 +08:00   ❤️ 6
    先问问你自己,“精准”的意义在哪里
    anzu
        6
    anzu  
       2021-03-18 14:51:58 +08:00
    运算效率
    qwerthhusn
        7
    qwerthhusn  
       2021-03-18 14:55:25 +08:00
    现在 CPU/GPU 应该都有浮点运算指令
    marcong95
        8
    marcong95  
       2021-03-18 14:55:25 +08:00
    规定的是浮点数存储格式,而不是十进制数存储格式,并不是让你当十进制用的,计算机是个二进制的机器,你看到的十进制数只不过是格式化的结果而已。IEEE754 也不是给你用的,是给计算机用的。
    geelaw
        9
    geelaw  
       2021-03-18 14:56:16 +08:00 via iPhone   ❤️ 7
    今日震惊小知识:你说的那种 decimal 也是浮点数。

    浮点数和定点数是表示某进位制下有限小数的方法,然而楼主的问题和浮点不浮点没关系。
    有限长度,无论什么编码都不能精确表达所有有理数;长度无上界时可以高效、精确表达所有有理数;不需要高效的时候可以表达所有可计算数;然而无论如何都无法表达所有实数。

    很多场景不需要精确,但需要速度,所以采用简短但不精确的表达。它的意义在于够用。
    rnicrosoft
        10
    rnicrosoft  
       2021-03-18 15:01:27 +08:00 via Android
    talk is cheap,你先来设计一个能把圆周率精确存了的小数看看?
    chenluo0429
        11
    chenluo0429  
       2021-03-18 15:01:52 +08:00 via Android   ❤️ 1
    牺牲精度换来的是更大的范围,更快的运算速度。同样是 32 位,float 最大值可以到 3.40282346638528860e+38,int 只能到 2,147,483,647 。
    xiaokongwu
        12
    xiaokongwu  
    OP
       2021-03-18 15:02:39 +08:00
    哇,第一次在 V2EX 发帖,大家这么热情
    xiaokongwu
        13
    xiaokongwu  
    OP
       2021-03-18 15:05:15 +08:00
    @rnicrosoft 我描述的不是很清楚……针对那种非无限小数,可以精确表示吧,不是圆周率这种
    xiaokongwu
        14
    xiaokongwu  
    OP
       2021-03-18 15:06:33 +08:00
    @lithiumii 比如 BigDecimal ( java ),这个毕竟是对象,实际的占用比基础类型大得多,如果有基础的精确类型就可以省去这个额外开销了
    xiaokongwu
        15
    xiaokongwu  
    OP
       2021-03-18 15:08:23 +08:00
    @marcong95 嗯能理解,不过那 float/double 这种浮点数字类型存在的意义在哪呢,除了占用低,完全不能拿来做运算
    xiaokongwu
        16
    xiaokongwu  
    OP
       2021-03-18 15:13:03 +08:00
    @geelaw 感谢解释。不过 java 中的 BigDecimal 貌似是把小数部分作为整数存储的,这也可以叫浮点数吗……float/double 这种基础类型虽然可以近似的表示小数,但是一计算就会出现精度问题,我现在理解这种基础类型有存在的价值(毕竟不是所有场景都需要运算),但是如果直接提供一种基础的 BigDecimal 类型,那不是更好吗
    zxCoder
        17
    zxCoder  
       2021-03-18 15:13:30 +08:00
    省空间?
    xiaokongwu
        18
    xiaokongwu  
    OP
       2021-03-18 15:14:47 +08:00
    @chenluo0429 也能理解这种基础的 float/double 存在的意义,不过提供一种基础的 Decimal 类型不是更好嘛,总比上层实现的占用低
    ylrshui
        19
    ylrshui  
       2021-03-18 15:15:55 +08:00 via iPhone
    早期 8 位计算机,16 位计算机,软盘甚至纸带时代,省存储空间,也节省运算量
    ylrshui
        20
    ylrshui  
       2021-03-18 15:18:45 +08:00 via iPhone
    @xiaokongwu 任何一种 Decimal 类型在数据表示的密度都不会比 float 和 double 大
    Dvel
        21
    Dvel  
       2021-03-18 15:19:39 +08:00
    现在的语言几乎都有 Decimal 类型了,日常的不需要太高精度的小计算用 float 就行了。
    rnicrosoft
        22
    rnicrosoft  
       2021-03-18 15:19:47 +08:00 via Android
    @xiaokongwu 我懂你意思了,只不过平常用不到而已,有需要的自己弄一个高精度计算的库就行,不一定要做进语言标准里。
    geelaw
        23
    geelaw  
       2021-03-18 15:23:41 +08:00 via iPhone   ❤️ 3
    @xiaokongwu #16 浮点数是指对于数 X*B^Y 直接存储了 X 和 Y 的格式,且两者没有必然的绑定关系,在一定范围内可以独立变化。double 和 float 也都是存储了 X 和 Y 。如果你说的格式里 Y 被 X 决定,则不是浮点数。

    BigDecimal 的开销主要不在于它是个 object,而是在于它可以达到任意精度,即使去掉 object 的 overhead 仍然不如 double 高效。另外 BigDecimal 看起来是可以根据需要变化自己的长度的,而 primitive 常常是定长的,因此 Java 的模型下它必须是 object 。

    可以参考 CLR 的 System.Decimal,这是一个定长的十进制浮点数,但范围和精度也当然都是固定的。

    另外你怎么就知道 BigDecimal 计算没有精度问题呢?根据文档,BigDecimal 是十进制浮点数,它不能精确表达 1/3 。
    imn1
        24
    imn1  
       2021-03-18 15:37:13 +08:00
    浮点数我理解是没有违反数学理论,就是精确到“所需”,换句话无限小数无法精确,有限小数就是精确到“有限”位
    然后,就是精确的概念,计算机和人脑定义不同,例如 1/1.0 的结果,人脑定义自然是整数 1,计算机定义是浮点数,“精确”的逻辑等不成立,既然前期定义不同,要靠后期修正,编程语言是其中一种方式
    lithiumii
        25
    lithiumii  
       2021-03-18 15:38:42 +08:00
    @xiaokongwu 按我理解,如果有基础的精确类型,就只是把这个额外的开销转移到基础里了而已
    whileFalse
        26
    whileFalse  
       2021-03-18 15:46:45 +08:00
    既然圆周率不精确,那么为什么还要计算圆的周长和体积?
    icyalala
        27
    icyalala  
       2021-03-18 15:50:47 +08:00
    你希望的是能精确表达"十进制" 的小数,可惜计算机是 "二进制"的。
    而二进制和十进制转换即使到今天也是非常复杂的。
    DOLLOR
        28
    DOLLOR  
       2021-03-18 16:15:27 +08:00 via Android
    建议去了解一下数字是怎样在计算机里表示的
    http://blog.sina.com.cn/s/blog_6e51df7f0100tbje.html
    xiaokongwu
        29
    xiaokongwu  
    OP
       2021-03-18 16:41:31 +08:00
    感谢各位的回复。总结一下:float/double 这种基本的浮点数类型,还是有存在的意义的。对于只读不写的场景,基本的浮点类型完全可以;不过我还是认为编程语言可以提供一种基础的“decimal”类型来解决十进制计算的精度问题,而不是各种奇淫巧技 /额外对象 /三方数字库之类的东西
    lakehylia
        30
    lakehylia  
       2021-03-18 16:55:53 +08:00
    对于无理数来说,任何格式都没有办法存储精确值,只是看你应用的场景,选一个你需要的精度。
    Kr98
        31
    Kr98  
       2021-03-18 17:06:20 +08:00 via Android
    楼主你要理解精度损失的来源

    不是 2 进制还是 10 进制的问题
    不是 float 还是 decimal 类型的问题

    计算精度损失来自于“有限的存储空间”
    lonewolfakela
        32
    lonewolfakela  
       2021-03-18 17:09:49 +08:00   ❤️ 13
    @xiaokongwu "认为编程语言可以提供一种基础的'decimal'类型"
    这个问题之所以不能实现,是有这样一个原因的:编程语言里的真正的“基础类型”,必须是能反映到 CPU 硬件指令上的类型;而 CPU 能做的指令都是有限的,一般来说,是要求基础类型的长度固定的:比如 float 就是 32 字节,double 就是 64 字节。那么 CPU 在执行一个比如“float 加法”的指令的时候,它能知道自己要做的事情实际上就是“读入两个 32 字节数据,送入一个浮点加法单元,这个单元在经过固定的时间长度之后就能得到结果,之后 CPU 就能进行后续计算”。
    而对于你说的这种实际存储长度不定的数据,CPU 一来不能静态地确定每次需要读入 /写出的数据长度,二来也不能固定地知道每次例如加法乘法之类的操作需要运行多长时间。因此即使要在 CPU 上进行相关运算,也几乎必然会先被拆分成几个“子任务”进行计算:先要读入你说的那个 scale/precision 值,然后决定接下来读入多少位整数和小数,甚至可能还要进行一次额外计算来考虑数据计算单元计算一次加法要多少个时钟周期,以便安排接下来的指令。这样复杂的一个东西很显然是不适合作为一个“基础类型”存在的。这也是为啥现有大部分对这种 decimal 类型的实现都是用额外对象 /第三方库之类的东西。
    lonewolfakela
        33
    lonewolfakela  
       2021-03-18 17:14:20 +08:00   ❤️ 3
    @xiaokongwu “对于只读不写的场景,基本的浮点类型完全可以;”
    即使对于需要写、甚至一些需要进行复杂运算的场景,现有的不精确的浮点类型依然是足够的。
    一个典型的场景就是 3D 游戏里的场景渲染。计算机要把一个模型的三维坐标转换成屏幕上的二维坐标,这个步骤基本上都是用 float 类型来算的(甚至 double 都用不上)。道理也很简单,你打游戏的时候是不会在意面前的那只即将被你打爆的外星小怪兽在屏幕上的位置是不是距离“它应该出现的物理上绝对准确的那个坐标”偏离了 0.0001 个像素的。相反,游戏里最重要的是计算速度,只有算得够快游戏才能不卡。所以在这个场景下选择 float 就是最佳的选择。
    ipwx
        34
    ipwx  
       2021-03-18 17:15:27 +08:00
    15L @xiaokongwu
    "float/double 这种浮点数字类型存在的意义在哪呢,除了占用低,完全不能拿来做运算"
    ----

    那么问题来了,1/3 这个无法被十进制和二进制精确表示的小数,楼主打算怎么处理呢? BigDecimal 也不能解决存储 1/3 精确值的问题。

    好,假设楼主为了精确用两个整数存储分母和分子,用分数(比如 Python 内置类型 fraction )。那么 sqrt, exp, log, sin, cos, ... 这些函数出来的大多是无限不循环小数(无理数),楼主打算怎么精确表示呢?

    事实上各种运算中,“不精确”才是常态,精确才是少部分情况。需要精确的时候,楼主可以用分数,或者用整数模拟定点小数,或者用 BigDecimal 这种十进制小数(处理货币)啊?
    xiaokongwu
        35
    xiaokongwu  
    OP
       2021-03-18 17:22:30 +08:00
    @lonewolfakela 感谢大佬回复,解释的真好。

    “这样复杂的一个东西很显然是不适合作为一个“基础类型”存在的。这也是为啥现有大部分对这种 decimal 类型的实现都是用额外对象 /第三方库之类的东西。”

    这段精辟,基础类型就干基础类型的事,复杂的工作交给上层解决
    xiaokongwu
        36
    xiaokongwu  
    OP
       2021-03-18 17:24:57 +08:00
    再次感谢各位大佬的回复,第一次在 V2EX 发帖有这么多人解答,太意外了
    ayase252
        37
    ayase252  
       2021-03-18 17:32:51 +08:00 via iPhone   ❤️ 3
    你永远无法用有限的集合映射到无限集合。你要强行映射必然会有精度。IEEE 754 代表了业界 99%都能通用的一种解决方案。如果不符合自己需求,那么需要自行实现
    lonewolfakela
        38
    lonewolfakela  
       2021-03-18 17:34:47 +08:00   ❤️ 2
    顺便补充一下,并不是所有的编程语言的基础类型里都没有楼主所说的这种任意精度小数的。
    例如在 mathematica 中,这类具有任意指定的精度的近似实数就是四种基本数字类型中的一种( Integer,Rational,Real,Complex 这四者中的 Real )
    但是它这么设计是有原因的:
    1 、Mathematica 不是一个类似 C 语言那样很底层、很接近 CPU 的一个语言,而是一个抽象程度较高的语言。用它编写的东西在电脑上执行前本来就会经过变化相当大的翻译,所以实际上它的“基础类型”也不是那么基础,相关操作在实际运行的时候也都会被翻译成更低级的子任务;
    2 、Mathematica 是面向数学家的语言。相比工程师的“只要在误差范围内就算成功”的思维方式,数学家还是更喜欢能有精确一些的东西的。

    所以归根到底还是出于语言的不同设计思路以及面向的不同使用人群的考量罢了。
    nightwitch
        39
    nightwitch  
       2021-03-18 17:47:34 +08:00   ❤️ 2
    在 IEEE754 之前,每个制造芯片的厂商都要考虑浮点数怎么表示的问题,你的这些思考都是当年就被考虑烂了的内容。

    浮点数据的不精确本质原因在于要用有限的位数去表达无限长度的量,无论你用什么精妙的结构去模拟这个过程都一定会产生舍入误差。
    gBurnX
        40
    gBurnX  
       2021-03-18 17:53:07 +08:00
    1.目前计算机体系中的浮点的设计原则,是因为以前计算机处理浮点功能少、性能低。
    现代的计算机,对于现代的大型游戏与各种运用程序来说,浮点处理性能也不行。


    2.可以设计一套用纯粹的数学公式作为标记的计数系统,比如圆周率,存π比存 3.233366666 要更精确。这种公式系统的优点是精准,但缺点是性能很低。你可以自己实现一套简单的,然后拿去和目前的图形引擎比比图形渲染性能。


    3.类似的问题还有 Datetime 长度问题,以及 IPv4\v6 的长度问题。虽然现在这些数据结构被加长,但长度仍然是个固定值。如果人类在很久很久以后还存在,那么以后当 64 位的 Datetime 被用完,肯定会再次遇到前年虫问题;当 IPv6 被分完,下次说不定会再出个 IPv8 甚至 IPv16...

    这些值其实完全可以一劳永逸地设计成动态长度,PC 也就算了,你看看路由器、交换机以及更低成本的物联网小硬件,那可怜的主频,那可悲的带宽,还要节能,还要考虑成本.....就算她们想要运算复杂的动态长度,但臣妾们也做不到啊。
    ho121
        41
    ho121  
       2021-03-18 18:01:34 +08:00   ❤️ 1
    实际上基本不需要 100%精确的计算,比如 NASA 他们π 一般也就用 15 位小数 https://www.jpl.nasa.gov/edu/news/2016/3/16/how-many-decimals-of-pi-do-we-really-need/
    yolee599
        42
    yolee599  
       2021-03-18 18:51:04 +08:00
    在汇编的世界里,没有浮点数,没有负数
    AoEiuV020
        43
    AoEiuV020  
       2021-03-18 19:13:02 +08:00
    省空间,想想 4 个字节的 float 比 int 范围大多少,
    favourstreet
        44
    favourstreet  
       2021-03-18 19:14:29 +08:00 via Android
    楼主听说了定点数的误差和( dsp 里的那种)计算,怕不是还会问为什么会有定点数这种东西……浮点数的运算误差是比较容易分析的,大部分计算不需要特别精确,只要误差在一个范围内就可以了……
    capti0n
        45
    capti0n  
       2021-03-18 20:18:02 +08:00
    来你来表示下 1/3
    xuanbg
        46
    xuanbg  
       2021-03-18 20:47:36 +08:00
    @xiaokongwu 浮点数的优势是计算快。

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

    需要精确计算的应用,反而是少数派。但常人接触比较多的,恰恰是这个少数派。
    touchwithe
        47
    touchwithe  
       2021-03-18 20:57:42 +08:00 via iPhone
    @capti0n 你和楼上说圆周率的同学都误会楼主了。楼主想问的是有限小数,比如 0.1+0.2 在 js 中是不等于 0.3 的。浮点数是 IEEE754 标准制定的,有限的位数必定会导致精度丢失。IEEE 标准不仅用于软件领域,也会用在硬件领域。我猜想硬件方面应该很难去实现 java 中的 decimal 。
    walsh
        48
    walsh  
       2021-03-18 22:40:03 +08:00 via iPhone
    冯诺依曼数字计算机存储的信息是离散的,与非门本来就是无法表示大部分连续的小数的值的,PI 这样的小数只能像存储矢量图那样用一个代号或者一个无限循环的计算算法代指
    lxilu
        49
    lxilu  
       2021-03-18 23:49:17 +08:00 via iPhone
    @yolee599 #42 这啥年代的事了?
    @touchwithe #47 楼上也有多人提到:二进制有限小数
    ryd994
        50
    ryd994  
       2021-03-19 00:17:29 +08:00
    @touchwithe 既然你明白有限位数会导致精度丢失,那你在硬件里实现个无限位数的出来?
    做个减法,小于某个限度就算相等。
    科学计数法的计算结果应该用科学的方法读。你输入只有 1 位有效数字,加法的输出就只有 1 位有效数字,你应该只取有效数字进行比较。计算机的比较就是减法,所以两者相减小于某个限度就可以说是相等。
    msg7086
        51
    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
        52
    xuegy  
       2021-03-19 06:08:06 +08:00
    你可以用 mathematica 啊,无限精度符号计算包你满意,代价是速度慢若干个数量级。
    xuegy
        53
    xuegy  
       2021-03-19 06:10:47 +08:00
    @ho121 难道不是因为 15 位正好是 double 的有效数字?
    ho121
        54
    ho121  
       2021-03-19 07:16:33 +08:00 via Android
    @xuegy 15 位小数加前面一个 3,一共 16 位有效数字吧
    yolee599
        55
    yolee599  
       2021-03-19 08:15:45 +08:00 via Android
    @lxilu 我的意思是浮点数仅仅是方便编程人员使用而已,对于硬件来说,浮点数是一个极其复杂的东西
    wanguorui123
        56
    wanguorui123  
       2021-03-19 08:34:14 +08:00 via iPhone
    float/double 的运算和存储效率应该很高才对,有些地方不需要那么精确的计算,比如:GPU 图形计算,用其他类型反而影响效率。
    sutra
        57
    sutra  
       2021-03-19 08:48:26 +08:00
    说来说去,你想要一个字面上( literally )看起来像原始类型( primitive type )的 BigDecimal 。
    但是又提供不了获取精度,计算时指定 rouding mode 等方法 的无用的东西。
    ssshooter
        58
    ssshooter  
       2021-03-19 08:53:27 +08:00
    简单来说浮点可以在内存不多的情况下表示 123456789 和 1.23456789,不是浮点内存不知道要多少了
    Mohanson
        59
    Mohanson  
       2021-03-19 09:04:26 +08:00 via Android
    1/3 在十进制下是无限循环小数,但在 3 进制下却是精确值。浮点数在二进制下是精确表示的,在 10 进制下会有进制转换的损失(极端例子 pi 在 10 进制是无限不循环小数,但 pi 在 pi 进制下是 1)。先把 ieee754 看一遍再去思考为什么半个世纪前的人为什么做了这个选择,事实上当时有很多小数表示规范…
    Carlgao
        60
    Carlgao  
       2021-03-19 09:13:53 +08:00
    计算机系统结构里面说得很清楚,浮点数下溢的处理方法,如何把一个浮点数存到规定长度的二进制里面,其中实数和虚数是放在一起的,这样的话一定有精度丢失,丢失精度后采取的方法是查表法,如果分开存储那 cpu 作运算需要取两次数据,这样可能会产生数据相关,对并行性能有损耗。
    raptor
        61
    raptor  
       2021-03-19 09:25:54 +08:00
    楼主基本功不行啊,这么基础的常识都不理解。

    计算机组成原理难道不是最基本的课程之一么?
    passerbytiny
        62
    passerbytiny  
       2021-03-19 09:32:31 +08:00 via Android
    不晚于高中,数学就会教你无限不循环小数、虚数,意即为“随着认知的扩大,完全精确的数是不存在的”。大学里面数学专业的高等代数 /数学分析,会教你迭代求(无限逼近但无法精确的)值,意即为“随着认知的扩大,完全精确的计算是不可能的”。而初中物理开篇之后第二堂课就是讲“误差”。

    以上回答不会对楼主现在的问题解惑,但会对楼主为什么不该提这个问题解惑。
    lz0755
        63
    lz0755  
       2021-03-19 09:37:29 +08:00 via Android
    你去看计组就明白了
    pkoukk
        64
    pkoukk  
       2021-03-19 09:52:25 +08:00
    开销问题啊,一般常用范围内的小数运算用 float 是没有问题的。a=0.3x0.2,print(a),我相信常见语言返回的都是 0.06000
    只是不建议用==进行比较而已,你非要比其实也没问题,据我所知很多语言编译时都会自动优化。
    zealinux
        65
    zealinux  
       2021-03-19 10:00:41 +08:00
    ```clojure
    (/ 3 9)
    ;; => 1/3


    (double 1/3)
    ;; => 0.3333333333333333
    ```

    可以使用有理数(分数形式),
    所有中间计算全部用分数,
    然后最后的结果再转化成浮点数,
    这样能保证全部中间计算不丢失任何精度。
    cigarzh
        66
    cigarzh  
       2021-03-19 10:25:53 +08:00
    二进制信息是离散的
    实数是稠密而连续的
    理论是无穷的
    现实是有限的

    没有完美的方法 能解决实际问题就是意义
    Cu635
        67
    Cu635  
       2021-03-19 10:44:46 +08:00
    @whileFalse
    说反了,是需要计算圆的周长和体积,发现周长除以直径是个常数记为 pi,然后才发现并且证明 pi 是个无理数。

    @cigarzh
    应该说有限位的二进制信息是离散的。
    nicebird
        68
    nicebird  
       2021-03-19 11:20:48 +08:00
    浮点数的目的就是为了小数位浮动,换取更大的表示范围。
    需要固定小数位的实现定点数就行了。
    siyemiaokube
        69
    siyemiaokube  
       2021-03-19 11:33:07 +08:00 via iPhone
    与精度有限的数值计算相对地,我们称作“符号计算”。

    实际上可以实现以分数形式储存有理数。在这种意义下,分子分母足够小时,这样的存储形式支持了以任意精度输出数值值。

    当然,你需要支持表示的数字的数量必然与内存开销成正比。

    同时,更复杂的结构进行运算时的时间开销,比起浮点数运算的时间开销多出很多很多数量级,对应的机器指令的数量也多出很多很多数量级。
    nightwitch
        70
    nightwitch  
       2021-03-19 12:02:04 +08:00
    @zealinux sin, cos,tan,sqrt,log,pow 等一大票高频使用的函数都不能用这种记号表示,意义有限
    MaxLi77
        71
    MaxLi77  
       2021-03-19 12:03:15 +08:00
    先问是不是,再问为什么
    xingguang
        72
    xingguang  
       2021-03-19 12:26:55 +08:00
    这个好像无解,是编码格式决定的,并不是单纯的二进制转十进制,还有符号位、反码、补码之类的格式限制,不过能到那么多位对决绝大多数场景适用了,如果不适用,那么证明这个公司有能力自己搞一套了
    Annoke
        73
    Annoke  
       2021-03-19 12:30:45 +08:00 via Android
    想想无限不循环小数?
    est
        74
    est  
       2021-03-19 13:03:31 +08:00 via Android
    LZ 想法很好,为什么不搞无限精度的浮点,其实可以搞,很多语言的计算库都支持无限精度,但是无限精度就意味着数据格式是变长的,变长的就没法高效率硬件加速计算。CPU 硬件支持的的 FPU 比直接软计算的快的多。
    est
        75
    est  
       2021-03-19 13:10:30 +08:00
    可能接下来有人会问,为啥变长的软加速就一定不如定长的硬加速。这个道理就好比,你背熟练了 9x9 乘法口诀表,计算 7x8 当然不用再把 7 个 8 加一遍。定长的硬加速也是类似的原理,直接电路把常见 IEEE754 浮点就能全算出来了。

    超出 IEEE754 范围的,变长的,就好比你要计算 46x79 这种乘法了。超出长度了。你没法一口回答出来,不得不一步一步分开计算。效率自然低得多。

    现在计算机可能直接告诉你,用 float 就行。没告诉你为啥要用浮点。

    因为用 IEEE754 float 效率高啊。计算机当时被发明出来是生产工具的,算弹道,算账。谁效率高谁 nb 。你要追求精度,那就牺牲效率来换呗。
    zealinux
        76
    zealinux  
       2021-03-19 14:53:38 +08:00
    @nightwitch 这些都支持
    lovecy
        77
    lovecy  
       2021-03-19 15:06:38 +08:00
    我的理解:没有绝对的精确,只有相对精确
    float 是相对精确比较高之中效率最高的,所以用 float
    laqow
        78
    laqow  
       2021-03-19 16:28:10 +08:00 via Android
    其实有另外一个思路理解这个问题:既然整数是绝对精确的,为什么要用浮点数来计算或储存数值?
    很多时候通过设计矩阵或算法能避免计算过程中间出现浮点数,只在输出结果时才输出一个近似值。
    jmc891205
        79
    jmc891205  
       2021-03-19 16:32:54 +08:00
    巴菲特说过 “宁要模糊的正确,不要精确的错误”( would rather be vaguely right than precisely wrong.)
    titan2006
        80
    titan2006  
       2021-03-20 11:31:26 +08:00 via iPhone
    说明编程语言垃圾 数据存储就应该不限制位数
    secondwtq
        81
    secondwtq  
       2021-03-20 16:15:58 +08:00
    既然人类个个都是傻 x,那么人类存在的意义在哪?
    secondwtq
        82
    secondwtq  
       2021-03-20 18:11:05 +08:00
    所谓“择其善者而从之,其不善者而改之”,就算是“不好”的东西,也是有存在的价值的。
    何况在计算机的世界里,并不存在绝对的“不好”。类似的问题还有:“既然硬盘这么慢,那么硬盘存在的意义在哪?”,“既然 MP3 音质有损失,那么 MP3 存在的意义在哪?”,“既然 Java 不如 PHP 好用,那么 PHP 存在的意义在哪?”,“既然 64 位浮点数比 32 位浮点数精确,那么 32 位浮点数存在的意义在哪?”“既然我们前端要 UTF-8 Everywhere,那么 GB 18030 存在的意义在哪?”“既然 memory_order_seq_cst 那么好用,那么 memory_order_relaxed 存在的意义在哪?”

    都是课本里面讲烂的东西,在这帖子里面重复的意义在哪?
    不如整点新活,比如 FP Lives Matter!!!!!1111
    xiaokongwu
        83
    xiaokongwu  
    OP
       2021-03-21 16:26:08 +08:00
    @touchwithe 哈哈哈,终于来了个明白的大哥,没想到有这么多人回复,有怼我垃圾没基础的,也有很多热心解答的。我这问题的关键不在那些无限小数,而是一些有限位的小数,但二进制不能精确表示的那些,为啥不弄一种类似 BigDecimal 的基础类型来实现(看完了评论区,大概了解了,除了存储还有运行效率,CPU 支持浮点数的运算,如果弄复杂类型就效率低了)。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2626 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 07:17 · PVG 15:17 · LAX 23:17 · JFK 02:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.