Sto scrivendo un wrapper per l'estensione bcmath
, e bug #10116 riguardo bcpow()
è particolarmente fastidioso - proietta l'$right_operand
($exp
) ad un (PHP nativo, non lunghezza arbitraria) intero, quindi quando si tenta di calcolare la radice quadrata (o qualsiasi altra radice superiore a 1
) di un numero si finisce sempre con 1
invece del risultato corretto.Calcolo in virgola mobile Powers (PHP/BCMath)
ho iniziato la ricerca di algoritmi che mi permettesse di calcolare la radice ennesima di un numero e mi found this answer che sembra piuttosto solido, in realtà ho expanded the formula usando WolframAlpha e sono stato in grado di migliorare la sua velocità di circa il 5%, mantenendo la precisione dei risultati.
Ecco un'implementazione PHP puro mimando mia implementazione BCMath e suoi limiti:
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;
}
Quanto sopra seems to work greattranne quando 1/fmod($exp, 1)
non cedere un numero intero. Ad esempio, se $exp
è 0.123456
, il suo inverso sarà 8.10005
e l'esito della pow()
e _pow()
sarà un po 'diverso (demo):
pow(2, 0.123456)
=1.0893412745953
_pow(2, 0.123456)
=1.0905077326653
_pow(2, 1/8)
=_pow(2, 0.125)
=1.0905077326653
Come posso ottenere lo stesso livello di accuratezza usando i calcoli esponenziali "manuali"?
Sta funzionando esattamente come pubblicizzato. '_pow' 'arrotonda' la parte frazionaria al più vicino' 1/n'. Potresti fare questo lavoro in modo ricorsivo. Quindi, dopo aver calcolato '_pow (2, 0.125)', si calcola '_pow (2.0.125-123456)' e così via. –
Ah, ora capisco. Quindi bcmath non ha 'exp' e' log' o ci sono altri motivi per cui 'a^b = exp (b * log (a))' non è un'opzione? La ricorsione suggerita da Jeffrey naturalmente funzionerebbe, ma la sua velocità potrebbe non essere soddisfacente se hai bisogno di molti '1/k' per rappresentare l'esponente. Scrivere l'esponente come numero razionale 'n/d' e calcolare' (a^n)^(1/d) 'un'opzione, o deve essere troppo grande' n' e 'd' essere previsto? Forse vale la pena di investigare è approssimare l'esponente con un numero razionale con un denominatore piccolo (espansione della frazione continua) e fare il resto con la ricorsione. –
@JeffreySax: Ah, capisco ... È un fiasco ma non sembra funzionare (http://codepad.org/eI4ykyQU) o mi manca qualcosa? –