V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
qingmumu
V2EX  ›  Python

Python 浮点的坑 怎么完美避免?

  •  
  •   qingmumu · 2018-04-01 15:04:31 +08:00 · 4045 次点击
    这是一个创建于 2419 天前的主题,其中的信息可能已经有所发展或是发生改变。



    万万没想到
    自己用 round 还是有坑


    新上手 python,打算跑脚本对账用的,可这坑太大了吧

    之前是写 php 的没遇到过这个问题,查了一下都说是进制的问题道理我是懂了,可是日常怎么避坑比较完美?请各位大佬指教。
    20 条回复    2018-04-02 17:45:50 +08:00
    SErHo
        1
    SErHo  
       2018-04-01 15:32:38 +08:00
    1. 用 decimal

    > from decimal import *
    > getcontext().rounding = ROUND_HALF_UP
    > Decimal("7.2") * Decimal("9.3")
    Out[3]: Decimal('66.96')
    > Decimal("0.1") + Decimal("0.1") + Decimal("0.1")
    Out[4]: Decimal('0.3')
    > Decimal("2.675").quantize(Decimal("0.00"))
    Out[5]: Decimal('2.68')

    2. 用分作为单位使用整数
    XIVN1987
        2
    XIVN1987  
       2018-04-01 15:33:34 +08:00 via Android   ❤️ 1
    别用 float,,用 decimal
    blankme
        3
    blankme  
       2018-04-01 15:35:10 +08:00
    乘以 100,用 int
    Luckyray
        4
    Luckyray  
       2018-04-01 15:38:08 +08:00 via iPhone
    楼上说的对,升几位用整数
    qingmumu
        5
    qingmumu  
    OP
       2018-04-01 15:53:53 +08:00
    @SErHo #1
    @XIVN1987
    @blankme #3
    @Luckyray #4
    感谢各位已决定用 decimal
    D3EP
        6
    D3EP  
       2018-04-01 15:59:33 +08:00 via iPhone
    PHP 没有这种情况?都是 IEE754 怎么可能没有。
    qingmumu
        7
    qingmumu  
    OP
       2018-04-01 16:04:27 +08:00
    @D3EP #6 可能学艺不精,但是 php 里没踩到这个坑,至少以上情况 php 正常
    akira
        8
    akira  
       2018-04-01 16:17:55 +08:00
    大部分语言的浮点数都有同样或类似的问题,特别是编译型语言。 根源是浮点数在计算机中的存储格式。
    方案的话,上面说的基本上就是了
    xpresslink
        9
    xpresslink  
       2018-04-01 16:27:53 +08:00
    楼主认为这个是 python 的坑说明基础知识太差。
    所有编程语言都有这个问题,这个是计算机体系结构本身制约造成的。
    浮点数运算的结果经常会出现无限循环或无限不循环小数,计算机只能用有限位来近似表示。
    ipwx
        10
    ipwx  
       2018-04-01 16:46:05 +08:00   ❤️ 2
    别的语言也是一样的,只不过他们输出的时候没输出这么多位而已。

    任何浮点数,只要小数部分不能写成 2 的负整数次幂的和,就有误差。

    比如 0.25 = 2^{-2},所以是精确的。但是 0.1 无法写成任何 2 的负整数次幂,所以会有误差。
    zhicheng
        11
    zhicheng  
       2018-04-01 17:13:00 +08:00 via iPhone
    一般应用不必用 decimal,因为无限不循环小数的存在的所以现在的计算机架构无法完美表示浮点数。你用的任何方式都是一定条件的取舍。
    joeke
        12
    joeke  
       2018-04-01 18:02:36 +08:00
    php 也是一样的
    ipwx
        13
    ipwx  
       2018-04-01 20:37:45 +08:00
    @zhicheng “对账用”
    xpresslink
        14
    xpresslink  
       2018-04-02 10:16:09 +08:00
    @qingmumu 在 python2.x 里 decimal 性能比浮点数低 1000 倍。
    python3.x 里 decimal 被改用 C 语言实现了性能要好一些。
    所有还要看你对性能是不是敏感。
    wizardoz
        15
    wizardoz  
       2018-04-02 10:36:01 +08:00
    这是 float 的存储格式决定的,大部分语言的 float 存储格式都是这样的。
    从根源上来说,是二进制数据表示浮点数必然会丢失精度的问题。
    pcar
        16
    pcar  
       2018-04-02 13:06:05 +08:00
    *100
    araraloren
        17
    araraloren  
       2018-04-02 16:30:49 +08:00
    Perl6 not have this problem:

    say 0.88882 - 0.22335 == 0.66547; # True

    [Try it online!]( https://tio.run/##K0gtyjH7/784sVLBQM8CCIwUdIEsIyNjY1MFW1sg08zM1MTc@v9/AA "Perl 6 – Try It Online")
    tonghuashuai
        18
    tonghuashuai  
       2018-04-02 17:31:52 +08:00
    记住一句话:涉及到钱的问题,一律用 decimal
    qingmumu
        19
    qingmumu  
    OP
       2018-04-02 17:45:18 +08:00 via Android
    确实基础差😂
    qingmumu
        20
    qingmumu  
    OP
       2018-04-02 17:45:50 +08:00 via Android
    @xpresslink 确实基础差 要努力了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4733 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 03:59 · PVG 11:59 · LAX 19:59 · JFK 22:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.