一文简单明了说明为什么 float64 float32 会有精确缺失的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
8520ccc
V2EX    程序员

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

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

    说明

    • 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  
    nbsp;  2022-07-13 08:27:06 +08:00
    想要回答这个问题,需要理解 IEEE754 ,它采用科学计数法,位数是有限的。而 0.1 在二进制中,是一个无穷的循环小数,没有办法用科学计数法精确表示。

    https://fasionchan.com/posts/ieee754-traps/
    AV1
        12
    AV1  
       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     Solana     2332 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 48ms UTC 10:14 PVG 18:14 LAX 02:14 JFK 05:14
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86