financial rate function in javascript not working properly - javascript

the function given at
simple financial rate function in javascript
is not giving me same answers as excel rate function some time. It works perfectly for the problem given at http://allfinancialmatters.com/2009/11/03/how-to-use-the-rate-function-in-excel/ but for my test cases. its results are different from excel rate. this is strange behaviour. i am unable to sort this out. my test cases (with excel output) are
RATE(360,-665.3, 99000) = 0.0059
RATE(360,-958.63, 192000) =0.0036
RATE(180,-1302.96,192000) = 0.0023
RATE(360, -889.19, 192000) =0.00312
RATE(360, -1145.8, 240000) = 0.0033
my code.js is
function rate(paymentsPerYear, paymentAmount, presentValue, futureValue, dueEndOrBeginning, interest)
{
//If interest, futureValue, dueEndorBeginning was not set, set now
//if (interest == null) // not working here :D
if (isNaN(interest))
interest = 0.1;
//interest = 0.1;
if (isNaN(futureValue))
futureValue = 0;
if (isNaN(dueEndOrBeginning))
dueEndOrBeginning = 0;
var FINANCIAL_MAX_ITERATIONS = 128;//Bet accuracy with 128
var FINANCIAL_PRECISION = 0.0000001;//1.0e-8
var y, y0, y1, x0, x1 = 0, f = 0, i = 0;
var rate = interest; // initiallizing rate to our guess interest
if (Math.abs(rate) < FINANCIAL_PRECISION)
{
y = presentValue * (1 + paymentsPerYear * rate) + paymentAmount * (1 + rate * dueEndOrBeginning) * paymentsPerYear + futureValue;
}
else
{
f = Math.exp(paymentsPerYear * Math.log(1 + rate));
y = presentValue * f + paymentAmount * (1 / rate + dueEndOrBeginning) * (f - 1) + futureValue;
}
y0 = presentValue + paymentAmount * paymentsPerYear + futureValue;
y1 = presentValue * f + paymentAmount * (1 / rate + dueEndOrBeginning) * (f - 1) + futureValue;
// find root by Newton secant method
i = x0 = 0.0;
x1 = rate;
while ((Math.abs(y0 - y1) > FINANCIAL_PRECISION)
&& (i < FINANCIAL_MAX_ITERATIONS))
{
rate = (y1 * x0 - y0 * x1) / (y1 - y0);
x0 = x1;
x1 = rate;
if (Math.abs(rate) < FINANCIAL_PRECISION)
{
y = presentValue * (1 + paymentsPerYear * rate) + paymentAmount * (1 + rate * dueEndOrBeginning) * paymentsPerYear + futureValue;
}
else
{
f = Math.exp(paymentsPerYear * Math.log(1 + rate));
y = presentValue * f + paymentAmount * (1 / rate + dueEndOrBeginning) * (f - 1) + futureValue;
}
y0 = y1;
y1 = y;
++i;
}
return rate;
//return String(parseFloat(rate).toFixed(3)); // rounding it to 3 decimal places
//return parseFloat(rate).toFixed(3);
}
and my HTML file is
<head><title>JavaScript Loan Calculator</title>
<script src="code.js"></script>
</head>
<body bgcolor="white">
<form name="loandata">
<table>
<tr>
<td>1)</td>
<td>paymentsPerYear:</td>
<td><input type="text" name="paymentsPerYear" size="12"
onchange="calculate();"></td>
</tr>
<tr>
<td>2)</td>
<td>paymentAmount:</td>
<td><input type="text" name="paymentAmount" size="12"
onchange="calculate();"></td>
</tr>
<tr>
<td>3)</td>
<td>presentValue:</td>
<td><input type="text" name="presentValue" size="12"
onchange="calculate();"></td>
</tr>
<tr>
<td>4)</td>
<td>futureValue:</td>
<td><input type="text" name="futureValue" size="12"></td>
</tr>
<tr>
<td>5)</td>
<td>dueEndOrBeginning:</td>
<td><input type="text" name="dueEndOrBeginning" size="12"></td>
</tr>
<tr>
<td>6)</td>
<td>interest:</td>
<td><input type="text" name="interest" size="12"></td>
</tr>
<tr><td colspan="3">
<input type="button" value="Compute" onClick="calculate();">
</td></tr>
<tr>
<td>APR:</td>
<td><input type="text" name="APR" id="APR" size="12"></td>
</tr>
</table>
</form>
<script language="JavaScript">
function calculate() {
var paymentsPerYear = document.loandata.paymentsPerYear.value;
var paymentAmount = document.loandata.paymentAmount.value;
var presentValue = document.loandata.presentValue.value;
var futureValue = document.loandata.futureValue.value;
var dueEndOrBeginning = document.loandata.dueEndOrBeginning.value ;
var interest = document.loandata.interest.value ;
var ans = rate(parseFloat(paymentsPerYear), parseFloat(paymentAmount), parseFloat(presentValue), parseFloat(futureValue), parseFloat(dueEndOrBeginning), parseFloat(interest));
document.loandata.APR.value=ans;
//alert(futureValue);
}
</script>
</body>
</html>

