Javascript for loop [loop doesn't stop] - javascript

I really try to find out why the for loop is looping again and again. My question is why is the first for looping again and again thought x is 1?
The result shows random counts of progressbars with a random progresses (img element is the progress). But it should only show 1 because x is 1. Can somebody tell me whats the answer?
function progress(){
var min = 0;
var max = 10;
/*var x = Math.floor(Math.random() * (max - min)) + min;*/
var x = 1;
var main_div = document.createElement('div');
main_div.className = "main_div";
document.body.appendChild(main_div);
for(var i = 0; i < x; i++){
var einfuegen = document.createElement('div');
einfuegen.className = 'statusbar';
main_div.appendChild(einfuegen);
var einfuegen2 = document.createElement('img');
einfuegen2.id = 'bild';
einfuegen2.name = 'bild';
einfuegen2.src = 'project_status.gif';
var zielort = document.getElementsByClassName('statusbar')[i];
zielort.appendChild(einfuegen2);
var min = 0;
var max = 100;
var x = Math.floor(Math.random() * (max - min)) + min;
document.getElementsByTagName('img')[i].style.width = x+"%";
}
}

You need to use some different names for variable in loop
var min = 0;
var max = 100;
var x = Math.floor(Math.random() * (max - min)) + min;
it should be
var min1 = 0;
var max1 = 100;
var x1 = Math.floor(Math.random() * (max1 - min1)) + min1;
As you are using x in loop condition and modifying it inside loop, causing malfunction of loop.

You're changing x here:
var x = Math.floor(Math.random() * (max - min)) + min;
So the loop will loop a random number of times between 0 and 100.
Use a different variable name for the value of your progress bar, and for that matter, the max and min values of the progress bar:
var value = Math.floor(Math.random() * (maxValue - minValue)) + minValue;
document.getElementsByTagName('img')[i].style.width = value+"%";
This confusion is the very reason why JSLint recommends declaring all of your variables at the top of your function:
function progress(){
var min = 0,
max = 10,
x = 1,
i,
main_div = document.createElement('div'),
einfuegen,
einfuegen2,
zielort,
minValue = 0,
maxValue = 100,
value;
// rest of function...
}
The variable list above is very long because it has the values for both the outside of the loop and the inside of the loop. The solution to this is to factor your code out into separate functions:
function progress(){
var min = 0,
max = 10;
x = 1,
main_div = document.createElement('div'),
i;
main_div.className = "main_div";
document.body.appendChild(main_div);
for(i = 0; i < x; i += 1){
mainDiv.appendChild(makeProgressBar());
}
}
function makeProgressBar() {
var einfuegen = document.createElement('div'),
einfuegen2 = document.createElement('img'),
min = 0,
max = 100,
x = Math.floor(Math.random() * (max - min)) + min;
einfuegen.className = 'statusbar';
einfuegen2.id = 'bild';
einfuegen2.name = 'bild';
einfuegen2.src = 'project_status.gif';
einfuegen.appendChild(einfuegen2);
einfuegen2.style.width = x+"%";
return einfuegen;
}
This will also help to prevent variable name collisions.

x starts as 1 but you change it in the loop like this:
var x = Math.floor(Math.random() * (max - min)) + min;
which returns a number between 0-100 and the loop continues until it reaches above the random number.

Related

Node js : find the same RSI as tradingview

the following code works but does not give me the same value as on tradingview. I don't understand the problem
var rsi_gain = 0;
var rsi_loss = 0;
for (let i = 18; i <= 20; i++) {
rsi_gain += (content[i][4] > content[i - 1][4]) ? (content[i][4] - content[i - 1][4]) : 0;
rsi_loss += (content[i][4] < content[i - 1][4]) ? (content[i - 1][4] - content[i][4]) : 0;
}
// Calcul Average Gain
var AVG_gain = (rsi_gain / 3); // (Gains / Periode)
// Calcul Average Loss
var AVG_loss = (rsi_loss / 3); // (Pertes / Periode)
//RS
var RS = (AVG_gain / AVG_loss);
//RSI
var RSI = 100 - (100 / (1 + RS));
My result with these values (48979.05,48861.92,48964.83) : 53.23
Tradingview result : 62.61
image : https://www.zupimages.net/viewer.php?id=21/51/y7ik.jpeg
Thank you
The first N bars (length) are calculated by using a simple moving average, afterwards you have to apply a exponential average.
https://www.tradingview.com/pine-script-reference/v5/#fun_ta{dot}rsi
https://www.tradingview.com/pine-script-reference/v5/#fun_ta{dot}rma

Why does this javascript while loop hang?

I was trying a very simple thing with javascript, to create a minesweeper grid.
gridsize=9;
//grid initialisation
var grid=Array(gridsize).fill(Array(gridsize).fill(null));
// this comes from <https://stackoverflow.com/questions/1527803/generating-random-whole-numbers-in-javascript-in-a-specific-range>
function randint(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
nbombs=20;
insertedbombs=0;
while (insertedbombs<nbombs){
rx=randint(0,gridsize-1);
ry=randint(0,gridsize-1);
if (grid[rx][ry] == null){
insertedbombs++;
grid[rx][ry]='b';
}
}
The while loop hangs, both in Chrome and Firefox consoles, all the values of the grid are filled, not just 20, i've no idea why, i guess i have some wrong understanding of javascript language, because the same code in python works.
Working python code:
grid= [[None for i in range(9)]for i in range(9)]
nbombs=20;
insertedbombs=0;
while (insertedbombs< nbombs):
rx=random.randint(0,8)
ry=random.randint(0,8)
if (grid[rx][ry]== None):
grid[rx][ry]='b'
insertedbombs+=1
The issues is that Array#fill doesn't do what you think it does.
In your example you create a SINGLE array Array(gridsize).fill(null) and then you put that array at each index of the outer array. Meaning that your grid actually contains the same array, 9 times over. So when you assign grid[0][0] you actually assign grid[0][0], grid[1][0], grid[2][0], grid[3][0], etc... all at once (ish).
const gridSize = 9;
//grid initialisation
const grid = Array(gridSize).fill(Array(gridSize).fill(null));
console.log(grid[0] === grid[1]);
grid[0][0] = 10;
console.log(grid[0][0], grid[0][0] === grid[1][0]);
What you want to do, is first fill the array with some dummy value, like null. Then map over the array and replace each entry with its own copy of Array(gridsize).fill(null).
const gridSize = 9;
//grid initialisation
const grid = Array(gridSize)
.fill(null)
.map(() => Array(gridSize)
.fill(null)
);
const randInt = (min, max) =>
Math.floor(Math.random() * (max - min + 1)) + min;
const nbombs = 20;
let insertedbombs = 0;
while (insertedbombs < nbombs){
const rx = randInt(0, gridSize - 1);
const ry = randInt(0, gridSize - 1);
if (grid[rx][ry] === null){
insertedbombs += 1;
grid[rx][ry] = 'b';
}
}
console.log(grid);

JavaScript array is too small for c-w saving algorithm, what to do?

I am implementing-w saving algorithm.
I implemented it and tested on small sets, works great. but when I input the large data, a problem occurs in the saving functions, which computes
c(i,j) = c(start,i) + c(start,j) - c(i,j)
where c(i,j) is the cost for traveling from i to j.
so I have to compute that first, but it turned out extremely big computations, I think it takes, since I have over 9000 locations in my data.
9000+8999+ ...... +1 = 50,000,000 (near to that)
steps.
here is my function to compute savings.
this.calc_savings=function()
{
var size = this.city_array.length; //number of cities: greater than 9000
var start =start_city_index;
for(var i=0; i < size; i ++)
{
if(i != start)
{
for(var j=i+1; j< size ; j++)
{
if(j !=start)
{
var dis1 = this.get_distance(start,i);
var dis2 = this.get_distance(start,j);
var dis3 = this.get_distance(j,i);
var cost = dis1 + dis2 - dis3;
var m_save = new saving(i,j,cost);
this.savings.push(m_save);
}
}
}
}
};
it is reporting heap out of memmory error.
And I find out that without
get_distance(...)
function, it works fast.
that function computes distance between two earth coordinates, as shown
function calcCrow(lat1, lon1, lat2, lon2)
{
var lati, latj, longi, longj;
var q1, q2, q3, q4, q5;
var m_pi = 3.14159265358979323846264;
lati = m_pi * lat1 / 180.0;
latj = m_pi * lat2 / 180.0;
longi = m_pi * lon1 / 180.0;
longj = m_pi * lon2 / 180.0;
q1 = Math.cos (latj) * Math.sin(longi - longj);
q3 = Math.sin((longi - longj)/2.0);
q4 = Math.cos((longi - longj)/2.0);
q2 = Math.sin(lati + latj) * q3 * q3 - Math.sin(lati - latj) * q4 * q4;
q5 = Math.cos(lati - latj) * q4 * q4 - Math.cos(lati + latj) * q3 * q3;
var dis_meter = (6378388.0 * Math.atan2(Math.sqrt(q1*q1 + q2*q2), q5) + 1.0);
return dis_meter / 1000;
};
which is called by
this.get_distance=function(first,next)
{
var first_city,next_city;
first_city = this.city_array[first];
next_city = this.city_array[next];
return Math.floor(calcCrow(first_city.x, first_city.y, next_city.x, next_city.y));
};
thes saving is defined as
var saving = function( x_int, y_int,value)
{
this.x =x_int ; //latitude
this.y =y_int ; //longitude
this.value = value;
};
so,what should I do?
Any suggestions?
You can reduce the amount of calls to get_distance a lot, by simply caching the results, since I assume that these Values don't change during one loop.
this.calc_savings = function(){
var size = this.city_array.length; //number of cities: greater than 9000
var startDistances = this.city_array.map((city,i) => i === start_city_index? 0: this.get_distance(start_city_index, i));
for(var i=0; i < size; ++i){
if(i === start_city_index) continue;
var dis1 = startDistances[i];
for(var j=i+1; j<size; ++j){
if(j === start_city_index) continue;
var dis2 = startDistances[j];
var dis3 = this.get_distance(j, i);
var cost = dis1 + dis2 - dis3;
this.savings.push(new saving(i, j, cost));
}
}
};
maybe you can even cache startDistances as long as start_city_index doesn't change; that would reduce the cost to compute even more.
If you include your implementation of get_distance and new saving(), there could be even more improvements possible.
Edit: I just realized that we're talking about cities, and that they don't move that much ;) so the distances are pretty static. You can precompute them once and cache em all; that's not even a big overhead, since you already have to do this in a single call to calc_savings. This would reduce your cost to call get_distance to a single lookup at an Array. Although, it might have quite a memory impact (9000 values -> 40495500 possible combinations -> ~155MB to store that many ints)
//Beware, code is untested
this.init_cache = function(){
var rad = Math.PI / 180;
var size = this.city_array.length;
var _distances = this._distances = Array(size * (size-1) / 2);
var _offsets = this._offsets = Array(size);
for(var i = 0, k = 0; i<size; ++i){
_offsets[i] = k;
var a = this.city_array[i],
lat1 = a.x * rad,
lon1 = a.y * rad;
for(var j = i+1; j<size; ++j){
var b = this.city_array[j],
lat2 = b.x * rad,
lon2 = b.y * rad,
q1 = Math.cos(lat2) * Math.sin(lon1 - lon2),
q3 = Math.sin((lon1 - lon2)/2),
q4 = Math.cos((lon1 - lon2)/2),
q2 = Math.sin(lat1 + lat2) * q3*q3 - Math.sin(lat1 - lat2) * q4*q4,
q5 = Math.cos(lat1 - lat2) * q4*q4 - Math.cos(lat1 + lat2) * q3*q3,
dist = 6378388 * Math.atan2(Math.sqrt(q1*q1 + q2*q2), q5) + 1;
_distances[k++] = Math.floor( dist / 1000 );
}
}
};
this.get_distance = function(i, j){
if(i === j) return 0;
if(j < i) i^=j, j^=i, i^=j; //swap i and j
this._distances || this.init_cache(); //just ensuring that cache is initialized when using it.
return this._distances[ this._offsets[i] + j-i-1 ]
};
this.calc_savings = function(){
var size = this.city_array.length;
for(var i = 0; i < size; i ++){
if(i === start_city_index) continue;
var dis1 = this.get_distance(start_city_index,i);
for(var j = i+1; j < size; j++){
if(j === start_city_index) continue;
var dis2 = this.get_distance(start_city_index,j);
var dis3 = this.get_distance(j,i);
var cost = dis1 + dis2 - dis3;
this.savings.push(new saving(i,j,cost));
}
}
};

why is this not working (js)

can someone tell why this does not work?
the code does print "generating fish" but than not printing enything...
function fish(x, y, degree, genes, Snumber) {
this.x = x;
this.y = y;
this.dgree = degree;
this.energy = 50;
this.genes = genes;
this.Snumber = Snumber;
}
fishs = new Array(10);
Snumber = 0;
document.writeln("generating fish");
for (i = 0; i < 10; i++) {
x = Math.round(Math.random * 600);
y = Math.round(Math.random * 600);
degree = Math.round(Math.random * 360);
genes + new Array(12);
for (j = 0; j < 12; j++) {
genes[j] = Math.random * 2 - 1;
}
fishs[i] = new fish(x, y, degree, genes, Snumber);
Snumber++;
document.writeln("genarating fish num" + i);
}
You have couple of errors and warnings in your code:
1.) You don't user the var keyword, so you automatically put the variables on the global scope.
2.) You use a + operator instead of an = in the line:
genes + new Array(12);
3.) You use Math.random (wich returns the random function, not a random number) instead of the function in 3 places.
4.) You use document.write(ln), which is deprecated. Use console.log instead (which prints to the console, hit F12 to see it)

