我正在为bcmath
扩展编写一个包装器,而关于错误 #10116的问题bcpow()
特别烦人——它将$right_operand
( $exp
) 转换为(原生 PHP,不是任意长度)整数,因此当您尝试计算平方根(或任何其他root 高于1
) 的一个数字,1
而不是正确的结果。
我开始寻找可以让我计算数字的第 n 根的算法,我发现这个答案看起来很可靠,我实际上使用 WolframAlpha扩展了公式,我能够在保持准确性的同时将速度提高约 5%的结果。
这是一个模仿我的 BCMath 实现及其局限性的纯 PHP 实现:
function _pow($n, $exp)
{
$result = pow($n, intval($exp)); // bcmath casts $exp to (int)
if (fmod($exp, 1) > 0) // does $exp have a fracional part higher than 0?
{
$exp = 1 / fmod($exp, 1); // convert the modulo into a root (2.5 -> 1 / 0.5 = 2)
$x = 1;
$y = (($n * _pow($x, 1 - $exp)) / $exp) - ($x / $exp) + $x;
do
{
$x = $y;
$y = (($n * _pow($x, 1 - $exp)) / $exp) - ($x / $exp) + $x;
} while ($x > $y);
return $result * $x; // 4^2.5 = 4^2 * 4^0.5 = 16 * 2 = 32
}
return $result;
}
上面的方法似乎很好用, 除非1 / fmod($exp, 1)
没有产生 integer。例如,如果$exp
is 0.123456
,它的倒数将会是并且8.10005
和 的结果会有点不同(demo):pow()
_pow()
pow(2, 0.123456)
=1.0893412745953
_pow(2, 0.123456)
=1.0905077326653
_pow(2, 1 / 8)
=_pow(2, 0.125)
=1.0905077326653
如何使用“手动”指数计算达到相同的精度水平?