我正在为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。例如,如果$expis 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
如何使用“手动”指数计算达到相同的精度水平?