V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
lyf362345
V2EX  ›  C

两个 double 做比较, 为什么加要个 1e-5 呢

  •  
  •   lyf362345 · May 4, 2015 · 2529 views
    This topic created in 4024 days ago, the information mentioned may be changed or developed.
    初学c++, 做练习题的时候跟答案对比, 发现有点不一样

    练习题是:

    描述
    在北大校园里, 没有自行车, 上课办事会很不方便. 但实际上, 并非去办任何事情都是骑车快,
    因为骑车总要找车、开锁、停车、锁车等, 这要耽误一些时间. 假设找到自行车,
    开锁并骑上自行车的时间为27秒; 停车锁车的时间为23秒; 步行每秒行走1.2米,
    骑车每秒行走3.0米. 请判断走不同的距离去办事, 是骑车快还是走路快.

    输入
    第一行为待处理的数据的数量n
    其后每一行整数为一次办事要行走的距离,单位为米.

    输出
    对应每个整数,如果骑车快,输出一行"Bike";如果走路快,输出一行"Walk";如果一样快,输出一行"All".

    样例输入
    4
    50
    90
    120
    180

    样例输出
    Walk
    Walk
    Bike
    Bike

    我的代码


    答案里定义了个 `double delta = 1e-5` 然后比较的时候 再加上去, 这里有什么用呢
    Supplement 1  ·  May 4, 2015
    根据一楼的指导, 17行已经改为 `bikeTime = m / 3.0 + 27 + 23;`
    Supplement 2  ·  May 5, 2015
    答案里 比较大小都加 delta 了, All 的情况我没写.
    31 replies    2015-05-05 21:33:55 +08:00
    dslwind
        1
    dslwind  
       May 4, 2015 via Android   ❤️ 1
    大概是因为浮点数在计算机内部的存储和表示的问题,并不是所有浮点数都能“精确”的等于你想要的值。ps. biketime应该等于m/3.0+27+23。/3是整除……
    acros
        2
    acros  
       May 4, 2015   ❤️ 1
    同楼上。
    delta这个名字就表明了意思:误差范围。
    zhicheng
        3
    zhicheng  
       May 4, 2015   ❤️ 1
    如果两个 double 很接近,不能直接进行比较。细节太多,楼主多 Google 一下。
    如果需要,我有一个封装好的可以直接拿来用。
    https://github.com/zhicheng/fequal
    cover
        4
    cover  
       May 4, 2015   ❤️ 1
    double的误差范围把。。比如你在做几何学运算的时候,两个角度相差 0.0001度的时候你就认为两个角度相等的意思
    lyf362345
        5
    lyf362345  
    OP
       May 4, 2015
    @dslwind 嗯 谢谢
    lyf362345
        6
    lyf362345  
    OP
       May 4, 2015
    @zhicheng 水很深呐, 我研究下你的代码
    lyf362345
        7
    lyf362345  
    OP
       May 4, 2015
    @cover 明白了, 非常感谢
    lyf362345
        8
    lyf362345  
    OP
       May 4, 2015
    @acros 恩恩 谢谢
    msg7086
        9
    msg7086  
       May 4, 2015
    10进制的有限小数在2进制里不一定就是有限小数。
    比如1.1(循环小数)+1.2(循环小数) 与 1.3(循环小数) 就不一定会相等,而是在最尾端可能会出现一个很小的误差。
    lyf362345
        10
    lyf362345  
    OP
       May 4, 2015
    @msg7086 嗯 谢谢啊
    Elethom
        12
    Elethom  
       May 4, 2015 via iPhone
    沒人吐槽應該是「both」麼?
    comicfans44
        13
    comicfans44  
       May 4, 2015
    浮点误差只有在比较相等的时候会用到,比如你判断
    if(abs(walkTime-bikeTime)<delta){
    cout<<"bike walk time equal"
    }
    可是现在你的逻辑是比较大小,当然是直接比较值,不明白答案为什么有delta。
    如果说进制不同导致的计算误差用一个delta来补足,显然也是不合适的。
    1e-5就不能用double准确表示(这本身就是一个十进制小数),怎么能假定加上一个不准确的delta就能让结果绝对准确?怎么能确定计算结果正好少了delta?如果需要绝对的准确性,那不应该加上delta,而是使用有理数进行计算。个人觉得这个delta是不合理的。
    WKPlus
        14
    WKPlus  
       May 4, 2015
    @comicfans44 对呀,不是浮点数用来判断是否相等的时候才需要引入一个delta的么?
    Neveroldmilk
        15
    Neveroldmilk  
       May 4, 2015
    浮点数在计算机里不是精确存储的,会有误差,所以要设定阈值。
    koykoi
        16
    koykoi  
       May 4, 2015
    比较大小要加什么阈值...
    即使是 tolerance 设为 1e-5 也没什么道理
    chai2010
        17
    chai2010  
       May 4, 2015
    fix typo: IEEE854 -> IEEE754
    lyf362345
        18
    lyf362345  
    OP
       May 4, 2015
    @Elethom both 那不就是都不加了么
    lyf362345
        19
    lyf362345  
    OP
       May 4, 2015
    @comicfans44
    @WKPlus
    @koykoi

    几位的回答又让我不确定了...
    CRVV
        20
    CRVV  
       May 4, 2015
    题目里说:如果一样快,输出一行"All"

    我咋没在代码里看到"All"...
    判断相等需要用阈值

    而且这题直接和100比较,大于100骑车,小于100走路,关浮点数什么事
    canautumn
        21
    canautumn  
       May 5, 2015
    这个答案可能不是很好。按理说判断大小不用考虑delta的,只有判断相等的时候才用delta。不过估计这个答案的原作者在m/3.0这儿写错写成了m/3,导致通不过oj,然后手动加了一个delta的hack才通过oj(我猜的,没测试)。还有一种可能是double精度太高,3.0实际存储的值是2.999999....,导致需要用delta来应对某个特殊的test case。想钻研的话可以看看这个 http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html (不负责任推荐,我也没看过,暂时没遇到需要考虑这些东西的情况)
    laoyur
        22
    laoyur  
       May 5, 2015
    @Elethom 槽点比较独特,不过你是√的,:)
    lyf362345
        23
    lyf362345  
    OP
       May 5, 2015
    @canautumn 我更新了下代码, 按答案的写法, 貌似不是写错; 文档我找了分中文的
    canautumn
        24
    canautumn  
       May 5, 2015
    @lyf362345 那就是第二个原因。我这边搜到的答案有说用float就可以通过oj,double就不行的。但没搜到使用delta的答案。
    CRVV
        25
    CRVV  
       May 5, 2015
    相等的情况没写,和写了相等的情况,是两回事
    先用阈值判断出来1.99999999和2相等,就不用比大小了
    不判断相等,直接比1.99999999和2,结果是不相等
    做题就按原题来做呗,何必自己精简题目
    CRVV
        26
    CRVV  
       May 5, 2015
    原来在代码结尾加上了else输出"All"...
    这题的每一个比较都是在大于、小于和等于3种情况里选择,所以每一步都需要阈值
    不过我还是觉得这题适合用整数来计算
    lyf362345
        27
    lyf362345  
    OP
       May 5, 2015
    lyf362345
        28
    lyf362345  
    OP
       May 5, 2015
    @CRVV All 部分是我后面加上的, 类似13楼的说法是 这个阀值是作者容忍的阀值还是计算机计算误差的阀值呢

    觉得如果题目有个前提就好了, 关于阀值部分, 不然我可以完全不管误差, 因为在实际应用的时候是会人为的去掉这个误差的

    我也不纠结了
    CRVV
        29
    CRVV  
       May 5, 2015
    @lyf362345



    我觉得你并没有搞懂浮点数的事,上面有人发链接了,先看明白再说吧
    至少要知道下面这个情况的原因,Python 3.4.3
    >>> 1.2-0.1
    1.0999999999999999

    这道题用1e-5得到正确的结果没有问题,代码应该也没错,至于1e-5这数选得好不好就另说了
    lyf362345
        30
    lyf362345  
    OP
       May 5, 2015
    @CRVV 好的
    lyf362345
        31
    lyf362345  
    OP
       May 5, 2015
    @CRVV 谢谢
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3022 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 59ms · UTC 08:27 · PVG 16:27 · LAX 01:27 · JFK 04:27
    ♥ Do have faith in what you're doing.