Я пишу оболочку для расширения bcmath
иошибка №10116относительно bcpow( )
особенно раздражает — он приводит $right_operand
( $exp
) к (собственному PHP, не произвольной длины) целому числу, поэтому, когда вы пытаетесь вычислить квадрат корень (или любой другой корень выше, чем 1
) числа вы всегда получите 1
вместо правильного результата.
Я начал искать алгоритмы, которые позволили бы мне вычислить корень числа n-й степени, и я нашел этот ответ, который выглядит довольно солидно, я на самом деле расширил формулу, используя WolframAlpha и Мне удалось улучшить его скорость примерно на 5%, сохранив при этом точность результатов.
Вот реализация на чистом PHP, имитирующая мою реализацию BCMath и ее ограничения:
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
равно 0.123456
, его обратное значение будет 8.10005
и результат pow()
и _pow ()
будет немного отличаться ( demo):
pow(2, 0.123456)
= 1.0893412745953
_pow(2, 0.123456)
= 1.0905077326653
_pow(2, 1/8)
= _pow(2, 0.125)
= 1.0905077326653
Как я могу достичь того же уровня точности, используя «ручные» экспоненциальные вычисления?