In case anyone is still looking for a javascript implementation of the Excel's Rate function, this is what I came up with:
var rate = function(nper, pmt, pv, fv, type, guess) {
// Sets default values for missing parameters
fv = typeof fv !== 'undefined' ? fv : 0;
type = typeof type !== 'undefined' ? type : 0;
guess = typeof guess !== 'undefined' ? guess : 0.1;
// Sets the limits for possible guesses to any
// number between 0% and 100%
var lowLimit = 0;
var highLimit = 1;
// Defines a tolerance of up to +/- 0.00005% of pmt, to accept
// the solution as valid.
var tolerance = Math.abs(0.00000005 * pmt);
// Tries at most 40 times to find a solution within the tolerance.
for (var i = 0; i < 40; i++) {
// Resets the balance to the original pv.
var balance = pv;
// Calculates the balance at the end of the loan, based
// on loan conditions.
for (var j = 0; j < nper; j++ ) {
if (type == 0) {
// Interests applied before payment
balance = balance * (1 + guess) + pmt;
} else {
// Payments applied before insterests
balance = (balance + pmt) * (1 + guess);
}
}
// Returns the guess if balance is within tolerance. If not, adjusts
// the limits and starts with a new guess.
if (Math.abs(balance + fv) < tolerance) {
return guess;
} else if (balance + fv > 0) {
// Sets a new highLimit knowing that
// the current guess was too big.
highLimit = guess;
} else {
// Sets a new lowLimit knowing that
// the current guess was too small.
lowLimit = guess;
}
// Calculates the new guess.
guess = (highLimit + lowLimit) / 2;
}
// Returns null if no acceptable result was found after 40 tries.
return null;
};
Testing the function with Abdul's test cases give the following results:
rate(360,-665.3, 99000);
0.005916521358085446
rate(360,-958.63, 192000);
0.0036458502960158515
rate(180,-1302.96,192000);
0.0022917255526408564
rate(360, -889.19, 192000);
0.0031250616819306744
rate(360, -1145.8, 240000);
0.003333353153720964

Related

brute force polynomial evaluation algorithm javascript

