

上图实际开发业务中,碰到了个坑,
数据库用的 mysql 左边 5.590 在数据库中存储是 decimal(10,3) 右边是换算出来的 float
现在 floatval(5.590) < floatval(5.59)
我 sun
1 elgae 2017-07-26 16:56:51 +08:00 关系到钱的业务用浮点数,心很大。 |
2 7654 2017-07-26 17:00:41 +08:00 有个故事,某企财务将全厂工资的几分零头抹掉,每月可偷几千块 |
3 Jacklee 2017-07-26 17:03:50 +08:00 计算机存储浮点型都不是精确的,如楼上所说,不能直接比较大小啊。涉及钱的业务更不能用啊。 |
4 Jacklee 2017-07-26 17:04:25 +08:00 补一句,这不是 PHP 的锅哈 |
5 oh 2017-07-26 17:09:27 +08:00 抛去楼上已解决说的,不知道楼主有没有试过在 if 前面 var_dump(floatval()) 看看这两个变量对比的时候是多少? |
6 Biscuits 2017-07-26 17:12:44 +08:00 5.59 可能是 5.5904444 |
7 bombless 2017-07-26 17:12:46 +08:00 比较的时候乘 100 按整数比吧 |
8 lujiajing1126 2017-07-26 17:12:52 +08:00 via iPhone 楼主需要复习一下 IEEE754 |
9 goodspb 2017-07-26 17:12:56 +08:00 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 |
10 ovear 2017-07-26 17:14:02 +08:00 请使用 bccomp |
11 exch4nge 2017-07-26 17:14:53 +08:00 对 PHP 不熟悉……不过表示金钱的类型应该用专门的 decimal 类型吧…… |
13 gclove 2017-07-26 17:15:50 +08:00 同上, 计算千万不要用符点, 还不如用大数计算 建议直接乘 100 取整 为什么设置 3 位, 你们应用还有微分 ? 有的话可以乘以 1000 取整 浮点在每种变成语言都有陷阱(坑), 经验不够老练都会踩上 |
14 gclve 2017-07-26 17:21:30 +08:00 非用浮点, 计算前值一定要进行类型转换 因为你不知道它是 整数, 浮点, 还是 字符串 |
15 solaro OP 本地开发环境用 5.6.27 没毛病,生产环境用 7.1 就触发异常。。。我日 |
16 doushiyinweini 2017-07-26 17:24:10 +08:00 |
17 moult 2017-07-26 17:25:36 +08:00 就算知道什么情况下出现这个问题,那又如何? 1、从数据库里面查询出来的浮点数,请使用 string。 2、http://php.net/manual/en/book.bc.php 3、个人癖好,有段时间,金钱我用 int 来存储,单位是分。不过现在都用 string 来做了。 |
20 zhs227 2017-07-26 17:34:48 +08:00 涉及到价格我每次都是*100 以后按整数存。float 的比较容易出问题,越相近越容易出问题。 |
22 ety001 2017-07-26 17:54:37 +08:00 之前用过整数(就是存储到分),后来就用 decimal 了。 |
23 oneonesv 2017-07-26 18:00:31 +08:00 浮点数精度不够 可能会有类似 0.111 != 0.111 的情况 PHP 文档 浮点数 章节里面有讲 |
24 stabc 2017-07-26 18:01:02 +08:00 谁能说下这种浮点数在计算中常见的坑? |
25 LioMore 2017-07-26 18:06:16 +08:00 请问一下,正确的做法是只用分来计算并使用整数吗? |
27 maypu 2017-07-26 18:49:14 +08:00 via Android 算错的时候,哈哈哈哈哈哈 |
28 a591826944 2017-07-26 19:54:37 +08:00 LZ 你的心真大。。浮点数算金额。。 |
29 a591826944 2017-07-26 19:55:11 +08:00 LZ 你试试 floor(8.29 * 100 * 100 / 100) 的结果 体会一下。。。 这真不是 PHP 的锅、、 |
30 bianchensz 2017-07-26 21:11:56 +08:00 233 就算是我老妈用 excel 涉及到钱的都要套个 round 取整,你这也是心大 |
31 xzem 2017-07-26 22:10:14 +08:00 via Android 被浮点坑过一次,再也不敢用浮点做计算 比较了 |
32 blankme 2017-07-26 22:18:51 +08:00 ``` if (fabs(a - b) > 1e-3 && a < b) ``` |
33 zhx1991 2017-07-26 23:16:42 +08:00 钱用浮点数什么都可能发生 想追究细节的话了解一下计算机怎么表示小数就明白了 |
34 stabc 2017-07-26 23:35:50 +08:00 看一下这个明白了: https://kknews.cc/tech/p8bpz2p.html |
35 incompatible 2017-07-26 23:42:03 +08:00 @LioMore 不是,不要听本帖的草台班子们胡扯用什么 int。正确的方法是用 decimal。 PHP 用户可以看一下 http://de2.php.net/manual/en/ref.bc.php |
36 dikT 2017-07-26 23:48:08 +08:00 现在想想微信的钱 fee 就是按分来存储.当时觉得很奇怪, 恍然大悟[doge] |
37 wsy2220 2017-07-26 23:54:47 +08:00 心真大 |
38 msg7086 2017-07-27 00:16:47 +08:00 浮点数大都是不精确的数据存储。 比如 5.59 这个数就无法用浮点数表达,因为在二进制中是个无理数。 |
39 LioMore 2017-07-27 00:20:13 +08:00 @incompatible 好的,感谢 |
40 solaro OP 被坑到了。谢谢各位 |
41 incompatible 2017-07-27 18:09:45 +08:00 via iPhone @solaro int 或 bigint 没法处理小数位数,两个数相除时是要处理结果保留几位小数以及 ceiling(四舍五入 / 去尾 / 进一)的规则的,所以应该用(数学意义上的)decimal。 那哥们用 string 的原因是 php 这个所谓的最好的语言居然没有内置对 decimal 的支持,而是需要通过 bc extension 处理 string 来实现对 decimal 的操作。 |
42 lestat 2017-07-28 20:14:58 +08:00 via iPhone 写个专门运算的函数,全部乘以 100 之后运算,把结果再除以 100 返回,可以参考微信支付的做法 |