Creating a slider between two numbers

So I've been working on re-producing the slider found here https://www.skylight.io/ ( Scroll down to find the price slider ).
So far Ive managed to create something similiar, but some numbers are hard coded, making it difficult to change and not very re-usable.
I've been researching around and I think I need to use Math.log() and Math.exp() together to achieve something like in the link above but I'm not sure.
Heres a jsfiddle of what I have so far https://jsfiddle.net/7wrvpb34/.
I feel that its the maths part of this problem that is halting me I think, so any help would be greatly appreciated.
Javascript code below:
var slider = document.getElementById("slider")
var sliderFill = document.getElementById("slider-fill")
var knob = document.getElementById("knob")
var mouseDown;
var mousePos = {x:0};
var knobPosition;
var minPrice = 20;
var price = 0;
var minRequests = 50;
var requests = 50 + ",000";
var incrementSpeed = 2;
var incrementModifier = 20;
var incrementValue = 1;
var minMillionCount = 1;
var millionCount = 1;
var previousRequestAmount = 0;
document.getElementById("price").innerHTML = price;
document.getElementById("requests").innerHTML = requests;
highlightTable(1);
document.addEventListener('mousemove', function(e) {
if(mouseDown) {
updateSlider(e);
}
})
function updateSlider(event) {
mousePos.x = event.clientX - slider.getBoundingClientRect().left;
mousePos.x -= knob.offsetWidth / 2;
console.log(mousePos.x);
if(mousePos.x < 0) {
knob.style.left = "0px";
sliderFill.style.width = "0px";
price = 0;
requests = 50 + ",000";
document.getElementById("price").innerHTML = price;
document.getElementById("requests").innerHTML = requests;
return
}
if(mousePos.x > slider.offsetWidth - 20) {
return
}
sliderFill.style.width = mousePos.x + 10 + "px";
knob.style.left = mousePos.x + "px";
//Increase requests by using X position of mouse
incrementSpeed = mousePos.x / incrementModifier;
requests = minRequests + (mousePos.x * incrementSpeed);
//Round to nearest 1
requests = Math.round(requests / incrementValue) * incrementValue;
if (requests >= 1000){
var m = requests/ 1000;
m = Math.round(m / 1) * 1;
//Problem, lower the modifier depending on requests
incrementModifier = 20 * 0.95;
document.getElementById("requests").innerHTML = m + " million";
//Adjust Prices
if(( requests >= 1000) && (requests < 10000)) {
var numOfMillions = requests / 100;
//Round to closest 10.
//10 * number of millions
var rounded = Math.round(numOfMillions / 10) * 10;
price = minPrice + rounded;
highlightTable(3);
}
//Adjust Prices
if(requests >= 10000) {
var numOfMillions = requests / 1000;
var rounded = Math.round(numOfMillions / 1) * 1;
var basePrice = minPrice * 6;
price = basePrice + rounded;
highlightTable(4);
}
} else {
incrementModifier = 20;
document.getElementById("requests").innerHTML = requests + ",000"
if(requests < 100) {
highlightTable(1);
price = 0;
} else {
highlightTable(2);
price = 20;
}
}
previousRequestAmount = requests;
document.getElementById("price").innerHTML = price;
}
knob.addEventListener('mousedown', function() {
mouseDown = true;
});
document.addEventListener('mouseup', function() {
mouseDown = false;
});
function highlightTable(rowNum) {
var table = document.getElementById("payment-table")
for(var i = 0; i < table.rows.length; ++i) {
var row = table.rows[i]
if(i == rowNum) {
row.style.background = "grey"
} else {
row.style.background = "white";
}
}
}
Thank you for your time.
If you want it to be reusable you need to create a mathematical function that assigns a result to the number of requests. I will give you a very easy example.
If you want a different result for 1,10,100,100,10000 etc
var d = Math.log10(requests);
if(d<1){
doSomething();
}else if(d<2){
doSomethingElse();
} //etc
This way if you want to change the specific values that create certain results, all you need to do is change the function.
This only works if your tiers of requests follow a math function, if they don't you need to hard code it.
However if say they don't follow a math function, but you know how you would like them to change based on a value then you can do this.
var changingValue = 4;
if(requests < 400*changingValue){
doSomthing();
}else if(requests <= 400*changingValue*changingValue){
doSomethingElse();
}else{// the requests is greater than any of the above
doTheOtherThing();
}
Edit:
For the second one you need to make sure that each condition if always larger than the other from top to bottom.
The description "increasingly increasing" matches an arbitrary number of functions. I assume you also want it to be continuous, since you already have a non-continuous solution.
TL;DR
Use an exponential function.
Generic approach
Assuming imin and imax are the minimal and maximal values of the slider (i for input) and omin and omax are the minimal and maximal values to be displayed, the simplest thing I can think of would be a multiplication by something based on the input value:
f(x)
{
return omin + (omax - omin) * g((x - imin) / (imax - imin));
}
This will pass 0 to g if x == imin and 1 if x == imax.
The return value r of g(y) should be
r == 0 for y == 0
r == 1 for y == 1
0 < r < y for 0 < y < 1
The simplest function that I can think of that fulfills this is an exponential function with exponent > 1.
An exponent of 1 would be a linear function.
An exponent of 2 would be make the middle of the slider display one fourth of the maximum price instead of half of it.
But you really need to find that exponent yourself, based on your needs.

Categories

Resources