what is required is a brute force algorithm, and not some other!
I'm trying to implement the brute force method for a polynomial in javascript, but an error occurs, the answer is different from the other method above (horner method) - this method is checked and it gives the correct answer
but here is the second brut force- method that gives an excellent result, which is not correct.
What is the error in my code?
input :
_x = 6 _n = 5 polyEval = [2,3,5,-6,2]
output Horner method:
3386 // good. correct answer
output Bruforce method:
1496 // bad. incorrect answer
class Programm {
constructor(x:number, n:number) {
this._x = 4;
this._n = 5;
this.polyEval = [2,3,5,-6,2] //this.RandomArray(this._n);
}
private _x:number;
private _n:number;
private polyEval:number[] = [];
//working method
private Horner(poly:number[], n:number, x:number){
let time = performance.now();
let result = poly[0];
for (let i = 1; i < n; i++){
result = result * x + poly[i];
}
time = performance.now() - time;
console.log("Method: Horner |" ,`Result: ${result}, array: ${this.polyEval} |` ,`time: ${time.toFixed(5)}`);
}
// method with an error that I can't find
private BruteForce(poly:number[], n:number, x:number){
let time = performance.now();
let p: number = 0;
for(let i = n - 1; i >= 0; i--){
let coefficient = 1;
for(let j = 1; j <= i; j++){
coefficient = coefficient * x;
}
p = p + poly[i] * coefficient;
}
time = performance.now() - time;
console.log("Method: Brute Force |" ,`Result: ${p}, array: ${this.polyEval} |` ,`time: ${time.toFixed(5)}`);
}
// generate random array
private RandomArray(n: number):number[]{
let result:number[] = new Array(n);
for (let i = 0; i < n; i++){
if(Math.round(Math.random() * 1) > 0){
result[i] = Math.floor(Math.random() * (10 - 1)) + 1;
}else{
result[i] = Math.floor(((Math.random() * (10 - 1)) + 1) * -1);
}
}
return result;
}
public Main() {
console.log(`n - array length: ${this._n} | x - coefficient: ${this._x}`);
this.Horner(this.polyEval, this._n, this._x);
this.BruteForce(this.polyEval, this._n, this._x);
}
}
const random_N:number = Math.floor(Math.random() * (5 - 1)) + 3;
const random_X:number = Math.floor(Math.random() * (5 - 1)) + 2;
const poly = new Programm(random_N, random_X);
poly.Main();
The Horner's scheme works like this:
// initially
result = poly[0] == p_0;
// iteration 1
result = result * x + poly[1] == p_0 * x + p_1
// iteration 2
result = result * x + poly[2] == (p_0 * x + p_1) * x + p_2
== p_0 * x^2 + p_1 * x + p_2
Thus, the polynomial coefficients in the array poly are in order of highest to lowest. Then to replicate that in the brute force solution, one needs to apply the formula as
result = sum(poly[i] * pow(x, n-1-i)) ==
result = sum(poly[n-1-i] * pow(x, i))

Solving for unknown exponent

I'trying to make a function creates a list of exponentially increasing numbers where the sum of the numbers is equal to some maximum.
For example:
/*
* What do I have to raise N by in order for the sum to be 40
*/
(1**x + 2**x + 3**x + 4**x + 5**x) === 40;
/*
* Wolframalpha tells me: x = 1.76445
* But how can I solve with JS.
*/
function listOfNumbers(n, maxSum) {
// implementation
}
var result = listOfNumbers(5, 40);
/*
* result === [1, 3.397..., 6.947..., 11.542..., 17.111...]
*
*/
result.reduce((acc, n) => acc += n) === 40
try https://en.wikipedia.org/wiki/Bisection_method
TOLERANCE = 1e-5;
let f = x => (1 ** x + 2 ** x + 3 ** x + 4 ** x + 5 ** x - 40);
let
min = 0,
max = 1,
x = 0;
// roughly locate the upper bound
while (f(max) < 0)
max *= 2;
// repeatedly bisect the interval [min, max]
while (1) {
x = (min + max) / 2;
let r = f(x);
if (Math.abs(r) < TOLERANCE)
break;
if (r > 0) {
max = x
} else {
min = x
}
}
// now, x is a "good enough" approximation of the root
console.log(x);

Javascript loop calculation

