发现 Python 的一个坑。。。 - V2EX
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
hard2reg
V2EX    Python

发现 Python 的一个坑。。。

  •  
  •   hard2reg 2016-06-05 19:54:58 +08:00 9795 次点击
    这是一个创建于 3416 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    60 条回复    2016-06-06 20:07:42 +08:00
    clino
        1
    clino  
       2016-06-05 19:58:20 +08:00
    明明 1/3 是 0
    >>> print 1/3
    0
    hard2reg
        2
    hard2reg  
    OP
       2016-06-05 20:00:20 +08:00
    @clino 我用的是 Python3
    Yc1992
        3
    Yc1992  
       2016-06-05 20:00:44 +08:00
    明明 1/3 = 0
    b = 1/0 = ∞
    hard2reg
        4
    hard2reg  
    OP
       2016-06-05 20:02:02 +08:00
    @Yc1992 我 Python3 。。。。
    publicID002
        5
    publicID002  
       2016-06-05 20:02:18 +08:00 via Android
    应该是输出的时候位数默认不多有舍入
    wsy2220
        6
    wsy2220  
       2016-06-05 20:04:41 +08:00
    浮点计算不保证结果精确的,换一个数甚至换一个机器结果就不一样了
    Kisesy
        7
    Kisesy  
       2016-06-05 20:08:03 +08:00
    py
    0.3333333333333333 3.0
    go
    0.3333333333333333 3
    shuax
        8
    shuax  
       2016-06-05 20:08:48 +08:00   1
    print(2.999999999999999999999999999)
    billlee
        9
    billlee  
       2016-06-05 20:26:40 +08:00
    不要依赖未定义行为
    clino
        10
    clino  
       2016-06-05 20:32:10 +08:00
    py3 的表现也合理啊
    >>> print(1/3)
    0.3333333333333333
    >>> print(1/(1/3))
    3.0
    >>> print(1/0.3333333333333333)
    3.0
    justjavac
        11
    justjavac  
       2016-06-05 20:34:10 +08:00 via Android
    是你孤陋寡闻了。
    浮点数的内部表示和浮点数的显示是两码事
    justjavac
        12
    justjavac  
       2016-06-05 20:36:19 +08:00 via Android   2
    pimin
        13
    pimin  
       2016-06-05 20:40:41 +08:00 via Android
    我发现数学的一个坑
    1/3=0.3333333...
    0.33333*3<1
    3*1/3=1
    ipconfiger
        14
    ipconfiger  
       2016-06-05 20:44:07 +08:00
    楼举不是计算机科班出身的吧, 先搞清楚二进制怎么存储浮点数就清楚了,如果我记得没错应该是在计算机组成原理的课本里有
    hadoop
        15
    hadoop  
       2016-06-05 20:46:30 +08:00
    @pimin 0.3333.....≠ 0.33333
    hard2reg
        16
    hard2reg  
    OP
       2016-06-05 20:48:00 +08:00
    @justjavac 大神啊,要出版了
    hard2reg
        17
    hard2reg  
    OP
       2016-06-05 20:49:02 +08:00
    @pimin 我没有任何这个意思。。。
    fy
        18
    fy  
       2016-06-05 20:55:45 +08:00
    日常又发现一个坑。。。
    hard2reg
        19
    hard2reg  
    OP
       2016-06-05 21:03:36 +08:00
    @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
        20
    jimmyye  
       2016-06-05 21:13:13 +08:00   1
    要用 decimal 之类的库
    SuperMild
        21
    SuperMild  
       2016-06-05 21:15:31 +08:00 via iPad
    楼主你看的是哪本入门教材,书中肯定有说到这个的,就在说基本类型的数字类型那章
    xuwenmang
        22
    xuwenmang  
       2016-06-05 21:31:37 +08:00
    @hard2reg C++你试试 1000000000000.2+1000000000000.2 还准不。
    ericls
        23
    ericls  
       2016-06-05 21:36:14 +08:00 via iPhone
    @hard2reg 输出和结果不一样很正常
    realpg
        24
    realpg  
    PRO
       2016-06-05 22:05:44 +08:00   7
    mornlight
        25
    mornlight  
       2016-06-05 22:14:37 +08:00 via iPhone
    @realpg 你这输入法做多了 PY 交易
    crazykuma
        26
    crazykuma  
       2016-06-05 22:23:22 +08:00
    666 楼主这是没仔细看入门教程吧
    随便一本入门里都有啊
    justjavac
        27
    justjavac  
       2016-06-05 22:40:39 +08:00 via Android
    @hard2reg 输出 0.6 才是不正常的。 C++默认的浮点数输出有效位数为 6 ,即 setprecision(6)。
    justjavac
        28
    justjavac  
       2016-06-05 22:45:48 +08:00 via Android
    @hard2reg 如果想要精确计算,使用 Decimal 之类的库。

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

    d = decimal(0.2)

    而是用

    d = decimal("0.2")

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

    输出 0.6 很正常, C++ 编译器的优化会把一些没什么意义的数值提前算出来,根本就轮不到运算……
    bramblex
        32
    bramblex  
       2016-06-05 23:36:18 +08:00
    @hard2reg

    输出 0.6 太正常不过了

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

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

    1 / 0.3 == 10 / 3

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

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

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

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

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

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

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

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

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

    来自廖雪峰的网站 http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431658624177ea4f8fcb06bc4d0e8aab2fd7aa65dd95000
    Clarencep
        45
    Clarencep  
       2016-06-06 09:48:49 +08:00
    浮点数当然是有误差的, 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
        46
    Arnie97  
       2016-06-06 09:51:56 +08:00 via Android
    @clino 是分数,不是无理数。无理数是无限不循环小数。
    clino
        47
    clino  
       2016-06-06 09:53:52 +08:00
    @Arnie97 好吧 概念模糊 数学都还给体育老师了...
    magiclx
        48
    magiclx  
       2016-06-06 09:54:40 +08:00
    奇怪的是大家不知道数学上: 0.333...*3 = 1 ?
    Arnie97
        49
    Arnie97  
       2016-06-06 09:55:23 +08:00 via Android
    Haskell 大法好,有原生的分数类型。
    misaka19000
        50
    misaka19000  
       2016-06-06 10:16:00 +08:00
    @realpg ...
    isno
        51
    isno  
       2016-06-06 10:31:23 +08:00
    @justjavac 博客质量不错啊
    BlackKey
        52
    BlackKey  
       2016-06-06 11:29:35 +08:00 via Android
    LZ 请去自行了解 IEEE754
    menc
        53
    menc  
       2016-06-06 11:45:32 +08:00
    @justjavac 你的博客写得真麻烦,不如直接看 IEEE754
    justjavac
        54
    justjavac  
       2016-06-06 12:33:27 +08:00
    @menc IEEE754 是专业,我是业余
    hard2reg
        55
    hard2reg  
    OP
       2016-06-06 13:41:27 +08:00
    @bramblex soga~ thx
    dixyes
        56
    dixyes  
       2016-06-06 13:48:17 +08:00 via Android
    还以为要讨论.3 循环乘 3 等于一的问题(同时因为.3 循环乘三等于.9 循环所以.9 循环等于一
    newton108
        57
    newton108  
       2016-06-06 15:37:06 +08:00
    有几位是高中生吧?
    浮点数运算和 0.99...=1 有任何关系么?
    aREMbosAl
        58
    aREMbosAl  
       2016-06-06 17:21:39 +08:00
    分数在内部存储的时候好像是精确的,显示出来是近似的。。
    mauve
        59
    mauve  
    PRO
       2016-06-06 19:51:39 +08:00
    有什么不对吗?
    ivechan
        60
    ivechan  
       2016-06-06 20:07:42 +08:00
    @pimin 0.33333333~~~~~=1/3,前提是 3 是无穷
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2810 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 00:22 PVG 08:22 LAX 17:22 JFK 20:22
    Do have faith in what you're doing.
    ubao 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