私はbcmath
拡張機能のラッパーを書いていますが、バグ #10116はbcpow()
特に厄介です - $right_operand
( $exp
) を (ネイティブ PHP、任意の長さではない) 整数にキャストするため、平方根 (またはその他の任意の長さ) を計算しようとすると正しい結果ではなく、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)
てうまく機能するようです。たとえば、$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
「手動」の指数計算を使用して同じレベルの精度を達成するにはどうすればよいですか?