金额计算的坑

(int)(32.8 * 100);//3279

一直以为 * 100就没问题了,结果支付时出了差额,大家注意,可以用bcmul函数来计算

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 28

这是因为浮点型数据在计算机中存储结构造成的,所以永远不要相信一个浮点数已经精确到了最后一位。

还有,在金钱的计算中,仅仅使用bc函数是不够的,因为他是粗暴的舍去多余的位数。
根据业务场景,你可以结合使用 round() 、floor() 、ceil() 等函数实现金额的计算。

题外:如果你涉及的计算数值,有可能超出一个INT的范围,那么你要当心在 float 转为 int 时候的溢出问题。

2年前 评论
忆往昔弹指间 (作者) 2年前
helloStar (楼主) 2年前
ononl 2年前
忆往昔弹指间 (作者) 2年前
你看我吊吗啊

看来是微信支付。。

2年前 评论
helloStar (楼主) 2年前

这是因为浮点型数据在计算机中存储结构造成的,所以永远不要相信一个浮点数已经精确到了最后一位。

还有,在金钱的计算中,仅仅使用bc函数是不够的,因为他是粗暴的舍去多余的位数。
根据业务场景,你可以结合使用 round() 、floor() 、ceil() 等函数实现金额的计算。

题外:如果你涉及的计算数值,有可能超出一个INT的范围,那么你要当心在 float 转为 int 时候的溢出问题。

2年前 评论
忆往昔弹指间 (作者) 2年前
helloStar (楼主) 2年前
ononl 2年前
忆往昔弹指间 (作者) 2年前

金额最小单位是1分,也就是1,以元作为单位就是0.01。出现浮点数精度丢失有可能是因为有限位数存储超过这个位数的小数,例如数据库decimal(5,1),范围应该是-999.9~999.9(一般来说负数用的少),我存储一个数为1.23,数据库里显示是1.2,但是计算的时候可能就会出问题;因此有几种办法:

一种是以1为最小单位,这样就不会有太多问题,但是每次存取都需要转换; 二是精确的位数存储精确的位数; 三是以字符串的形式存储。 推荐是使用第二种,前端的计算显示可能也会有问题,但是整体来说对于金额是最友好的。

2年前 评论
helloStar (楼主) 2年前

var_dump(32.8 * 100) ; //float(3280) 是个无限接近 3280 的浮点型,类似 3279.999..
(int) 强制转成整形,就变成 3279 了。floor($b);//3279
这样的话还不如不转,直接 32.8 * 100

2年前 评论
helloStar (楼主) 2年前

四舍五入,保留2位再计算.

2年前 评论
helloStar (楼主) 2年前
rufo (作者) 2年前
rufo (作者) 2年前
没前途的程序员 2年前
laisxn

金额存成分/计算的时候先转分计算,最后结果的时候再转成元,问题:就是项目使用要统一规范,要不也是坑

2年前 评论
helloStar (楼主) 2年前

存 "分"

2年前 评论
helloStar (楼主) 2年前

你看似有穷的小数, 在计算机的二进制表示里却是无穷的

(int)(32.8 * 100);//3279

32.8 这个小数在计算机中就是不精确的,所以用不精确的值再做乘法加多少个 0 也没有用。
代码里全用「分」,不考虑「元」,让前端转。就不会有 “计算麻烦” 这件事了
可以看下鸟哥的文章:PHP浮点数的一个常见问题的解答

2年前 评论

金额单位都已分为单位存就可以了啊,你看看微信支付的接口,也是已分为单位的。

专业肯定不会出现计算导致精度损失的问题。

2年前 评论

我都是用整型来算的...数据库也是存整型,,显示除/100就行了

2年前 评论

涉及金钱都是使用bc计算,其它非敏感都是四舍五入,存分显示还要计算一遍,我用的少,都是使用sql decimal类型来存储。

2年前 评论
giao哥

数据库存储使用整数瑟以分为单位

2年前 评论

composer require money

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!