bcadd 的精度问题?
以为是集合 sum 精度有问题,实际是bcadd的用法不正确。
这里有一个计算
$data = [
[
"id" => 9,
"user_id" => 2,
"value" => 0.000013
],
[
"id" => 19,
"user_id" => 2,
"value" => 0.000009
]
];
$sumValue = collect($data)->sum('value');
\Log::info('$sumValue:' . $sumValue);
// 结果:$sumValue:2.2E-5 是科学记数法
\Log::info('bcadd:' . bcadd($sumValue, 0, 8));
// 结果: bcadd:0.00000000
\Log::info('sprintf:' . sprintf('%.8f', $sumValue));
// 结果:sprintf:0.00002200
bcadd 数字、字符串、科学记数法类型的计算结果
1、数值
1) 4位小数,且前4位为0的
\Log::info('bcadd:' . bcadd(0.00002200, 0, 8));
// 结果:bcadd:0.00000000
2) 5位小数,且前4位有大于0的
\Log::info('bcadd:' . bcadd(0.00012200, 0, 8));
// 结果:bcadd:0.00012200
2、字符串
\Log::info('bcadd:' . bcadd('0.00002200', 0, 8));
// 等同于 \Log::info('bcadd:' . bcadd((string)0.00012200, 0, 8));
// 结果:bcadd:0.00002200
3、科学记数法
1) 5位小数,且前4位有大于0的
\Log::info('bcadd:' . bcadd(2.2E-4, 0, 8));
// 结果:bcadd:0.00022000
2) 5位小数,且第4位等于0
\Log::info('bcadd:' . bcadd(2.2E-5, 0, 8));
// 结果:bcadd:0.00000000
3) 5为小数,第4位大于0
\Log::info('bcadd:' . bcadd(12.2E-5, 0, 8));
// 结果:bcadd:0.00012200
结论是超过4位小数,且前4位都为0时,如不转为字符串进行bcadd计算,那么精度会有问题,结果会按0来计算;高精度计算,建议先转为字符串再进行计算。
根据需要,提前转为精度+1的字符串类型参与计算,如需保留6位,就取7位出来
$value = 0.000011;
$value = sprintf('%.7f', $value);
保存数据时,可转再转为6位
$model->value = bcadd($value, 0, 6);
$model->save();
注:laravel 从mysql读出的decimal类型的数据会转换为字符串类型,所以直接从数据库查询结果中取到的此类型字段可以直接参与bc函数的计算。
默认使用mysqli 或者 pdo-mysql从数据库中读出来的数据都会转换为字符串类型,通过设置参数可以把int/float/tinyint等会转为对应数据类型。laravel默认设置了这个转换参数,如下图:
参考:分享:Laravel 的 DB 查询是如何实现字段类型自动转的?
详细解释:
博客: Laravel Database——数据库服务的启动与连接
数据库驱动参考:
https://www.jianshu.com/p/7a9c0bb8fe22
https://blog.csdn.net/weixin_34406061/arti...
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: