Annuity amortization table in JavaScript - javascript

I need help with a function which can calculate mortgage annuity amortization table with output in cols and rows of payment amount, principal payment, Interest payment, etc. sorted by each month like in link below:
Output example
The output file format should be .cvs. At the moment I am stuck with this witch is still far away from result:
var i = 5/100;
var loanAmount = 15000;
var m = 12;
var monthlyPayment = loanAmount*(i/12)*Math.pow((1+i/12), m) / (Math.pow((1+i/12), m)-1)
var currentBalance = loanAmount;
var paymentCounter = 1;
var totalInterest = 0;
monthlyPayment = monthlyPayment;
while(currentBalance > 0) {
//this calculates the portion of your monthly payment that goes towards interest
towardsInterest = (i/12)*currentBalance;
if (monthlyPayment > currentBalance){
monthlyPayment = currentBalance + towardsInterest;
}
towardsBalance = monthlyPayment - towardsInterest;
totalInterest = totalInterest + towardsInterest;
currentBalance = currentBalance - towardsBalance;
}
Would really appreciate any help on this.

Try something like this:
const annuity = (C, i, n) => C * (i/(1-(1+i)**(-n)));
const balance_t = (C, i, P) => {
const period_movements = {
base: C
}
period_movements.interest = C*i;
period_movements.amortization = P - (C*i);
period_movements.annuity = P;
period_movements.final_value = Math.round((C - period_movements.amortization)*100)/100;
return period_movements;
}
const display_mortgage = (C, i, n) => {
const payements = annuity(C, i, n);
let movements = balance_t(C, i, payements);
while (movements.final_value>-.01){
console.log(movements);
movements = balance_t(movements.final_value, i, payements);
}
}
display_mortgage(20000, 0.05, 4);
Output:
{ base: 20000,
interest: 1000,
amortization: 4640.236652069255,
annuity: 5640.236652069255,
final_value: 15360 }
{ base: 15360,
interest: 768,
amortization: 4872.236652069255,
annuity: 5640.236652069255,
final_value: 10488 }
{ base: 10488,
interest: 524.4,
amortization: 5115.836652069255,
annuity: 5640.236652069255,
final_value: 5372 }
{ base: 5372,
interest: 268.6,
amortization: 5371.6366520692545,
annuity: 5640.236652069255,
final_value: 0 }

Related

Javascript:: addEventListener on change radio button not working using requirejs

Requirejs addEventListener on change radio button not working in magento
Here everything works fine just one issue is there, it doesn't the value and id of input radio fields, So I think addEventListener DOMContentLoaded is not working here.
Help is really appreciated TIA
This is js file code
define([
"jquery",
"domReady!"
], function($){
"use strict";
const myscript=function(){
const profit = document.querySelector('input[name="rdmonths"]:checked').value;
const id = document.querySelector('input[name="rdmonths"]:checked').id;
const principal = document.querySelector('input[name="investment_calc"]').value;
const time = id;
const rate = profit/100;
const n = 1;
const compoundInterest = (p, t, r, n) => {
const amount = p * (Math.pow((1 + (r / n)), t));
return amount;
};
document.getElementById("total-amount").innerHTML = (compoundInterest(principal, time, rate, n).toFixed(2));
console.log(compoundInterest(principal, time, rate, n).toFixed(2));
}
document.addEventListener('DOMContentLoaded',()=>{
document.querySelectorAll('input[type="radio"][name="rdmonths"]').forEach(input=>{
input.addEventListener('click', myscript )
})
})
return myscript;
});
Just add click function for change of radio button
define([
"jquery",
"domReady!"
], function($){
"use strict";
return function myscript()
{
const profit = document.querySelector('input[name="rdmonths"]:checked').value;
const id = document.querySelector('input[name="rdmonths"]:checked').id;
const principal = document.querySelector('input[name="investment_calc"]').value;
const time = id;
const rate = profit/100;
const n = 1;
const compoundInterest = (p, t, r, n) => {
const amount = p * (Math.pow((1 + (r / n)), t));
return amount;
};
document.getElementById("total-amount").innerHTML = (compoundInterest(principal, time, rate, n).toFixed(2));
jQuery(".months").click(function(){
const profit = document.querySelector('input[name="rdmonths"]:checked').value;
const id = document.querySelector('input[name="rdmonths"]:checked').id;
const principal = document.querySelector('input[name="investment_calc"]').value;
const time = id;
const rate = profit/100;
const n = 1;
const compoundInterest = (p, t, r, n) => {
const amount = p * (Math.pow((1 + (r / n)), t));
return amount;
};
document.getElementById("total-amount").innerHTML = (compoundInterest(principal, time, rate, n).toFixed(2));
});
}
});

