2012-04-07 2 views
1

J'ai ce code: http://pastebin.com/Sd9WKZFrTAUX fonction basée PHPExcel() retour NAN()

Quand j'appelle quelque chose comme rate(60, -6000, 120000) il me renvoie un résultat, mais la même fonction NAN sur MS Excel me retourne 0,04678.... J'ai le même problème en essayant -5000, -4000, -3000 et -2000. Lorsque je débogue le code, je vois qu'à propos de l'itération 8/9, le numéro de ligne 29 commence à renvoyer un résultat NAN, rendant tous les autres résultats à NAN aussi. MAIS, quand j'appelle quelque chose comme rate(60, -1000, 120000) il me renvoie float -0.02044..., exactement le même résultat de MS Excel.

J'ai déjà tryed pour convertir tous des calculs mathématiques dans fonctions bcmath, mais cette façon, les résultats de -6000 est faux (-1,0427 ... au lieu de 0,04678 ...) mais en utilisant - 1000 le résultat est correct, correspondant au résultat d'Excel.

Existe-t-il un moyen de le faire fonctionner correctement?

Merci d'avance pour tout renseignement utile à ce sujet.

+1

Ce sont seulement guessings, cela ressemble avant tout comme un calcul problème. - est-il possible que le taux $ puisse être négatif alors log() n'est pas défini dans la ligne 29? - vos parenthèses sont-elles réglées correctement? – worenga

+0

Salut @mightyuhu, il n'y a pas d'erreurs de sintaxe car l'utilisation de -1000 fonctionne très bien. En même temps, c'est une fonction de stable phpexcel. Merci quand même. – slinstj

+0

@sidtj @mightyuhu a raison, 'rate (60, -6000, 120000)' produit un résultat intermédiaire de Rate <1 (vous l'avez déjà identifié à l'itération 8/9ème). Vous devez travailler sur votre algorithme –

Répondre

2

Je devrai faire quelques tests pour m'assurer qu'il n'y a pas d'effets négatifs dans d'autres situations; mais ce qui suit semble que cela pourrait résoudre ce problème, et calcule certainement la valeur du taux correct pour vos arguments TAUX (60, -6000, 120000) se stabilise à ,046781916422493 dans l'itération 15.

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

Salut Baker, j'étais sur le point de vous envoyer ce lien dans le forum de phpexcel quand j'ai vu qui l'avait envoyé: vous-même Merci beaucoup, je vais essayer dans un autre Circonstances avant d'accepter votre réponse Merci – slinstj

+0

Déjà fait quelques essais: cela ne fonctionne pas avec votre exemple de taux (60, -1000, 120000), en recherchant plus loin –

+0

Quel dommage.À l'aide de 60, -6000, 120000 je reçois 0.046781916422493 , le même résultat de LibreOffice Calc (Excel ne peut pas le faire, renvoyant #NUM!). Mais les valeurs inférieures (-1000, -2000, etc) cette fonction, utilisant maintenant abs(), passent vraiment pour retourner des résultats erronés. Nous vous remercions de vos précieux efforts. – slinstj

1

Je ne suggère d'utiliser Méthode sécante pour trouver internal rate of return car elle consomme plus de temps que d'autres méthodes itératives préférées telles que la méthode de Newton Raphson. À partir du code, il semble mettre un maximum de 128 itérations est une perte de temps

En utilisant Newton Raphson method to find RATE avec l'une des deux TVM équations ne prend que 3 itérations

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%