Javascript IRR (Internal rate of return) Formula Accuracy

15,066

Solution 1

After a quick skim read through your code, the error seems to be related to floating point precision error. More information can be found here: http://ajaxian.com/archives/crock-on-floating-points-in-javascript

In older javascript engines, if you did 0.3 + 0.3 you get something like 0.600000000001

Though most javascript engines today return 0.6, under the hood, the problem remains. Adding floats together causes unexpected results. So in your case the

inc = 0.000001;
guest += inc;

seems to me, to be the problem.

A way to solve this would be to use whole numbers. So instead of 0.000001 you would use 1 and instead of 0.001 you would use 1000. Then divide your return result by 100000

Solution 2

We modified the code to achieve performance and accuracy. Try this:

function IRRCalc(CArray) {

  min = 0.0;
  max = 1.0;
  do {
    guest = (min + max) / 2;
    NPV = 0;
    for (var j=0; j<CArray.length; j++) {
          NPV += CArray[j]/Math.pow((1+guest),j);
    }
    if (NPV > 0) {
      min = guest;
    }
    else {
      max = guest;
    }
  } while(Math.abs(NPV) > 0.000001);
  return guest * 100;
}

Solution 3

Try this.

function NPV(discountRate, cashFlow){
    var npv = 0;
    for(var t = 0; t < cashFlow.length; t++) {
        npv += cashFlow[t] / Math.pow((1+ discountRate),t);
    }
    return npv;
}


function IRR(cashFlow,guess){
    guess = guess ? guess : 0.1;
    var npv;
    var cnt = 0;
    do
    {
        npv = NPV(guess,cashFlow);
        guess+= 0.001;

        cnt++;
    }
    while(npv > 0)

    return guess;
}

Solution 4

It's a floating point issue to be sure. You're going to want to use a library like BigDecimal.js to handle your values. It's really the only way to avoid this issue.

Solution 5

I would like to build on from @Zohaib Answer, but what I would like to do is show undefined where appropriate. The best I can do is get it to equal to zero. I am using this simple dataset irr_arr=[-100, 100, 100, 100, 100,100]. I would appreciate some advice.

//IRRCALC funtion that handles irr going to infinity 

function IRRCalc_test(CArray) {

  min = 0.0;
  max = 1.0;
  c=0;
  do {
    guest = (min + max) / 2;
    NPV = 0;
    for (var j=0; j<CArray.length; j++) {
          NPV += CArray[j]/Math.pow((1+guest),j);
    }
    if (NPV > 0) {
      min = guest;
      c++; 
    }
    else {
      max = guest;
      c++;
    }

    if(c>=15){ return guest*100; }
  } while(Math.abs(NPV) > 0.000001);
  return guest*100;
}


// some testing 

irr_arr=[-100, 100, 100, 100, 100,100]
irr_res_arr_expected=[0,0,61.8,83.93,92.76,96.6]
for(i=1;i<=irr_arr.length;i++){
console.log("irr_arr - ",irr_arr.slice(0,i));
console.log("IRRCalc - ",IRRCalc(irr_arr.slice(0,i)))
//console.log("irr_expected - ", irr_res_arr_expected[i-1])
//if(IRRCalc(irr_arr.slice(0,i))===parseFloat(irr_res_arr_expected[i-1]).toFixed(2)){console.log(i,"- TRUE")} else {console.log(i,"- FALSE")}
}

this is the output

irr_arr -  [-100]
IRRCalc -  0.00      <<<<<<<<<<<<<<<<<<<------- this should be 'undefined' and not 'zero'
irr_arr -  [-100, 100]
IRRCalc -  0.00
irr_arr -  [-100, 100, 100]
IRRCalc -  61.80
irr_arr -  [-100, 100, 100, 100]
IRRCalc -  83.93
irr_arr -  [-100, 100, 100, 100, 100]
IRRCalc -  92.76
irr_arr -  [-100, 100, 100, 100, 100, 100]
IRRCalc -  96.60

here is the excel of what I am trying to produce

enter image description here

Share:
15,066
dciso
Author by

dciso

Updated on July 28, 2022

Comments

  • dciso
    dciso almost 2 years

    I'm using a IRR function in javascript to create calculation a that is done in excel using its own IRR function. The problem is mine is little off and I have no idea why. Here's the code below.

    var IRRval = [];
    
    IRRval.push(-financed);
    for (i = 0; i < period; i++) {
        IRRval.push(rental);
    }
    
    var IRR = IRRCalc(IRRval, 0.001) * 0.01;
    
    function IRRCalc(CArray, guest) {
        inc = 0.000001;
        do {
            guest += inc;
            NPV = 0;
            for (var j=0; j < CArray.length; j++) {
                NPV += CArray[j] / Math.pow((1 + guest), j);
            }
        } while (NPV > 0);
        return guest * 100;
    }
    

    Now if you use these figures:


    Period 24

    Financed 22000

    Rental 1017.5000

    My Result is: 0.008523000000000175

    Excel Result is: 0.008522918


    OR


    Period 42

    Financed 218000

    Rental 5917.1429

    My Result is: 0.006247000000000489

    Excel Result is: 0.00624616


    The Excel function is called: =IRR(T12:T73,0.01) T12-T73 is the same figures I'm using.

    Any help would be much appreciated, Thanks Jason

    UPDATE

    I've solved it by changing the values below. But now the performance is too slow. Any ideas on how to improve this?

    IRRCalc(IRRval, 0.001)
    
    //to
    
    IRRCalc(IRRval, 0.0001)
    
    inc = 0.000001;
    
    //to
    
    inc = 0.00000001;
    
  • dciso
    dciso about 11 years
    Thanks for your reply. I tried using whole numbers only to get 8523000. Same level of accuracy.
  • whitneyit
    whitneyit about 11 years
    The / Math.pow() in NPV could be the next culprit. Either way, you probably won't be able to solve it there.
  • Giridaran Regunathan
    Giridaran Regunathan about 10 years
    Zohaib, Thanks for your code, its working like a charm when we giving more terms like 20 or 25 years, but its hanged when giving terms like 3 05 5. can you help on this?
  • Edward
    Edward almost 10 years
    @GiridaranRegunathan - you need to add a counter and exit after a certain number of iterations without resolution (the method fails and you have an undefined result). The actual value depends on your accuracy requirements, but we use 100000 for some non-critical path code.
  • schudel
    schudel over 8 years
    if you want to reproduce Excels IRR function that also returns negative values, setting min = -1.0; works for me.
  • HattrickNZ
    HattrickNZ over 8 years
    @Zohaib just trying to come up with a good way of exiting after a certain number of iterations and returning undefined. my attempt is below which I though you might be able to help me with.
  • jasonfungsing
    jasonfungsing over 7 years
    I have tested more than 5 IRR library, non of them are correct until I found this. Thank you so much!!!!
  • Altimus Prime
    Altimus Prime almost 7 years
    How does this work for anyone? By itself there are errors thrown for min, max guest and NPV being undefined. Where does guest (guess) get incremented?
  • Jakob Alexander Eichler
    Jakob Alexander Eichler over 4 years
    What if the guess is too high? Your function will never decrease it.