Compound Interest Calculator Not Producing Correct Values - javascript

I'm working on creating a compound interest formula with monthly contributions in javascript for populating a chartkick.js graph to show the total amount the principal grows to at the end of each year. Here is the formula I'm following.
Compound Interest For Principal
P(1 + r/n) ^ nt
Future Value of a Series
PMT * (((1 + r/n)^nt - 1) / (r/n)) * (1+r/n)
A = [Compound Interest for Principal] + [Future Value of a Series]
A = the future value of the investment/loan, including interest
P = the principal investment amount (the initial deposit or loan amount)
PMT = the monthly payment
r = the annual interest rate (decimal)
n = the number of times that interest is compounded per year AND additional payment frequency
t = the number of years the money is invested or borrowed for
*/
Here's my javascript:
P = $("#start-amount").val().replace(/[^\d\.]/g, '');
var t = $("#years").val();
var PMT = $("#contributions-amount").val().replace(/[^\d\.]/g, '');
var n = $("#contribution-rate").val();
//If you choose monthly it is equal to 12 and annually it is equal to 1
//Convert Interest Rate to Decimal
var r_percentage = $("#interest-rate").val().replace(/[^\d\.]/g, '');
var r = parseFloat(r_percentage) / 100.0;
//Create an arary with list of numbers less than number of years
var t_arr = [];
for (i = 0; i <= t; i++) {
if (i > 0 && i <= t) {
t_arr.push(i)
}
}
//For Chartkick Chart
data = [
{"name": "With interest", "data": {}
},
{"name": "No Interest", "data": {}
}];
/*
Needs to be like this!
data = [
{"name":"Workout", "data": {"2013-02-10 00:00:00 -0800": 3, "2013-02-17 00:00:00 -0800": 4}},
{"name":"Call parents", "data": {"2013-02-10 00:00:00 -0800": 5, "2013-02-17 00:00:00 -0800": 3}}
];*/
/*With Interest
J is equal to each individual year less than the total number of years*/
for (j = 1; j <= t_arr.length; j++) {
var compound_interest_for_principal = P * (Math.pow(1 + r / n, n * t));
var value_rounded1 = Math.round(compound_interest_for_principal * 100) /100;
var future_value_of_series = PMT * (Math.pow(1 + r / n, n * j) - 1) / (r / n) * (1 + r / n);
var value_rounded2 = Math.round(future_value_of_series * 100) / 100;
var A = value_rounded1 + value_rounded2;
var A = A.toFixed(2);
if (data[0]["data"][j] === undefined) {
data[0]["data"][j] = A;
}
}
/*Without Interest */
for (k = 1; k <= t_arr.length; k++) {
var r = 0;
var principal_no_interest= P;
var value_rounded1 = Math.round(principal_no_interest * 100) /100;
var monthly_no_interest = PMT * n * k;
var value_rounded2 = Math.round(monthly_no_interest * 100) / 100;
var A = value_rounded1 + value_rounded2;
var A = A.toFixed(2);
if (data[1]["data"][k] === undefined) {
data[1]["data"][k] = A;
}
}
new Chartkick.LineChart("savings-chart", data, {"discrete": true});
The values I'm testing are P = $1,000, r = 5% (annual interest), PMT = $100 per month, and n = 12 (number of times interested is compounded per year AND additional payment frequency).
Where the problem is coming in is the values I'm getting.
After 1 year with interest, I get $2,880 and I should get $2,277. After 10 years, I should get $17,065.21, but I'm getting $17,239.94. I don't understand why it's adding about $1,800 to the original vs about $1,200 like it should. Any suggestions?

You could check this
var result = PMT * (Math.pow(1 + r / n, nt) - 1) / (r / n) * (1 + r / n);

