PHP高精度/金钱//数学函数库-bcmath

本文探讨了为何在PHP中使用bcmath进行高精度数学运算,避免浮点数和整数溢出问题。讲解了bcadd、bccomp、bcdiv等核心函数,并通过实例演示了如何进行加、减、乘、除和比较操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么要使用 bcmath

首先我们要明白为什么要使用 bcmath,因为我们平时没怎么使用它们,但是我们在做高精度计算,或者金钱计算的时候对结果要尽可能的精确且可控,但是编程语言对浮点数和大整数的运算,表示,存储方面都存在一定的问题,这个和语言无关。

先来看浮点数的问题

$f = 0.58;
$r = $f * 100;
var_dump($r); // float(58)
var_dump(intval($r)); // int(57)

首先就是你看到的和实际内存中存储的不一致,实际存储可能是 0.58 -> 0.57999999999999996,而 $r -> 57.999999999999996,这就出现了不可控,甚至到了不可用的地步。

其次是大的整数,而整数能存储的最大值是受操作系统限制的,比如有32位和64位系统之分,当你要存储的值超过了上限,那么就会被当做浮点数来存了,牵涉到浮点数就可能存在计算偏差。

$a = PHP_INT_MAX;  
$b = PHP_INT_MAX+1; 
var_dump($a); // int(2147483647)
var_dump($b); // float(2147483648)
var_dump($a === $b - 1); // bool(false)

针对以上的问题,可以使用字符串来存储浮点数和大整数。

$f = 0.58;
$r = strval($f*100);
var_dump(intval($r)); // int(58)

基于这样的思路,于是有了 PHP bcmath ,每个语言都有相对应的实现。

关于 bcmath (Binary Calculator)

对于任意精度的数学,PHP提供了支持用字符串表示的任意大小和精度的数字的二进制计算,最多为 2147483647-1(或0x7FFFFFFF-1)

本类函数仅在 PHP 编译时配置了 --enable-bcmath 时可用。PHP 的 Windows 版本已内建对此扩展的支持。不需要载入额外的扩展来使用这些函数。

它包含了如下的一些计算:相加,比较,相除,相减,求余,相乘,n次方,配置默认小数点数目,求平方等等。这些函数在涉及到有关金钱的计算时比较有用。

  • bcadd 相加
  • bccomp 比较两个任意精度的数字,结果 1,0,-1
  • bcdiv 2个任意精度的数字除法计算
  • bcmod 对一个任意精度数字取模
  • bcmul 2个任意精度数字乘法计算
  • bcpow 任意精度数字的乘方
  • bcpowmod 先乘方,再取模
  • bcscale 设置所有bc数学函数的默认小数点保留位数
  • bcsqrt 任意精度数字的二次方根
  • bcsub2个任意精度数字的减法
bcadd

2个任意精度数字的加法计算

bcadd ( string $left_operand , string $right_operand , int $scale = ? ) : string

int $scale此可选参数用于设置结果中小数点后的小数位数。也可通过使用 bcscale() 来设置全局默认的小数位数,用于所有函数。如果未设置,则默认为 0

$a = '1.234';
$b = '5.366';

var_dump(bcadd($a, $b));     // string(1) "6"
var_dump(bcadd($a, $b, 4));  // string(6) "6.6000"
$a = '1.2348111111111111111111';
$b = '5.3152222222222222222222';

var_dump(bcadd($a, $b));     // string(1) "6"
var_dump(bcadd($a, $b, 2));  // string(6) "6.55"

小数的位数是相加后四舍五入再来截取的,位数不够的补0

bccomp

比较两个任意精度的数字的大小

bccomp ( string $left_operand , string $right_operand , int $scale = int ) : int

可选的scale参数表示要以几位小数来比较。

如果两个数相等返回0, 左边的数left_operand比较右边的数right_operand大返回1, 否则返回-1

var_dump(bccomp('1', '2'));     // int(-1)
var_dump(bccomp('1.00001', '-1', 3));  // int(1)
var_dump(bccomp('1.00001', '1', 3));  // int(0)
var_dump(bccomp('1.00001', '1', 5));  // int(1)
bcdiv

2个任意精度的数字除法计算

bcdiv ( string $left_operand , string $right_operand , int $scale = int ) : string

scale此可选参数用于设置结果中小数点后的小数位数。也可通过使用 bcscale() 来设置全局默认的小数位数,用于所有函数。如果未设置,则默认为 0

var_dump(bcdiv('105', '6.55957', 3));  // 16.007
bcmod

对一个任意精度数字取模

bcmod ( string $left_operand , string $modulus ) : string

返回字符串类型取模后结果,如果系数为0则返回null

echo bcmod('4', '2'); // 0
echo bcmod('2', '4'); // 2
bcmul

2个任意精度数字乘法计算

bcmul ( string $left_operand , string $right_operand , int $scale = int ) : string
echo bcmul('1.34747474747', '35', 3); // 47.161
echo bcmul('2', '4'); // 8
bcpow

任意精度数字的乘方

bcpow ( string $left_operand , string $right_operand , int $scale = ? ) : string
echo bcpow('4.2', '3', 2); // 74.08
bcpowmod

先乘方,再取模

bcpowmod ( string $num , string $exponent , string $modulus , int|null $scale = null ) : string
var_dump(bcpowmod('3', '3', '2', 0));  // string(1) "1"
bcscale

设置所有bc数学函数的默认小数点保留位数

bcscale ( int $scale ) : bool
bcsqrt

任意精度数字的二次方根

bcsqrt ( string $operand , int $scale = ? ) : string
bcsub

2个任意精度数字的减法

bcsub ( string $left_operand , string $right_operand , int $scale = int ) : string

参考

https://www.laruence.com/2013/03/26/2884.html

https://www.laruence.com/2011/12/19/2399.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值