Find a time slot which can accommodate a new time stamp and calculate frequency

I have a series of time slots:
[
"00:00-00:15",
"00:15-00:30",
.
.
.
"11:15-11:30",
"11:30-11:45",
"11:45-00:00"
]
I have a list of incoming time stamps along with some data which look like:
20:18 apple
20:07 bananas
00:12 apple
.
.
.
13:52 cake
I basically want to group these at the end and display something like:
.
.
20:15-20:30 apple 1 bananas 2,
20:30-20:45 cake 5,
20:45-21:00 apple 3, egg 1,
.
.
.
The approach I have thought of is iterating through all the time slots and finding which time slot can accommodate the time stamp.
Is there anything better I can do to optimise it?
Also, I am unable to figure out how to store the frequency of multiple objects under a single time slot.
Should I use JSON?
Here's my try. It has a lot of things going on. I have greatly simplified my problem statement to avoid any confusion but since Nina Scholz asked:
var express = require("express");
var router = express.Router();
var axios = require("axios");
function convertUTC(t) {
let unix_timestamp = t;
var date = new Date(unix_timestamp * 1000);
var hours = ("0" + date.getHours()).slice(-2);
var minutes = "0" + date.getMinutes();
var formattedTime = hours + ":" + minutes.substr(-2);
return formattedTime;
}
function generateTimeSlots() {
try {
var x = 15;
var times = [];
var tt = 0;
for (var i = 0; tt < 24 * 60; i++) {
hh = Math.floor(tt / 60);
mm = tt % 60;
beg = ("0" + (hh % 12)).slice(-2) + ":" + ("0" + mm).slice(-2);
hh = Math.floor((tt + 15) / 60);
mm = (tt + 15) % 60;
end = ("0" + (hh % 12)).slice(-2) + ":" + ("0" + mm).slice(-2);
times[i] = beg + "-" + end;
tt = tt + x;
}
return times;
} catch (error) {
console.log(error);
}
}
router.post("/process-logs", async (req, res) => {
fileStrings = req.body.logFiles;
parallelCount = req.body.parallelFileProcessingCount;
times = generateTimeSlots();
for (var i = 0; i < fileStrings.length; i++) {
await axios.get(fileStrings[i]).then(function (response) {
lines = response.data.split(/\r?\n/);
for (var j = 0; j < lines.length; j++) {
time = convertUTC(lines[j].split(" ")[1]);
console.log(time);
}
});
}
res.send(times);
res.send("done");
});
module.exports = router;
A very simple and naive approach (with O(n^2) time complexity) that works for arbitrary ranges would be to create a helper map, iterate through each of the slots and find the matching timestamps. If there's a match update the count for the corresponding fruit in the map. Something like this:
const slots = [ '00:00-00:15', '11:30-11:45', '13:25-14:00', '20:00-20:30'];
const data = ['20:18 apple','00:11 apple', '20:07 bananas', '20:27 bananas', '00:12 apple', '13:52 cake', '11:22 cake'];
function groupTimeslots(slots, fruitData) {
const timeSlotMap = {};
for (const key of slots) {
timeSlotMap[key] = {};
}
for (const slot of slots) {
for (const entry of fruitData) {
const [timestamp, fruit] = entry.split(' ');
if (isBetween(slot, timestamp)) {
timeSlotMap[slot][fruit] = timeSlotMap[slot][fruit] ? ++timeSlotMap[slot][fruit] : 1;
}
}
}
return timeSlotMap;
}
function isBetween(slot, timestamp) {
const [start, end] = slot.split('-');
const timestampMins = toMinutes(timestamp);
return timestampMins > toMinutes(start) && timestampMins < toMinutes(end);
}
function toMinutes(timestamp) {
const [hours, minutes] = timestamp.split(':');
return Number.parseInt(hours) * 60 + Number.parseInt(minutes);
}
console.log(groupTimeslots(slots, data));
You can assign the index to a particular time slot. Then we can convert an incoming time to the index.
An index could be calculated by how many "slots" proceeds the particular time, sou we could divide the time in minutes by 15 to get the index.
[
"00:00-00:15", // 0th -> index = 0
"00:15-00:30", // 1st -> index = 1
.
.
.
"11:15-11:30", // 93th
"11:30-11:45", // 94th
"11:45-00:00" // 95th -> index = 95
]
const indexToTime = (index) => {
const hour = Math.floor(15 * index / 60) % 24
const minute = (15 * index) % 60
const h = `${hour}`.padStart(2, 0)
const m = `${minute}`.padStart(2, 0)
const time = `${h}:${m}`
return time
}
const timeToIndex = (time) => {
const [hour, minute] = time.split(':')
const [h, m] = [parseInt(hour), parseInt(minute)]
const index = hour * 4 + Math.floor(minute / 15)
return index
}
const slots = [...Array(24 * 60 / 15)].map((_, i) => `${indexToTime(i)}-${indexToTime(i+1)}`)
console.log('slots =', slots)
const records = ['20:47 apple', '20:18 apple', '20:17 bananas', '20:43 cake', '20:18 bananas', '20:31 cake', '20:30 cake', '20:40 cake', '20:39 cake', '20:49 apple', '20:54 egg', '20:50 apple']
console.log('records =', records)
const stats = []
records.forEach(record => {
const [time, item] = record.split(' ')
const index = timeToIndex(time)
if (!stats[index]) {
stats[index] = {[item]: 1}
} else if(!stats[index][item]) {
stats[index][item] = 1
} else {
stats[index][item]++
}
})
console.log('stats =', stats)
const statsRecords = slots.map((time, index) => ({ time, stats: stats[index] }))
console.log('statsRecords =', statsRecords)
const display = (statsRecords) => {
return statsRecords.map(({ time, stats = {} }) => `${time} ${Object.entries(stats).map(([item, count]) => `${item} ${count}`).join(', ')}`).join('\n')
}
console.log(display(statsRecords))

