基于PHPExcel的函数RATE()返回NAN()

时间:2012-04-07 01:06:56

标签: php phpexcel nan financial

我有这段代码:http://pastebin.com/Sd9WKZFr

当我调用类似rate(60, -6000, 120000)的内容时,它会返回NAN个结果,但MS Excel上的相同功能会返回0,04678...。我有同样的问题,尝试-5000,-4000,-3000和-2000。

当我调试代码时,我看到关于8/9迭代,第29行开始返回NAN结果,使所有其他结果也转为NAN

但是,当我打电话给rate(60, -1000, 120000)时,它会返回float -0.02044...,与MS Excel完全相同。

我已经尝试将所有的数学计算转换为 BCMath函数,但这样-6000的结果是错误的(-1.0427 ...而不是0 ,04678 ...)但是使用-1000结果是正确的,匹配excel的结果。

有没有办法让它正常工作?

提前感谢任何有用的观点。

2 个答案:

答案 0 :(得分:2)

我需要做一些测试,以确保在其他情况下没有不良影响;但以下看起来好像可以解决这个问题,并且肯定会为您的参数计算正确的速率值RATE(60,-6000,120000)在迭代15中稳定在0.046781916422493。

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

答案 1 :(得分:1)

我不建议使用Secant方法来查找internal rate of return,因为它比其他首选迭代方法(如Newton Raphson方法)消耗更多时间。从代码中看,设置最多128次迭代是浪费时间

Newton Raphson method to find RATE与两个TVM等式中的任何一个一起使用只需3次迭代

TVM Eq. 1: PV(1+i)^N + PMT(1+i*type)[(1+i)^N -1]/i + FV = 0

f(i) = 0 + -6000 * (1 + i * 0) [(1+i)^60 - 1)]/i + 120000 * (1+i)^60

f'(i) = (-6000 * ( 60 * i * (1 + i)^(59+0) - (1 + i)^60) + 1) / (i * i)) + 60 * 120000 * (1+0.05)^59

i0 = 0.05
f(i1) = 120000
f'(i1) = 42430046.1459
i1 = 0.05 - 120000/42430046.1459 = 0.0471718154728
Error Bound = 0.0471718154728 - 0.05 = 0.002828 > 0.000001

i1 = 0.0471718154728
f(i2) = 12884.8972
f'(i2) = 33595275.7358
i2 = 0.0471718154728 - 12884.8972/33595275.7358 = 0.0467882824629
Error Bound = 0.0467882824629 - 0.0471718154728 = 0.000384 > 0.000001

i2 = 0.0467882824629
f(i3) = 206.9714
f'(i3) = 32520602.801
i3 = 0.0467882824629 - 206.9714/32520602.801 = 0.0467819181458
Error Bound = 0.0467819181458 - 0.0467882824629 = 6.0E-6 > 0.000001

i3 = 0.0467819181458
f(i4) = 0.056
f'(i4) = 32503002.4159
i4 = 0.0467819181458 - 0.056/32503002.4159 = 0.0467819164225
Error Bound = 0.0467819164225 - 0.0467819181458 = 0 < 0.000001
IRR = 4.68%


TVM Eq. 2: PV + PMT(1+i*type)[1-{(1+i)^-N}]/i + FV(1+i)^-N = 0

f(i) = 120000 + -6000 * (1 + i * 0) [1 - (1+i)^-60)]/i + 0 * (1+i)^-60

f'(i) = (--6000 * (1+i)^-60 * ((1+i)^60 - 60 * i - 1) /(i*i)) + (0 * -60 * (1+i)^(-60-1))

i0 = 0.05
f(i1) = 6424.2628
f'(i1) = 1886058.972
i1 = 0.05 - 6424.2628/1886058.972 = 0.0465938165535
Error Bound = 0.0465938165535 - 0.05 = 0.003406 > 0.000001

i1 = 0.0465938165535
f(i2) = -394.592
f'(i2) = 2081246.2069
i2 = 0.0465938165535 - -394.592/2081246.2069 = 0.046783410646
Error Bound = 0.046783410646 - 0.0465938165535 = 0.00019 > 0.000001

i2 = 0.046783410646
f(i3) = 3.1258
f'(i3) = 2069722.0554
i3 = 0.046783410646 - 3.1258/2069722.0554 = 0.0467819004105
Error Bound = 0.0467819004105 - 0.046783410646 = 2.0E-6 > 0.000001

i3 = 0.0467819004105
f(i4) = -0.0335
f'(i4) = 2069813.5309
i4 = 0.0467819004105 - -0.0335/2069813.5309 = 0.0467819165937
Error Bound = 0.0467819165937 - 0.0467819004105 = 0 < 0.000001
IRR = 4.68%