Using the below script
var lvl = 0;
var HappB = 5;
var DecoX = 5;
var DecoY = 5;
while (lvl < 5) {
document.ofrm.UpgSD.value += Math.ceil((Math.exp((HappB + lvl) / ((DecoX * DecoY) * 1.8))) * 1 * 130000 * (Math.tanh((lvl + 1) / 20)) * (Math.tanh((lvl + 1) / 20)));
lvl++;
}
<form name="ofrm">
<input type="text" name="UpgSD" size="50" tabindex="1">
</form>
The result is
363147633676050952513778
The expected output is
363 + 1476 + 3367 + 6050 + 9525 + 13778 = 34559
How can I fix this?
Here's an updated code.
1. Your loop condition needs to be corrected.
2. .value is string. You can set to a variable and then attach it.
var lvl = 0;
var HappB = 5;
var DecoX = 5;
var DecoY = 5;
var number = 0;
while (lvl <= 5) {
number += Math.ceil((Math.exp((HappB + lvl) / ((DecoX * DecoY) * 1.8))) * 1 * 130000 * (Math.tanh((lvl + 1) / 20)) * (Math.tanh((lvl + 1) / 20)));
lvl++;
}
document.ofrm.UpgSD.value = number;
<form name="ofrm">
<input type="text" name="UpgSD" size="50" tabindex="1">
</form>
It looks like document.ofrm.UpgSD.value is being cast into a string (rather than a number).
var lvl = 0;
var HappB = 5;
var DecoX = 5;
var DecoY = 5;
var initialValue = parseInt(document.ofrm.UpgSD.value);
while (lvl < 5) {
initialValue += Math.ceil((Math.exp((HappB + lvl) / ((DecoX * DecoY) * 1.8))) * 1 * 130000 * (Math.tanh((lvl + 1) / 20)) * (Math.tanh((lvl + 1) / 20)));
lvl++;
}
document.ofrm.UpgSD.value = initialValue;

Refactor a for() loop using Math.pow()?