Change chances of picking a random string

I would like Anna to have 67% chance of being picked randomly, Bob to have a 30% change, and Tom to have a 3% chance. Is there a simpler way to do this?
This is what I have so far:
var nomes = ['Anna', 'Bob', 'Tom'];
var name = nomes[Math.ceil(Math.random() * (nomes.length - 1))];
console.log(name);
Based on this Stack Overflow I think the following code will work for you:
function randomChoice(p) {
let rnd = p.reduce((a, b) => a + b) * Math.random();
return p.findIndex(a => (rnd -= a) < 0);
}
function randomChoices(p, count) {
return Array.from(Array(count), randomChoice.bind(null, p));
}
const nomes = ['Anna', 'Bob', 'Tom'];
const selectedIndex = randomChoices([0.67, 0.3, 0.03], nomes);
console.log(nomes[selectedIndex]);
// Some testing to ensure that everything works as expected:
const odds = [0, 0, 0];
for (let i = 0; i < 100000; i++) {
const r = randomChoices([0.67, 0.3, 0.03], nomes);
odds[r] = odds[r] + 1;
}
console.log(odds.map(o => o / 1000));
Here's a short solution for you:
function pick(){
var rand = Math.random();
if(rand < .67) return "Anna";
if(rand < .97) return "Bob";
return "Tom";
}
console.log( pick() );

How to calculate waypoints between multiple waypoints?

So for example I have an array with 3 waypoints:
[ [ 526, 1573, 24 ], [ 2224, 809, -1546 ], [ 6869, 96, -3074 ] ]
I also know I want to rest for lets say n times between between arriving at the first and last waypoint. So in the end I want an array of n points.
How do I go about finding those n resting-points in JS?
Thanks in advance!
EDIT: Note this is not a single object! Imagine each axis being one person. They have to stop the same amount of time and at the same time but they do not have to be at the same place obviously.
You want to use linear interpolation.
A quick example:
const POINTS = [ [ 526, 1573, 24 ], [ 2224, 809, -1546 ], [ 6869, 96, -3074 ] ];
const N = 10;
function getDistance(point1, point2) {
// speed in 3d space is mutated according only to the X distance,
// to keep speed constant in X dimension
return Math.abs(point1[0] - point2[0]);
}
function go(points, n) {
const pointDistances = points.slice(1).map((point, index) => getDistance(points[index], point));
const fullDistance = pointDistances.reduce((sum, distance) => sum + distance, 0);
const distancePerSection = fullDistance / n;
return points.slice(1)
.reduce((last, point, index) => {
const thisDistance = pointDistances[index];
const numRestPoints = Math.max(0, Math.floor(thisDistance / distancePerSection) - 1);
if (!numRestPoints) {
return last.concat([point]);
}
const thisYVector = point[1] - points[index][1];
const thisZVector = point[2] - points[index][2];
return last.concat(new Array(numRestPoints).fill(0)
.reduce((section, item, restIndex) => {
return section.concat([[
points[index][0] + (restIndex + 1) * distancePerSection,
points[index][1] + (restIndex + 1) * thisYVector * distancePerSection / thisDistance,
points[index][2] + (restIndex + 1) * thisZVector * distancePerSection / thisDistance
]]);
}, [])
.concat([point])
);
}, points.slice(0, 1));
}
function test() {
const result = go(POINTS, N);
if (result.length !== N) {
throw new Error('Must be N length');
}
if (!result[0].every((value, index) => value === POINTS[0][index])) {
throw new Error('Doesn\'t start at the first point');
}
if (!result[N - 1].every((value, index) => value === POINTS[POINTS.length - 1][index])) {
throw new Error('Doesn\'t end at the last point');
}
if (!POINTS.slice(1, N - 1).every(point =>
result.some(resultPoint => resultPoint.every((value, index) => value === point[index]))
)) {
throw new Error('Doesn\'t go through every provided point');
}
console.log(result.slice(1).map((point, index) => getDistance(point, result[index])));
console.log('The result passed the tests!');
console.log(JSON.stringify(result, null, 2));
}
test();
I'm basically going through the list of points, and determining if there should exist any rest points between them, inserting them if so.
Please comment if you want further clarification!
I also solved this problem now with linear interpolation:
My solution:
var waypoints = [[526,1573,24],[2224,809,-1546],[6869,96,-3074]];
var pauses = 20;
generateWaypopints();
function generateWaypopints(){
var newWaypoints = [];
var progressAtMainPoints = 1 / (waypoints.length - 1)
var pausesBetweenWaypoints = pauses * progressAtMainPoints;
var progressAtPauses = 1 / pausesBetweenWaypoints;
newWaypoints.push(waypoints[0]);
var sector = 0;
var pausesInSector = 0;
for(var i = 0; i < pauses; i++){
var progress = progressAtPauses * (pausesInSector + 1)
var x = Math.round(waypoints[sector][0] + (waypoints[sector + 1][0] - waypoints[sector][0]) * progress);
var y = Math.round(waypoints[sector][1] + (waypoints[sector + 1][1] - waypoints[sector][1]) * progress);
var z = Math.round(waypoints[sector][2] + (waypoints[sector + 1][2] - waypoints[sector][2]) * progress);
if(progress >= 1){
sector++;
pausesInSector = 0;
}else
pausesInSector++;
newWaypoints.push([x,y,z]);
}
console.log(newWaypoints);
return newWaypoints;
}