Thank you all for your help. I found a solution. Here's the incorrect code vs the correct code:
/*
Formula to Implement
P(1 + r/n) ^ nt
Future Value of a Series
PMT * (((1 + r/n)^nt - 1) / (r/n)) * (1+r/n)
A = [Compound Interest for Principal] + [Future Value of a Series]
A = the future value of the investment/loan, including interest
P = the principal investment amount (the initial deposit or loan amount)
PMT = the monthly payment
r = the annual interest rate (decimal)
n = the number of times that interest is compounded per year AND additional payment frequency
t = the number of years the money is invested or borrowed for
/*
/*INCORRECT SOLUTION
J is equal to each individual year less than the total number of years*/
for (j = 1; j <= t_arr.length; j++) {
//Correct
var compound_interest_for_principal = P * (Math.pow(1 + r / n, n * t));
//Correct
var a= Math.round(compound_interest_for_principal * 100) /100;
//Incorrect
var future_value_of_series = PMT * (Math.pow(1 + r / n, n * j) - 1) / (r / n) * (1 + r / n);
var b = Math.round(future_value_of_series * 100) / 100;
var A = a + b;
var A = A.toFixed(2);
if (data[0]["data"][j] === undefined) {
data[0]["data"][j] = A;
}
}
//CORRECT SOLUTION
for (j = 1; j <= t_arr.length; j++) {
//Incorrect
var compound_interest_for_principal = P * (Math.pow(1 + r / n, n * j));
var a = Math.round(compound_interest_for_principal * 100) / 100;
var future_value_of_series = ((PMT * n) / r) * (Math.pow(1 + r / n, n * j) - 1)
var b = Math.round(future_value_of_series * 100) / 100;
var A = a + b
var A = A.toFixed(2);
if (data[0]["data"][j] === undefined) {
data[0]["data"][j] = A;
}

Related

SyntaxError: identifier starts immediately after numeric literal while trying to create a BigInt in javascript

I am trying to solve Pi till n number of digits in JavaScript with this formula:
#!/usr/bin/env js60
function calculatePi(n) {
var q = t = k = 1
var m = x = 3
var n = n + 1
var r = 0
str = ''
while (str.length < n) {
if (4 * q + r - t < m * t) {
str += m
var rr = r
r = 10 * (r - m * t)
m = Math.floor((10 * (3 * q + rr)) / t - 10 * m)
q = 10 * q
}
else {
m = Math.floor(((q * (7 * k + 2)) + (r * x)) / (t * x))
r = ((2 * q) + r) * x
t = t * x
q = q * k
k = k + 1
x = x + 2
}
}
return str.slice(0, 1) + '.' + str.slice(1)
}
print(calculatePi(19))
Here's how it works in a language with arbitrary length integer support.
But in JavaScript the code generate correct values till the 18 decimal places, and after that the number gets really big to work with. Worse, if the function is given a large number like 10000, it will run in a infinite loop.
When I am trying to write a big number with an n appended to it (as suggested here):
var a = 1000000000000000000000000000n
I get:
typein:1:8 SyntaxError: identifier starts immediately after numeric literal:
typein:1:8 var a = 1000000000000000000000000000n
typein:1:8 ........^
How can I represent an arbitrary length integer in JavaScript?
Thanks to the comments, changing the JS engine from SpiderMonkey to Node solved the issue. The final code looked like:
#!/usr/bin/env node
function calculatePi(n) {
var one = 1n, two = 2n, three = 3n, seven = 7n, ten = 10n
var q = t = k = one
var m = x = three
var n = BigInt(n) + one
var r = 0n
str = ''
while (str.length < n) {
if (4n * q + r - t < m * t) {
str += m
var rr = r
r = ten * (r - m * t)
m = (ten * (three * q + rr)) / t - ten * m
q *= ten
}
else {
t *= x
m = (q * (seven * k + two) + (r * x)) / t
r = ((two * q) + r) * x
q *= k
k += one
x += two
}
}
return str.slice(0, 1) + '.' + str.slice(1)
}
console.log(calculatePi(5000))
Now it can solve any digits using some system's memory (around 40 MiB for 5,000 digits).
The code removed Math.floor() function because BigInt calculation are Integers. A floating point number with arbitrary precision is not going to be calculated here.

Javascript - Creating number with specific formula modulo11

I created following generator for Czech tax number (IČO). I know that there is certainly better way how to code that in javascript. I am beginner and I would like to see how to write my code properly. The number is created with special formula and it has 8didgits, tha last digit is based on modulo11 as you can see below in code.
Thanks for your replies.
//Generation of single random numbers as variables
var a = Math.floor(Math.random() * 10);
var b = Math.floor(Math.random() * 10);
var c = Math.floor(Math.random() * 10);
var d = Math.floor(Math.random() * 10);
var e = Math.floor(Math.random() * 10);
var f = Math.floor(Math.random() * 10);
var g = Math.floor(Math.random() * 10);
//Formula for tax number
var formula = a * 8 + b * 7 + c * 6 + d * 5 + e * 4 + f * 3 + g * 2;
var modulo11 = formula % 11;
if (modulo11 === 0) {
var h = 1;
} else if (modulo11 === 1) {
var h = 0;
} else {
var h = 11 - modulo11;
};
//Completing tax number
var identificationNumber = "" + a + b + c + d + e + f + g + h;
//displaying number in console
console.log(identificationNumber);
Take benefit from Array data structure to store a, b,...g.
Then "map" this array by (8- indexOfItem) * item
šŸ‘‰šŸ¼ so , for the 1Ė¢įµ— item which has index = 0 , we will have (8 - 0) * a -āž” 8* a.
šŸ‘‰šŸ¼ for the 2āæįµˆ item āž” (8 -1) * b āž” 7 *b
šŸ‘‰šŸ¼....so on.
Then use "reduce" to calculate the sum .
Then use "join" instead of ""+ a +b + ....+ g+ h
function getH(modulo11) {
if (modulo11 === 0) return 1;
if (modulo11 === 1) return 0;
return 11 - modulo11;
}
//Generation of single random numbers as variables
const numbers= Array.from({length: 7},(v, k) =>Math.floor(Math.random() * 10))
//Formula for tax number
const formula= numbers.map((n, i) => (8 - i) * n).reduce((total, next) => total+ next , 0)// alternative of sum : a * 8 + b * 7 + c * 6 + d * 5 + e * 4 + f * 3 + g * 2
const h= getH(formula % 11);
//Completing tax number
const identificationNumber = [...numbers, h].join('');
//displaying number in console
console.log(identificationNumber);

How to use Javascript class for xirr formula

Hello I have found a javascript class for some excel functions but i dont know how to use it. I need to use XIRR function but i dont know the type and format of parameters and the syntax.
Here is the code:
/* Based on
* - EGM Mathematical Finance class by Enrique Garcia M. <egarcia#egm.co>
* - A Guide to the PMT, FV, IPMT and PPMT Functions by Kevin (aka MWVisa1)
*/
var ExcelFormulas = {
PVIF: function(rate, nper) {
return Math.pow(1 + rate, nper);
},
FVIFA: function(rate, nper) {
return rate == 0? nper: (this.PVIF(rate, nper) - 1) / rate;
},
PMT: function(rate, nper, pv, fv, type) {
if (!fv) fv = 0;
if (!type) type = 0;
if (rate == 0) return -(pv + fv)/nper;
var pvif = Math.pow(1 + rate, nper);
var pmt = rate / (pvif - 1) * -(pv * pvif + fv);
if (type == 1) {
pmt /= (1 + rate);
};
return pmt;
},
IPMT: function(pv, pmt, rate, per) {
var tmp = Math.pow(1 + rate, per);
return 0 - (pv * tmp * rate + pmt * (tmp - 1));
},
PPMT: function(rate, per, nper, pv, fv, type) {
if (per < 1 || (per >= nper + 1)) return null;
var pmt = this.PMT(rate, nper, pv, fv, type);
var ipmt = this.IPMT(pv, pmt, rate, per - 1);
return pmt - ipmt;
},
DaysBetween: function(date1, date2) {
var oneDay = 24*60*60*1000;
return Math.round(Math.abs((date1.getTime() - date2.getTime())/oneDay));
},
// Change Date and Flow to date and value fields you use
XNPV: function(rate, values) {
var xnpv = 0.0;
var firstDate = new Date(values[0].Date);
for (var key in values) {
var tmp = values[key];
var value = tmp.Flow;
var date = new Date(tmp.Date);
xnpv += value / Math.pow(1 + rate, this.DaysBetween(firstDate, date)/365);
};
return xnpv;
},
XIRR: function(values, guess) {
if (!guess) guess = 0.1;
var x1 = 0.0;
var x2 = guess;
var f1 = this.XNPV(x1, values);
var f2 = this.XNPV(x2, values);
for (var i = 0; i < 100; i++) {
if ((f1 * f2) < 0.0) break;
if (Math.abs(f1) < Math.abs(f2)) {
f1 = this.XNPV(x1 += 1.6 * (x1 - x2), values);
}
else {
f2 = this.XNPV(x2 += 1.6 * (x2 - x1), values);
}
};
if ((f1 * f2) > 0.0) return null;
var f = this.XNPV(x1, values);
if (f < 0.0) {
var rtb = x1;
var dx = x2 - x1;
}
else {
var rtb = x2;
var dx = x1 - x2;
};
for (var i = 0; i < 100; i++) {
dx *= 0.5;
var x_mid = rtb + dx;
var f_mid = this.XNPV(x_mid, values);
if (f_mid <= 0.0) rtb = x_mid;
if ((Math.abs(f_mid) < 1.0e-6) || (Math.abs(dx) < 1.0e-6)) return x_mid;
};
return null;
}
};
You want to use XIRR, so let's look at its signature:
XIRR: function(values, guess)
What does it do with values?
var f1 = this.XNPV(x1, values);
So values must be whatever XNPV is expecting. It has this chunk at its core:
for (var key in values) {
var tmp = values[key];
var value = tmp.Flow;
var date = new Date(tmp.Date);
xnpv += value / Math.pow(1 + rate, this.DaysBetween(firstDate, date)/365);
};
So it is expecting values to be a dictionary (associative array), where the value part of the key-value pair has members .Flow and .Date. I assume .Flow is the cashflow, and from the DaysBetween method I can see that .Date is a javascript Date. The key is ignored, so it can be a numeric if we want. So let's make one of those:
var myInstrument = { 0: {Flow: 5, Date: new Date(2015, 7, 6)},
1: {Flow: 105, Date: new Date(2016, 7, 6)} };
(That is a dictionary (or array) declaration).
The other input to XIRR is guess, which it will use to solve something, but it will default to using 0.1 (10% !) if given a falsy input value. So we can call it with our myInstrument thus:
var myInternalReturn = XIRR(myInstrument, false);
NB: The XIRR function is implementing the Actual/365 Fixed day count convention for Annual payment frequency, which may not be appropriate for the instrument you are valuing. Maybe it won't make much difference, but it will be incorrect for semi-annual or 30/360, with particular problems around month-end dates, simple interest instruments and so on

Polyline Length

I get line length by this functions.
google.maps.LatLng.prototype.kmTo = function(a){
var e = Math, ra = e.PI/180;
var b = this.lat() * ra, c = a.lat() * ra, d = b - c;
var g = this.lng() * ra - a.lng() * ra;
var f = 2 * e.asin(e.sqrt(e.pow(e.sin(d/2), 2) + e.cos(b) * e.cos
(c) * e.pow(e.sin(g/2), 2)));
return f * 6378.137;
}
google.maps.Polyline.prototype.inKm = function(n){
var a = this.getPath(n), len = a.getLength(), dist = 0;
for (var i=0; i < len-1; i++) {
dist += a.getAt(i).kmTo(a.getAt(i+1));
}
return dist;
}
And use :
alert('Line Length: '+ poly1.inKm() +'');
Everything working. But i have a small problem.
Its shows me: >> Line Length: 8.854502612255438km <<
Digits is to long i want it show me only 8.8 how can i do it?
Sorry for my english!
Try something like:
Math.floor(x * 10) / 10
Where x is the number you are trying to show (8.854502612255438).
Instead of floor (which will turn 88.5 to 88) you may want to try round (which will turn 88.5 to 89).
Edit - ah no, that won't work will it because your number is a string with 'km' at the end (did not spot that)...
so... try using parseFloat like this:
Math.floor(parseFloat(x, 10) * 10) / 10
You would have to add 'km' to the end of the string your self, so the full thing becomes:
alert('Line Length: '+ (Math.floor(parseFloat(poly1.inKm(), 10) * 10) / 10) +'km');

How to make a function that computes the factorial for numbers with decimals?

How can I make a function that calculates the factorial (or the gamma function) of decimal numbers in JavaScript? For example, how could I calculate 2.33!?
I might have found an existing solution...
It's an implementation of Lanczos method, I found it at the swedish wikipedia (http://sv.wikipedia.org/wiki/Gammafunktionen). It was written in python and says to be correct up to 15 decimals. I ported it to js, cross checked some random values against (http://www.efunda.com/math/gamma/findgamma.cfm).
http://jsfiddle.net/Fzy9C/
var g = 7;
var C = [0.99999999999980993, 676.5203681218851, -1259.1392167224028,771.32342877765313, -176.61502916214059, 12.507343278686905, -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7];
function gamma(z) {
if (z < 0.5) return Math.PI / (Math.sin(Math.PI * z) * gamma(1 - z));
else {
z -= 1;
var x = C[0];
for (var i = 1; i < g + 2; i++)
x += C[i] / (z + i);
var t = z + g + 0.5;
return Math.sqrt(2 * Math.PI) * Math.pow(t, (z + 0.5)) * Math.exp(-t) * x;
}
}
(and ofcourse it does not support imaginary numbers, since js does not)
As an alternative to the other answers here, here's a much simpler approximation for the gamma function, proposed in 2007 by Gergő Nemes. (See the wikipedia page on Stirling's approximation).
This can be implemented directly in JavaScript in a single line:
function gamma(z) {
return Math.sqrt(2 * Math.PI / z) * Math.pow((1 / Math.E) * (z + 1 / (12 * z - 1 / (10 * z))), z);
}
You can see this in action on jsFiddle.
This is accurate to 8 digits for z > 8, but it is still accurate to a handful of digits for smaller z. It is not quite as accurate as Lanczos approximation, but it is simpler and also slightly faster.
Note that the gamma function and the factorial function are slightly different. The factorial function can be defined in terms of the gamma function thus:
function factorial(n) {
return gamma(n + 1);
}
This is not a trivial problem. There is not a simple closed-form formula for the gamma function. That said, there are some numerical approximations that should suit your needs.
The following answer will be using a technique called Lanczos approximation. The formula is as follows:
where g is an arbitrarily chosen constant that controls how accurate the approximation will be. For larger g, the approximation will be more accurate. Ag(z) is defined thus:
The hardest part is finding Ag(z), since pn is also defined with a complicated formula dependent on g.
I can't take too much credit for the following code, since I am just writing a port of the Python program on the wikipedia page.
function gamma(n) { // accurate to about 15 decimal places
//some magic constants
var g = 7, // g represents the precision desired, p is the values of p[i] to plug into Lanczos' formula
p = [0.99999999999980993, 676.5203681218851, -1259.1392167224028, 771.32342877765313, -176.61502916214059, 12.507343278686905, -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7];
if(n < 0.5) {
return Math.PI / Math.sin(n * Math.PI) / gamma(1 - n);
}
else {
n--;
var x = p[0];
for(var i = 1; i < g + 2; i++) {
x += p[i] / (n + i);
}
var t = n + g + 0.5;
return Math.sqrt(2 * Math.PI) * Math.pow(t, (n + 0.5)) * Math.exp(-t) * x;
}
}
and of course, by definition of the gamma function:
function factorial(n) {
return gamma(n + 1);
}
You can see this in action on jsFiddle.
Just to complete #apelsinapa answer to correct the calculation for an integer (we didn't get an integer solution when inputing an integer number).
#apelsinapa's great solution:
var g = 7;
var C = [0.99999999999980993, 676.5203681218851, -1259.1392167224028,771.32342877765313, -176.61502916214059, 12.507343278686905, -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7];
function gamma(z) {
if (z < 0.5) return Math.PI / (Math.sin(Math.PI * z) * gamma(1 - z));
else {
z -= 1;
var x = C[0];
for (var i = 1; i < g + 2; i++)
x += C[i] / (z + i);
var t = z + g + 0.5;
return Math.sqrt(2 * Math.PI) * Math.pow(t, (z + 0.5)) * Math.exp(-t) * x;
}
}
And to get a correct answer for integer:
function factorialOfNumber(number) {
if (number % 1 != 0 || number<0){
return gamma(number + 1);
}
else {
if(number == 0) {
return 1;
}
for(var i = number; --i; ) {
number *= i;
}
return number;
}
}
Here's a version I wrote a few years ago ... a bit messy but tested :)
var
M_GAMMA = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5],
M_GAMMAS = 6;
function gammaFn(x) // Modified to JavaScript from "Numerical Recipies in C" by P. Mainwaring
{
var i = 0, n = ++x, tmp = x + 5.5, ser = 1.000000000190015;
for (tmp -= (x + 0.5) * Math.log(tmp); i < M_GAMMAS; ++i) ser += M_GAMMA [i] / ++n;
return Math.log(2.5066282746310005 * ser / x) - tmp;
}
function fact(x) { return x > 1 ? Math.exp(gammaFn(x)) : 1 }
function combin(n, k) { return (Math.exp(gammaFn(n) - gammaFn(n - k) - gammaFn(k)) + 0.5) | 0 } // Ms Excel COMBIN() n! / k!(n - k)!
n = 49; k = 6; alert(fact(n) + ' ' + fact(k) + ' ' + combin(n, k)); // Lottery odds! (13,983,816)
The gamma and gammaLn functions are then:
function gammaLn(x) { return gammaFn(--x) }
function gamma(x) { return Math.exp(gammaLn(x)) }
:-)
If you're just looking for the function to compute factorials of real numbers then you only need this bit of code from Lanczos approximation:
function = factorial(z) {
var g = 7;
var C = [0.99999999999980993, 676.5203681218851, -1259.1392167224028, 771.32342877765313, -176.61502916214059, 12.507343278686905, -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7];
var x = C[0];
for (var i = 1; i < g + 2; i++)
x += C[i] / (z + i);
var t = z + g + 0.5;
return Math.sqrt(2 * Math.PI) * Math.pow(t, (z + 0.5)) * Math.exp(-t) * x;
}
Works great for negative numbers in addition to decimals.

Categories