2012-04-07 12 views
1

Ich habe diesen Code: http://pastebin.com/Sd9WKZFrPHPExcel basierte Funktion RATE() Rückkehr NAN()

Wenn ich so etwas wie rate(60, -6000, 120000) nennen es gibt mir ein NAN Ergebnis, aber die gleiche Funktion auf MS Excel gibt mir 0,04678.... Ich habe das gleiche Problem versucht -5000, -4000, -3000 und -2000.

Wenn ich den Code debuggen, sehe ich, dass über die 8/9-Iteration die Zeilennummer 29 beginnt, ein NAN Ergebnis zurückzugeben, so dass alle anderen Ergebnisse zu NAN drehen.

ABER, wenn ich etwas wie rate(60, -1000, 120000) aufrufen, gibt es mir eine float -0.02044..., genau das gleiche Ergebnis von MS Excel.

Ich habe bereits tryed, aber auf diese Weise die Ergebnisse von -6000 all von mathematischen Berechnungen in BCMath Funktionen zu konvertieren, ist falsch (-1,0427 ... statt 0,04678 ...), aber unter Verwendung von - 1000 ist das Ergebnis korrekt und entspricht dem Ergebnis von Excel.

Gibt es eine Möglichkeit, damit es richtig funktioniert?

Vielen Dank im Voraus für alle nützlichen Anblick darüber.

+1

dies nur guessings ist nimmt, das sieht in erster Linie als Berechnungs Problem. - ist es möglich $ Rate kann negativ werden, so dass log() in Zeile 29 undefiniert ist? - sind Ihre Klammern richtig eingestellt? – worenga

+0

Hallo @ Mightyuhu, es gibt keine sintaxe Fehler verursachen mit -1000 funktioniert es gut. Gleichzeitig ist es eine Funktion von stabilem phpexcel. Danke trotzdem. – slinstj

+0

@sidtj @ Mightyuhu ist richtig, 'Rate (60, -6000, 120000)' erzeugt ein Zwischenergebnis von Rate <1 (Sie haben dies bereits bei der 8./9. Iteration identifiziert). Sie müssen an Ihrem Algorithmus arbeiten –

Antwort

2

Ich muss einige Tests durchführen, um sicherzustellen, dass in anderen Situationen keine negativen Auswirkungen auftreten. aber die folgende aussieht, als ob es könnte dieses Problem beheben, und berechnet sicherlich den richtige Rate Wert für Ihre Argumente RATEN (60, -6000, 120000) stabilisiert dich bei ,046781916422493 in Iteration 15.er

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

Hallo Baker, ich wollte dir diesen Link im phpexcel-Forum schicken, als ich sah, wer es geschickt hatte: du selbst. Ich danke dir so viel, ich werde es anders versuchen circunstances, bevor Sie Ihre Antwort akzeptieren. "Danke. – slinstj

+0

Bereits einige Tests durchgeführt: es funktioniert nicht mit Ihrer Rate (60, -1000, 120000) Beispiel, weitere Untersuchungen –

+0

Was für ein Pech. Mit 60, -6000, 120000 bekomme ich 0,046781916422493 , das gleiche Ergebnis von LibreOffice Calc (Excel kann das nicht, gibt #NUM zurück!). Aber niedrigere Werte (-1000, -2000, usw.) Diese Funktion, die nun abs() verwendet, wird wirklich übergeben, um falsche Ergebnisse zurückzugeben. Vielen Dank für Ihre wertvollen Bemühungen. – slinstj

1

würde ich nicht vorschlagen, mit Secant-Methode, um internal rate of return zu finden, da es mehr Zeit als andere bevorzugte iterative Methoden wie Newton Raphson-Methode verbraucht. Von dem Code scheint es maximal 128 Iterationen Einstellung ist eine Verschwendung von Zeit

Mit Newton Raphson method to find RATE mit einem der beiden TVM Gleichungen nur drei Iterationen

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%