Воссоздать функцию скорости Excel с помощью метода Ньютона
Я работаю над преобразованием ипотечного калькулятора в PHP, но мне не обязательно нужно решение PHP. Я ищу логику, необходимую для репликации Excel . Я нашел решение, которое использует разделение пополам, и если хуже, я использую это.
Я знаю, что кто-то там, в мире паутины, знает о такой функции, поэтому я хотел бы получить простой ответ, а не создавать решение из царапать.
ссылки:
- http://office.microsoft.com/en-us/excel-help/rate-HP005209232.aspx
- http://en.wikipedia.org/wiki/Newton%27s_method
спасибо
2 ответов
реализация функции MS Excel RATE () с использованием секущего метода (конечно-разностная аппроксимация метода Ньютона), взятого из PHPExcel:
define('FINANCIAL_MAX_ITERATIONS', 128);
define('FINANCIAL_PRECISION', 1.0e-08);
function RATE($nper, $pmt, $pv, $fv = 0.0, $type = 0, $guess = 0.1) {
$rate = $guess;
if (abs($rate) < FINANCIAL_PRECISION) {
$y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
} else {
$f = exp($nper * log(1 + $rate));
$y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
}
$y0 = $pv + $pmt * $nper + $fv;
$y1 = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
// find root by secant method
$i = $x0 = 0.0;
$x1 = $rate;
while ((abs($y0 - $y1) > FINANCIAL_PRECISION) && ($i < FINANCIAL_MAX_ITERATIONS)) {
$rate = ($y1 * $x0 - $y0 * $x1) / ($y1 - $y0);
$x0 = $x1;
$x1 = $rate;
if (abs($rate) < FINANCIAL_PRECISION) {
$y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
} else {
$f = exp($nper * log(1 + $rate));
$y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
}
$y0 = $y1;
$y1 = $y;
++$i;
}
return $rate;
} // function RATE()
Я попытался использовать код выше, но результаты просто не такие же, как Excel (или Google Spreadsheet).
Я не знаю, нужно ли вам реализовать эту функцию, но в любом случае я посмотрел, как был построен этот алгоритм, и хотя я не смог получить доступ к исходному коду excel (или листу google), я обнаружил, что это не простой расчет. Об этой математике, подробнее можно прочитать здесь:
https://brownmath.com/bsci/loan.htm#Eq8
функция в PHP может быть примерно такой:
function rate($nprest, $vlrparc, $vp, $guess = 0.25) {
$maxit = 100;
$precision = 14;
$guess = round($guess,$precision);
for ($i=0 ; $i<$maxit ; $i++) {
$divdnd = $vlrparc - ( $vlrparc * (pow(1 + $guess , -$nprest)) ) - ($vp * $guess);
$divisor = $nprest * $vlrparc * pow(1 + $guess , (-$nprest - 1)) - $vp;
$newguess = $guess - ( $divdnd / $divisor );
$newguess = round($newguess, $precision);
if ($newguess == $guess) {
return $newguess;
} else {
$guess = $newguess;
}
}
return null;
}