1

最初のローン額、返済回数、返済額を考慮して、ローンの利息を計算しようとしています。基本的な数式を使用して十分に近い数値を取得できないようです。そのため、ここで使用されているニュートン ラフソン法を使用しようとしています: http://www.efunda.com/formulae/finance /loan_calculator.cfm (これはまさに私が実装しようとしている機能です)

PHPExcel の RATE() 関数を使用してみましたが、入力に対して正しい出力が得られません。つまり、利率が 0.1% または同様に返されます (実際には 5.75% に近い場合)。

これは、PHPExcel の関連コードです。

/** FINANCIAL_MAX_ITERATIONS */
define('FINANCIAL_MAX_ITERATIONS', 128);

/** FINANCIAL_PRECISION */
define('FINANCIAL_PRECISION', 1.0e-08);

/**
 * Convert an array to a single scalar value by extracting the first element
 *
 * @param   mixed       $value      Array or scalar value
 * @return  mixed
 */
function flattenSingleValue($value = '') {
    while (is_array($value)) {
        $value = array_pop($value);
    }

    return $value;
}

/**
 * RATE
 *
 * Returns the interest rate per period of an annuity.
 * RATE is calculated by iteration and can have zero or more solutions.
 * If the successive results of RATE do not converge to within 0.0000001 after 20 iterations,
 * RATE returns the #NUM! error value.
 *
 * Excel Function:
 *      RATE(nper,pmt,pv[,fv[,type[,guess]]])
 *
 * @access  public
 * @category Financial Functions
 * @param   float   nper        The total number of payment periods in an annuity.
 * @param   float   pmt         The payment made each period and cannot change over the life
 *                                  of the annuity.
 *                              Typically, pmt includes principal and interest but no other
 *                                  fees or taxes.
 * @param   float   pv          The present value - the total amount that a series of future
 *                                  payments is worth now.
 * @param   float   fv          The future value, or a cash balance you want to attain after
 *                                  the last payment is made. If fv is omitted, it is assumed
 *                                  to be 0 (the future value of a loan, for example, is 0).
 * @param   integer type        A number 0 or 1 and indicates when payments are due:
 *                                      0 or omitted    At the end of the period.
 *                                      1               At the beginning of the period.
 * @param   float   guess       Your guess for what the rate will be.
 *                                  If you omit guess, it is assumed to be 10 percent.
 * @return  float
 **/
function RATE($nper, $pmt, $pv, $fv = 0.0, $type = 0, $guess = 0.1) {
    $nper   = (int) flattenSingleValue($nper);
    $pmt    = flattenSingleValue($pmt);
    $pv     = flattenSingleValue($pv);
    $fv     = (is_null($fv))    ? 0.0   :   flattenSingleValue($fv);
    $type   = (is_null($type))  ? 0     :   (int) flattenSingleValue($type);
    $guess  = (is_null($guess)) ? 0.1   :   flattenSingleValue($guess);

    $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 (($nper * abs($pmt)) > ($pv - $fv))

            $x1 = abs($x1);

        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()

関数への私の入力は次のとおりです。

RATE(60, 1100, 50000);     // Outputs 0.00420298759161

RATE(60, -1100, 50000);    // Outputs 0.00959560344752

RATE(60, 1100, 66000);     // Outputs -1.05036370955

60 は 5 年間の月数、1100 または -1100 は毎月の返済額、50,000 は借入総額です。

私は数学者ではありません。上記の関数はあまり意味がありませんが、私の読書によると、これが率を計算する最良の方法です。うまくいけば、私は愚かな間違いを犯しているだけです...

4

1 に答える 1

3

「ニュートン・ラフソン法」の代わりに「二分探索法」を使うこともできます。

function rate($month, $payment, $amount)
{
    // make an initial guess
    $error = 0.0000001; $high = 1.00; $low = 0.00;
    $rate = (2.0 * ($month * $payment - $amount)) / ($amount * $month);

    while(true) {
        // check for error margin
        $calc = pow(1 + $rate, $month);
        $calc = ($rate * $calc) / ($calc - 1.0);
        $calc -= $payment / $amount;

        if ($calc > $error) {
            // guess too high, lower the guess
            $high = $rate;
            $rate = ($high + $low) / 2;
        } elseif ($calc < -$error) {
            // guess too low, higher the guess
            $low = $rate;
            $rate = ($high + $low) / 2;
        } else {
            // acceptable guess
            break;
        }
    }

    return $rate * 12;
}

var_dump(rate(60, 1000, 20000));
// Return 0.56138305664063, which means 56.1383%

「二分探索法」や「ニュートン・ラフソン法」は基本的に当て推量法です。最初の推測を行い、許容可能な推測に達するまで、時間の経過とともに推測を改善します。通常、「ニュートン ラフソン法」は「推測の改善」戦略が優れているため、「二分探索」よりも高速です。

コンセプトはシンプルです:

ここに画像の説明を入力

知りたいrのは金利です。N、C、および P はわかっています。 が何であるかはわかりませんがr、0.00 から 1.00 までの任意の数を推測してみましょう。(この場合、金利が 100% を超えることはないと想定しています)。

  • ステップ 1: ランダムに推測する
  • ステップ 2: 率を式に当てはめます。
  • ステップ 3: 推測が低すぎるか、推測が高すぎるかを確認し、ステップ 2 に進む
  • ステップ 4: 推測が高すぎるかどうかを確認し、推測を下げて、ステップ 2 に進む
  • ステップ 5: 許容レートを取得しました。
  • ステップ 6:r月額料金です。年率を取得するには、12 を掛けます。
于 2013-09-17T02:44:53.227 に答える