solaro
V2EX  ›  PHP

PHP 什么情况下 5.590 小于 5.59

  •  
  •   solaro · Jul 26, 2017 · 6198 views
    This topic created in 3391 days ago, the information mentioned may be changed or developed.

    Markdown

    上图实际开发业务中,碰到了个坑,

    数据库用的 mysql 左边 5.590 在数据库中存储是 decimal(10,3) 右边是换算出来的 float

    现在 floatval(5.590) < floatval(5.59)

    我 sun

    43 replies  •  2017-07-29 14:12:15 +08:00
    elgae
    elgae
    Jul 26, 2017
    1
    关系到钱的业务用浮点数,心很大。
    7654
    7654
    Jul 26, 2017❤️3
    2
    有个故事,某企财务将全厂工资的几分零头抹掉,每月可偷几千块
    Jacklee
    Jacklee
    Jul 26, 2017❤️1
    3
    计算机存储浮点型都不是精确的,如楼上所说,不能直接比较大小啊。涉及钱的业务更不能用啊。
    Jacklee
    Jacklee
    Jul 26, 2017
    4
    补一句,这不是 PHP 的锅哈
    oh
    oh
    Jul 26, 2017❤️1
    5
    抛去楼上已解决说的,不知道楼主有没有试过在 if 前面 var_dump(floatval()) 看看这两个变量对比的时候是多少?
    Biscuits
    Biscuits
    Jul 26, 2017❤️2
    6
    5.59 可能是 5.5904444
    bombless
    bombless
    Jul 26, 2017❤️1
    7
    比较的时候乘 100 按整数比吧
    lujiajing1126
    lujiajing1126
    Jul 26, 2017 via iPhone
    8
    楼主需要复习一下 IEEE754
    goodspb
    goodspb
    Jul 26, 2017
    9
    php > var_dump(floatval(5.590) < floatval(5.59));
    php shell code:1:
    bool(false)
    php > var_dump(floatval(5.590) == floatval(5.59));
    php shell code:1:
    bool(true)
    php > var_dump(5.590 == 5.59);
    php shell code:1:
    bool(true)
    php > var_dump(5.590 < 5.59);
    php shell code:1:
    bool(false)

    恩?有啥问题?

    php -v 一下

    PHP 5.6.30 (cli) (built: Apr 17 2017 10:09:18)
    Copyright (c) 1997-2016 The PHP Group
    Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
    with Xdebug v2.5.3, Copyright (c) 2002-2017, by Derick Rethans
    ovear
    ovear
    Jul 26, 2017❤️1
    10
    请使用 bccomp
    exch4nge
    exch4nge
    Jul 26, 2017
    11
    对 PHP 不熟悉……不过表示金钱的类型应该用专门的 decimal 类型吧……
    nfroot
    nfroot
    Jul 26, 2017
    12
    @bombless 加减乘除都这样么 0 0
    gclove
    gclove
    Jul 26, 2017
    13
    同上, 计算千万不要用符点, 还不如用大数计算

    建议直接乘 100 取整
    为什么设置 3 位, 你们应用还有微分 ?
    有的话可以乘以 1000 取整

    浮点在每种变成语言都有陷阱(坑), 经验不够老练都会踩上
    gclove
    gclove
    Jul 26, 2017
    14
    非用浮点, 计算前值一定要进行类型转换

    因为你不知道它是 整数, 浮点, 还是 字符串
    solaro
    solaro
    OP
    Jul 26, 2017
    15
    本地开发环境用 5.6.27 没毛病,生产环境用 7.1 就触发异常。。。我日
    moult
    moult
    Jul 26, 2017
    17
    就算知道什么情况下出现这个问题,那又如何?
    1、从数据库里面查询出来的浮点数,请使用 string。
    2、http://php.net/manual/en/book.bc.php
    3、个人癖好,有段时间,金钱我用 int 来存储,单位是分。不过现在都用 string 来做了。
    solaro
    solaro
    OP
    Jul 26, 2017
    18
    @moult 为什么,请老司机传道受业解惑,int 不够用我可以理解,bigint 不好吗?为什么换 string
    solaro
    solaro
    OP
    Jul 26, 2017
    19
    @elgae 早期留下的坑
    zhs227
    zhs227
    Jul 26, 2017
    20
    涉及到价格我每次都是*100 以后按整数存。float 的比较容易出问题,越相近越容易出问题。
    cnfzv
    cnfzv
    Jul 26, 2017
    21
    @solaro 同问
    ety001
    ety001
    Jul 26, 2017
    22
    之前用过整数(就是存储到分),后来就用 decimal 了。
    oneonesv
    oneonesv
    Jul 26, 2017
    23
    浮点数精度不够 可能会有类似 0.111 != 0.111 的情况

    PHP 文档 浮点数 章节里面有讲
    stabc
    stabc
    Jul 26, 2017
    24
    谁能说下这种浮点数在计算中常见的坑?
    LioMore
    LioMore
    Jul 26, 2017
    25
    请问一下,正确的做法是只用分来计算并使用整数吗?
    azh7138m
    azh7138m
    Jul 26, 2017 via Android
    26
    @LioMore 是的
    maypu
    maypu
    Jul 26, 2017 via Android
    27
    算错的时候,哈哈哈哈哈哈
    a591826944
    a591826944
    Jul 26, 2017
    28
    LZ 你的心真大。。浮点数算金额。。
    a591826944
    a591826944
    Jul 26, 2017❤️1
    29
    LZ 你试试 floor(8.29 * 100 * 100 / 100) 的结果 体会一下。。。

    这真不是 PHP 的锅、、
    bianchensz
    bianchensz
    Jul 26, 2017❤️1
    30
    233 就算是我老妈用 excel 涉及到钱的都要套个 round 取整,你这也是心大
    xzem
    xzem
    Jul 26, 2017 via Android
    31
    被浮点坑过一次,再也不敢用浮点做计算 比较了
    blankme
    blankme
    Jul 26, 2017❤️1
    32
    ```
    if (fabs(a - b) > 1e-3 && a < b)
    ```
    zhx1991
    zhx1991
    Jul 26, 2017❤️1
    33
    钱用浮点数什么都可能发生

    想追究细节的话了解一下计算机怎么表示小数就明白了
    stabc
    stabc
    Jul 26, 2017❤️1
    34
    看一下这个明白了:
    https://kknews.cc/tech/p8bpz2p.html
    incompatible
    incompatible
    Jul 26, 2017❤️4
    35
    @LioMore 不是,不要听本帖的草台班子们胡扯用什么 int。正确的方法是用 decimal。
    PHP 用户可以看一下 http://de2.php.net/manual/en/ref.bc.php
    dikT
    dikT
    Jul 26, 2017❤️1
    36
    现在想想微信的钱 fee 就是按分来存储.当时觉得很奇怪, 恍然大悟[doge]
    wsy2220
    wsy2220
    Jul 26, 2017
    37
    心真大
    msg7086
    msg7086
    Jul 27, 2017
    38
    浮点数大都是不精确的数据存储。
    比如 5.59 这个数就无法用浮点数表达,因为在二进制中是个无理数。
    LioMore
    LioMore
    Jul 27, 2017
    39
    @incompatible 好的,感谢
    solaro
    solaro
    OP
    Jul 27, 2017
    40
    被坑到了。谢谢各位
    incompatible
    incompatible
    Jul 27, 2017 via iPhone❤️1
    41
    @solaro int 或 bigint 没法处理小数位数,两个数相除时是要处理结果保留几位小数以及 ceiling(四舍五入 / 去尾 / 进一)的规则的,所以应该用(数学意义上的)decimal。
    那哥们用 string 的原因是 php 这个所谓的最好的语言居然没有内置对 decimal 的支持,而是需要通过 bc extension 处理 string 来实现对 decimal 的操作。
    lestat
    lestat
    Jul 28, 2017 via iPhone
    42
    写个专门运算的函数,全部乘以 100 之后运算,把结果再除以 100 返回,可以参考微信支付的做法
    mingyun
    mingyun
    Jul 29, 2017
    43
    @stabc 链接 500 Internal Server Error
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1537 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 77ms · UTC 02:00 · PVG 10:00 · LAX 18:00 · JFK 21:00
    ♥ Do have faith in what you're doing.