Look up tables and integer ranges - javascript

So I am looking to create look up tables. However I am running into a problem with integer ranges instead of just 1, 2, 3, etc. Here is what I have:
var ancient = 1;
var legendary = 19;
var epic = 251;
var rare = 1000;
var uncommon = 25000;
var common = 74629;
var poolTotal = ancient + legendary + epic + rare + uncommon + common;
var pool = general.rand(1, poolTotal);
var lootPool = {
1: function () {
return console.log("Ancient");
},
2-19: function () {
}
};
Of course I know 2-19 isn't going to work, but I've tried other things like [2-19] etc etc.
Okay, so more information:
When I call: lootPool[pool](); It will select a integer between 1 and poolTotal Depending on if it is 1 it will log it in the console as ancient. If it hits in the range of 2 through 19 it would be legendary. So on and so forth following my numbers.
EDIT: I am well aware I can easily do this with a switch, but I would like to try it this way.
Rather than making a huge lookup table (which is quite possible, but very inelegant), I'd suggest making a (small) object, choosing a random number, and then finding the first entry in the object whose value is greater than the random number:
// baseLootWeight: weights are proportional to each other
const baseLootWeight = {
ancient: 1,
legendary: 19,
epic: 251,
rare: 1000,
uncommon: 25000,
common: 74629,
};
let totalWeightSoFar = 0;
// lootWeight: weights are proportional to the total weight
const lootWeight = Object.entries(baseLootWeight).map(([rarity, weight]) => {
totalWeightSoFar += weight;
return { rarity, weight: totalWeightSoFar };
});
console.log(lootWeight);
const randomType = () => {
const rand = Math.floor(Math.random() * totalWeightSoFar);
return lootWeight
.find(({ rarity, weight }) => weight >= rand)
.rarity;
};
for (let i = 0; i < 10; i++) console.log(randomType());
Its not a lookup, but this might help you.
let loots = {
"Ancient": 1,
"Epic": 251,
"Legendary": 19
};
//We need loots sorted by value of lootType
function prepareSteps(loots) {
let steps = Object.entries(loots).map((val) => {return {"lootType": val[0], "lootVal": val[1]}});
steps.sort((a, b) => a.lootVal > b.lootVal);
return steps;
}
function getMyLoot(steps, val) {
let myLootRange;
for (var i = 0; i < steps.length; i++) {
if((i === 0 && val < steps[0].lootVal) || val === steps[i].lootVal) {
myLootRange = steps[i];
break;
}
else if( i + 1 < steps.length && val > steps[i].lootVal && val < steps[i + 1].lootVal) {
myLootRange = steps[i + 1];
break;
}
}
myLootRange && myLootRange['lootType'] ? console.log(myLootRange['lootType']) : console.log('Off Upper Limit!');
}
let steps = prepareSteps(loots);
let pool = 0;
getMyLoot(steps, pool);

Categories

Resources