Here's a question that I'm hoping will improve my programming chops. I have this loop that is calculating a future sum based on annual payments, increased by interest and devalued by inflation (it's derived from the PV function in Excel):
var pmt = 66,449.75 // annual payment
var ip = 0.03 // interest rate
var fv = 0 // future value, not require here
var k = 1 // interest is applied at beginning / end of period
var n = 25 // number of periods (years in this case)
var ri = 0.025 // rate of inflation
var pv = 0;
for (var i = n - 1; i >= 0; i -= 1) {
pv = (pv + (pmt * k - fv) * Math.pow(1 + ri, i)) / (1 + ip);
}
Is it possible to use Math.pow() to reproduce what this loop is doing?
To simplify, I rename some expressions
a = pmt * k - fv;
b = 1 + ri;
c = 1 + ip;
x = pv;
So your code becomes
for (var i = n - 1; i >= 0; --i) {
x = x / c + a * Math.pow(b, i) / c;
}
Then
x_0
x_1 = x_0 / c + a b^{n-1} / c
x_2 = x_1 / c + a b^{n-2} / c = x_0 / c^2 + a b^{n-1} / c^2 + a b^{n-2} / c
...
x_i = x_{i-1} / c + a b^{n-i} / c = x_0 / c^i + \sum_{k=1}^i a b^{n-k} / c^{i-k+1}
...
x_n = x_0 / c^n + \sum_{k=1}^n a * b^{n-k} / c^{n-k+1}
According to WolframAlpha,
x_n = x_0 / c^n + a (b^n-c^n) / (c^n (b-c))
Therefore, instead of your loop you can use
var foo = Math.pow(1 + ip, n); // c^n
pv = pv / foo + (pmt*k-fv) * (Math.pow(1+ri,n) - foo) / foo / (ri-ip);

Writing Variables into HTML from Javascript

I have some javascript and HTML to display the BPM values of a keyboard tap. On the HTML at the bottom, i have some script to get the value of 'simpleTempo' form JAVASCRIPT and write it into a non editable text box however want this to be plain text which I can assign styles with CSS to. If you could help me - it would be really appreciated!
---------------------------JAVSCRIPT---------------------------
// JavaScript Document/*
"use strict";
var startTime;
var beatTimes;
var xsum, xxsum, ysum, yysum, xysum;
var periodprev, aprev, bprev;
var isDone;
init();
function init() {
startTime = null;
beatTimes = [];
xsum = 0;
xxsum = 0;
ysum = 0;
yysum = 0;
xysum = 0;
isDone = false;
document.onkeydown = doBeat;
}
function doBeat() {
if (!isDone)
countBeat(new Date().getTime());
return true;
}
function countBeat(currTime) {
// Coordinates for linear regression
if (startTime == null)
startTime = currTime;
var x = beatTimes.length;
var y = currTime - startTime;
// Add beat
beatTimes.push(y);
var beatCount = beatTimes.length;
setValue("simpleBeats", beatCount);
setValue("simpleTime", floatToString(y / 1000, 3));
// Regression cumulative variables
xsum += x;
xxsum += x * x;
ysum += y;
yysum += y * y;
xysum += x * y;
var tempo = 60000 * x / y;
if (beatCount < 8 || tempo < 190)
setValue("simplePosition", Math.floor(x / 4) + " : " + x % 4);
else // Two taps per beat
setValue("simplePosition", Math.floor(x / 8) + " : " + Math.floor(x / 2) % 4 + "." + x % 2 * 5);
if (beatCount >= 2) {
// Period and tempo, simple
var period = y / x;
setValue("simpleTempo", floatToString(tempo, 2));
setValue("simplePeriod", floatToString(period, 2));
// Advanced
var xx = beatCount * xxsum - xsum * xsum;
var yy = beatCount * yysum - ysum * ysum;
var xy = beatCount * xysum - xsum * ysum;
var a = (beatCount * xysum - xsum * ysum) / xx; // Slope
var b = (ysum * xxsum - xsum * xysum) / xx; // Intercept
setValue("advancedPeriod", floatToString(a, 3));
setValue("advancedOffset", floatToString(b, 3));
setValue("advancedCorrelation", floatToString(xy * xy / (xx * yy), 9));
setValue("advancedTempo", floatToString(60000 / a, 3));
// Deviations from prediction
if (beatCount >= 3) {
setValue("simpleLastDev" , floatToString(periodprev * x - y, 1));
setValue("advancedStdDev" , floatToString(Math.sqrt(((yy - xy * xy / xx) / beatCount) / (beatCount - 2)), 3));
setValue("advancedLastDev", floatToString(aprev * x + bprev - y, 1));
}
periodprev = period;
aprev = a;
bprev = b;
}
}
function done() {
isDone = true;
setValue("simplePosition" , "");
setValue("simpleLastDev" , "");
setValue("advancedLastDev", "");
}
// d: Number of decimal places
function floatToString(x, d) {
if (x < 0)
return "-" + floatToString(-x, d);
var m = Math.pow(10, d);
var tp = Math.round(x % 1 * m);
var s = "";
for (var i = 0; i < d; i++) {
s = tp % 10 + s;
tp = Math.floor(tp / 10);
}
return Math.floor(Math.round(x * m) / m) + "." + s;
}
function setValue(elemId, val) {
document.getElementById(elemId).value = val;
}
---------------------------HTML---------------------------
<form action="#" method="get" onsubmit="return false" onreset="init()">
<input id="simpleTempo" action="#" method="get"/>
<input id="simpleBeats" readonly="readonly" type="hidden" />
<input id="simplePosition" readonly="readonly" type="hidden"/>
<input id="simpleTime" readonly="readonly" type="hidden"/>
<input id="advancedStdDev" readonly="readonly" type="hidden"/>
<input id="advancedOffset" readonly="readonly" type="hidden"/>
<input id="advancedCorrelation" readonly="readonly" type="hidden"/>
<input id="simpleLastDev" readonly="readonly" type="hidden"/>
<input id="advancedLastDev" readonly="readonly" type="hidden"/>
<input id="simplePeriod" readonly="readonly" type="hidden"/>
<input id="advancedPeriod" readonly="readonly" type="hidden"/>
<input id="simpleTempo" readonly="readonly" type="hidden"/>
<input type="reset" alt="reset" class="imgClass"/>
</form>
<script type="application/javascript" src="tap-to-measure-tempo.js"></script>
There is a similar post to this at:
Passing javascript variable to html textbox
Basically to get a JavaScript value into a html textbox you use getElementById
document.getElementById("simpleTempo").value = "some text";

Categories

Resources