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

一文简单明了说明为什么 float64 float32 会有精确缺失的问题

  •  
  •   8520ccc · 2022-07-13 00:13:04 +08:00 · 2382 次点击
    这是一个创建于 861 天前的主题,其中的信息可能已经有所发展或是发生改变。

    说明

    • float64 == 8 字节 == 64bit == 只能精确表达 18446744073709552000(2^64) 个数字
    • float32 == 4 字节 == 32bit == 只能精确表达 4294967296(2^32) 个数字

    取值范围

    • float64 最大值大约是 1.8e308 ( 18 后面 307 个 0 )
    • float32 最大值大约是 3.4e38 ( 34 后面 37 个 0 )
    • 即使忽略小数,负数 从 0 到这个最大值都已经远远超出其能精确表达的数字了
    • 所以它们只能取接近的数字
    • 或者说他们的表达不是连续的 例如 1 4 8 15 当值是 7 时就会取最接近的值 8
    14 条回复    2022-07-13 11:01:26 +08:00
    yayiji
        1
    yayiji  
       2022-07-13 00:35:07 +08:00 via Android   ❤️ 3
    用范围容易理解,但我总喜欢另一个角度,就是数制

    比如,十进制的 0.1 在二进制中是个无限循环小数,所以使用有限的二进制无论如何也无法精确表示 0.1

    也即是说,即便不考虑范围问题,对于很多确定十进制小数二进制也无能为力,比如说,麻烦用二进制精确存储 0.1 0.2 0.3 0.4 0.5 这五个数吧
    8520ccc
        2
    8520ccc  
    OP
       2022-07-13 00:39:54 +08:00 via iPhone
    @yayiji 这种说法比较绕,直接用范围不用考虑那么多,明白原理就行
    ruixue
        3
    ruixue  
       2022-07-13 00:43:51 +08:00
    @yayiji 0.5 的二进制不就是 0.1 吗
    yayiji
        4
    yayiji  
       2022-07-13 00:55:53 +08:00 via Android
    @8520ccc 因为还有数制本身的问题,比如说,我只想存十进制的 0.1 ,其他数不考虑了,这时仍然无法精确存储
    yeqizhang
        5
    yeqizhang  
       2022-07-13 00:58:02 +08:00 via Android
    用的了这么复杂么,精度缺失不就是一句话: 因为算出来的都是近似值。只是 float 定的规则,长度固定的情况下,小数点前面越长,小数点后面位数就越短,偏差就会越来越大。

    你算出来是 2^64 也是不对的,肯定不止这么点的。用的科学表示法,能表达的数值的数量你以为跟整形能算的出来?
    yeqizhang
        6
    yeqizhang  
       2022-07-13 01:00:23 +08:00 via Android
    额,我看错了,你说的二进制的个数呀,那是我说错了🌚
    hsfzxjy
        7
    hsfzxjy  
       2022-07-13 01:02:33 +08:00 via Android
    @yeqizhang 不是不止这么点,而是不到 2^64 个,nan 要占掉很多个位
    Jooooooooo
        8
    Jooooooooo  
       2022-07-13 01:07:19 +08:00
    真的不如 "一个有限十进制小数无法用有限二进制小数" 表达来的简单

    按照你这个说法, 很难解释出 0.1+0.2 怎么不等于 0.3 呢
    hsfzxjy
        9
    hsfzxjy  
       2022-07-13 01:07:48 +08:00 via Android
    感觉不同人的盲点还是不一样的。有的人就是知道了浮点数不能表示所有实数,但还是迷惑「哎呀 0.1 这么简单的数怎么就不能表示」。这时就要和他用进制解释。
    haolongsun
        10
    haolongsun  
       2022-07-13 01:12:14 +08:00
    复习一下 IEEE754 标准,不知道肯定大学计组不过关,推荐 csapp 。
    hxysnail
        11
    hxysnail  
       2022-07-13 08:27:06 +08:00
    想要回答这个问题,需要理解 IEEE754 ,它采用科学计数法,位数是有限的。而 0.1 在二进制中,是一个无穷的循环小数,没有办法用科学计数法精确表示。

    https://fasionchan.com/posts/ieee754-traps/
    DOLLOR
        12
    DOLLOR  
       2022-07-13 09:42:22 +08:00
    我感觉大家把两件事混在一起谈了。

    一是,一个数在十进制下是有限小数,但在二进制下是无限小数,导致浮点数无法精确表示对应的十进制数。

    二是,浮点数所表达的数字,它的绝对值越大,精度越低。以至于当它要表达的数字超过 MAX_SAFE_INTEGER 或 MIN_SAFE_INTEGER 之后,连整数都不能精确表达了。
    momocraft
        13
    momocraft  
       2022-07-13 10:10:29 +08:00
    显然可以有一种格式存储在二进制下无限循环的有理数

    ieee754 无能为力 不是"二进制无能为力"
    zmal
        14
    zmal  
       2022-07-13 11:01:26 +08:00
    不简单不明了,解释还是错的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3122 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 14:28 · PVG 22:28 · LAX 06:28 · JFK 09:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.