推荐学习书目
› 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
hard2reg
V2EX  ›  Python

发现 Python 的一个坑。。。

  •  
  •   hard2reg · Jun 5, 2016 · 10856 views
    This topic created in 3807 days ago, the information mentioned may be changed or developed.

    不知道是不是所有语言都是这样的。。

    #我用的是Python3
    a = 1 / 3
    # 这时候 a 打印出来应该是 0.333333333
    b = 1 / a
    # 这时候打印 b 居然输出的是 3
    

    这说明 Python 在内部是以分数的形式储存无限循环小数的?

    还是我孤陋寡闻了。。。。

    60 replies  •  2016-06-06 20:07:42 +08:00
    clino
    clino
    Jun 5, 2016
    1
    明明 1/3 是 0
    >>> print 1/3
    0
    hard2reg
    hard2reg
    OP
    Jun 5, 2016
    2
    @clino 我用的是 Python3
    bytenoob
    bytenoob
    Jun 5, 2016
    3
    明明 1/3 = 0
    b = 1/0 = ∞
    hard2reg
    hard2reg
    OP
    Jun 5, 2016
    4
    @Yc1992 我 Python3 。。。。
    publicID002
    publicID002
    Jun 5, 2016 via Android
    5
    应该是输出的时候位数默认不多有舍入
    wsy2220
    wsy2220
    Jun 5, 2016
    6
    浮点计算不保证结果精确的,换一个数甚至换一个机器结果就不一样了
    Kisesy
    Kisesy
    Jun 5, 2016
    7
    py
    0.3333333333333333 3.0
    go
    0.3333333333333333 3
    momo1999
    momo1999
    Jun 5, 2016❤️1
    8
    print(2.999999999999999999999999999)
    billlee
    billlee
    Jun 5, 2016
    9
    不要依赖未定义行为
    clino
    clino
    Jun 5, 2016
    10
    py3 的表现也合理啊
    >>> print(1/3)
    0.3333333333333333
    >>> print(1/(1/3))
    3.0
    >>> print(1/0.3333333333333333)
    3.0
    justjavac
    justjavac
    Jun 5, 2016 via Android
    11
    是你孤陋寡闻了。
    浮点数的内部表示和浮点数的显示是两码事
    pimin
    pimin
    Jun 5, 2016 via Android
    13
    我发现数学的一个坑
    1/3=0.3333333...
    0.33333*3<1
    3*1/3=1
    ipconfiger
    ipconfiger
    Jun 5, 2016
    14
    楼举不是计算机科班出身的吧, 先搞清楚二进制怎么存储浮点数就清楚了,如果我记得没错应该是在计算机组成原理的课本里有
    hadoop
    hadoop
    Jun 5, 2016
    15
    @pimin 0.3333.....≠ 0.33333
    hard2reg
    hard2reg
    OP
    Jun 5, 2016
    16
    @justjavac 大神啊,要出版了
    hard2reg
    hard2reg
    OP
    Jun 5, 2016
    17
    @pimin 我没有任何这个意思。。。
    fy
    fy
    Jun 5, 2016
    18
    日常又发现一个坑。。。
    hard2reg
    hard2reg
    OP
    Jun 5, 2016
    19
    @justjavac 貌似 JS 和 Python 都会出现 0.2 + 0.4 ≠ 0.6 的情况,但是我用 C++试了下输出的是 0.6 。请问这是为啥。。

    float a;
    a = 0.2 + 0.4;
    cout << a << endl;

    如果想要让 JS 和 Python 正确输出 0.6 改如何写。。
    jimmyye
    jimmyye
    Jun 5, 2016❤️1
    20
    要用 decimal 之类的库
    SuperMild
    SuperMild
    Jun 5, 2016 via iPad
    21
    楼主你看的是哪本入门教材,书中肯定有说到这个的,就在说基本类型的数字类型那章
    xuwenmang
    xuwenmang
    Jun 5, 2016
    22
    @hard2reg C++你试试 1000000000000.2+1000000000000.2 还准不。
    ericls
    ericls
    Jun 5, 2016 via iPhone
    23
    @hard2reg 输出和结果不一样很正常
    realpg
    realpg
    Jun 5, 2016❤️7
    24
    mornlight
    mornlight
    Jun 5, 2016 via iPhone
    25
    @realpg 你这输入法做多了 PY 交易
    crazykuma
    crazykuma
    Jun 5, 2016
    26
    666 楼主这是没仔细看入门教程吧
    随便一本入门里都有啊
    justjavac
    justjavac
    Jun 5, 2016 via Android
    27
    @hard2reg 输出 0.6 才是不正常的。 C++默认的浮点数输出有效位数为 6 ,即 setprecision(6)。
    justjavac
    justjavac
    Jun 5, 2016 via Android
    28
    @hard2reg 如果想要精确计算,使用 Decimal 之类的库。

    但是要注意,初始化的时候不要使用

    d = decimal(0.2)

    而是用

    d = decimal("0.2")

    想想为什么?
    OnTheRoad
    OnTheRoad
    Jun 5, 2016
    29
    除法不可避免的会产生误差。
    当误差处于精度下限时,会做近似处理。
    如:
    <code>
    print(0.3333333333333333 * 3)
    # Output: 1.0
    </code>
    bdbai
    bdbai
    Jun 5, 2016 via Android
    30
    @justjavac 我猜一下,前者表达式的精度已经损失了。对吗?
    bramblex
    bramblex
    Jun 5, 2016
    31
    @justjavac

    输出 0.6 很正常, C++ 编译器的优化会把一些没什么意义的数值提前算出来,根本就轮不到运算……
    bramblex
    bramblex
    Jun 5, 2016
    32
    @hard2reg

    输出 0.6 太正常不过了

    a = 0.2 + 0.4 这行代码已经被 C++ 编译器编译优化成了 a = 0.6 了。所以在程序运行的时候根本就不存在 0.2 + 0.4 这个步骤,所以也就没有什么丢失精度的问题了。
    clino
    clino
    Jun 5, 2016 via Android
    33
    0.2 0.4 在 10 进制世界里是有理数 在二进制的世界里是无理数
    所以二进制里无法用有限位数表达出 0.2 所以实际上计算机里没有对的 0.2 和 0.4 所以结果当然不一样 只是近似到误差非常小而已
    300
    300
    Jun 5, 2016 via Android
    34
    @pimin 其实 0.33333 3 循环乘以 3 等于 1 。。。
    chairuosen
    chairuosen
    Jun 5, 2016
    35
    还是我大 JS 屌, 1/0.3 = 3.3333333333333335
    ADMlN
    ADMlN
    Jun 6, 2016 via Android
    36
    'http://'+str(.1+.2)+'.com'
    mikegreen7892003
    mikegreen7892003
    Jun 6, 2016
    37
    https://en.wikipedia.org/wiki/IEEE_floating_point

    楼主可以看看文档。浮点数在计算机内一般以二进制来存储。
    浮点数的话,显示的结果和存储的内容不一定完全一致。只能说非常近似。
    veficos
    veficos
    Jun 6, 2016
    38
    1 除以 0.3 是 3.3333 没错啊。。。。。。

    1 / 0.3 == 10 / 3

    这是数学问题好吧.....
    veficos
    veficos
    Jun 6, 2016
    39
    换成分数去算就知道为什么了....
    veficos
    veficos
    Jun 6, 2016 via Android
    40
    是我看错题义了。。。
    introom
    introom
    Jun 6, 2016 via Android
    41
    好吧,我也不懂。
    是因为 0.333...被精确表示了么?别坑我, ieee745 没到无限循环小数那个份上啊。

    那最后为什么会变成 3.0 ,而不是 2.9999999 呢?

    要么是输出的时候四舍五入了,要么是 intel 的 fp 指令搞得鬼。

    我更相信前者。
    justjavac
    justjavac
    Jun 6, 2016 via Android
    42
    @bramblex 编译器提前算的时候不是使用的浮点数?或者说编译器使用了其他当时计算的 0.2+0.4 的值
    tkisme
    tkisme
    Jun 6, 2016
    43
    a=1/3.0
    b=1/a
    coddmajes
    coddmajes
    Jun 6, 2016
    44
    最后解释一下整数的除法为什么也是精确的。在 Python 中,有两种除法,一种除法是 /:

    >>> 10 / 3
    3.3333333333333335
    /除法计算结果是浮点数,即使是两个整数恰好整除,结果也是浮点数:

    >>> 9 / 3
    3.0
    还有一种除法是 //,称为地板除,两个整数的除法仍然是整数:

    >>> 10 // 3
    3
    你没有看错,整数的地板除 //永远是整数,即使除不尽。要做精确的除法,使用 /就可以。

    因为 //除法只取结果的整数部分,所以 Python 还提供一个余数运算,可以得到两个整数相除的余数:

    >>> 10 % 3
    1
    无论整数做 //除法还是取余数,结果永远是整数,所以,整数运算结果永远是精确的。

    来自廖雪峰的网站 http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431658624177ea4f8fcb06bc4d0e8aab2fd7aa65dd95000
    Clarencep
    Clarencep
    Jun 6, 2016
    45
    浮点数当然是有误差的, LZ 可以试试这样子:


    ```

    >>> '%.50lf' % (0.3)
    '0.29999999999999998889776975374843459576368331909180'
    >>> '%.50lf' % (1/3)
    '0.33333333333333331482961625624739099293947219848633'


    >>> '%.50lf' % (0.33333333333333333)
    '0.33333333333333331482961625624739099293947219848633'
    >>> '%.50lf' % (1/0.33333333333333333)
    '3.00000000000000000000000000000000000000000000000000'

    >>> '%.50lf' % (0.3333333333333333)
    '0.33333333333333331482961625624739099293947219848633'
    >>> '%.50lf' % (1/0.333333333333333)
    '3.00000000000000310862446895043831318616867065429688'

    ```
    Arnie97
    Arnie97
    Jun 6, 2016 via Android
    46
    @clino 是分数,不是无理数。无理数是无限不循环小数。
    clino
    clino
    Jun 6, 2016
    47
    @Arnie97 好吧 概念模糊 数学都还给体育老师了...
    magiclx
    magiclx
    Jun 6, 2016
    48
    奇怪的是大家不知道数学上: 0.333...*3 = 1 ?
    Arnie97
    Arnie97
    Jun 6, 2016 via Android
    49
    Haskell 大法好,有原生的分数类型。
    misaka19000
    misaka19000
    Jun 6, 2016
    50
    @realpg ...
    isno
    isno
    Jun 6, 2016
    51
    @justjavac 博客质量不错啊
    BlackKey
    BlackKey
    Jun 6, 2016 via Android
    52
    LZ 请去自行了解 IEEE754
    menc
    menc
    Jun 6, 2016
    53
    @justjavac 你的博客写得真麻烦,不如直接看 IEEE754
    justjavac
    justjavac
    Jun 6, 2016
    54
    @menc IEEE754 是专业,我是业余
    hard2reg
    hard2reg
    OP
    Jun 6, 2016
    55
    @bramblex soga~ thx
    dixyes
    dixyes
    Jun 6, 2016 via Android
    56
    还以为要讨论.3 循环乘 3 等于一的问题(同时因为.3 循环乘三等于.9 循环所以.9 循环等于一
    newton108
    newton108
    Jun 6, 2016
    57
    有几位是高中生吧?
    浮点数运算和 0.99...=1 有任何关系么?
    aREMbosAl
    aREMbosAl
    Jun 6, 2016
    58
    分数在内部存储的时候好像是精确的,显示出来是近似的。。
    mauve
    mauve
    Jun 6, 2016
    59
    有什么不对吗?
    ivechan
    ivechan
    Jun 6, 2016
    60
    @pimin 0.33333333~~~~~=1/3,前提是 3 是无穷
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   759 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 148ms · UTC 23:15 · PVG 07:15 · LAX 15:15 · JFK 18:15
    ♥ Do have faith in what you're doing.