JS learning exercise? [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
So I'm just starting out teaching myself JS from a cheesy textbook and there's a challenge to figure out what this code does:
function clunk (times) {
var num = times;
while (num > 0) {
display("clunk");
num = num - 1;
}
}
function thingamajig (size) {
var facky = 1;
clunkCounter = 0;
if (size == 0) {
display("clank");
} else if (size == 1) {
display("thunk");
} else {
while (size > 1) {
facky = facky * size;
size = size - 1;
}
clunk (facky);
}
}
function display(output) {
console.log(output);
clunkCounter = clunkCounter + 1;
}
var clunkCounter = 0;
thingamajig(5);
console.log(clunkCounter);
For the life of me, I can't follow the logic here that gives the answer at the back, which is that "clunk" will display in the console 120 times. They mention it has to do with factorials (I was never any good with math...) but I can't find the step where the code to display "clunk" repeats that many times. To spare you all the details, every time I walk through it on paper/in my head I just get "clunk" 1 as the output in the console... can anyone hold my hand through this or show me where this factorial part is happening? Thanks!

I am not going to go through the code with you. But I am going to introduce you to a method in which you can go through the code with yourself, inspect it step by step, and understand it better.
What i am referring to is the use of debugging. By running the above code with node inspect script.js you can run the script in a debugging mode. This will allow you to place little stop signs within the script that will help you analyze what's going on as it is running.
The main stop sign is simply debugger.
When you put this in the code, the inspect mode will stop at that point and let you access the different variables and methods set up in the script from the console it self. That way you can track what's happening to the different elements and see step by step how the script is operating.
Analyzing it this way will help you understand the logic in a much more profound way and I highly recommend you give it a try.
Here is the script with the debugger set up in a decent way:
function clunk (times) {
var num = times;
while (num > 0) {
display("clunk");
num = num - 1;
debugger;
}
}
function thingamajig (size) {
var facky = 1;
clunkCounter = 0;
debugger;
if (size == 0) {
display("clank");
debugger;
} else if (size == 1) {
display("thunk");
debugger;
} else {
while (size > 1) {
facky = facky * size;
size = size - 1;
debugger;
}
clunk (facky);
}
}
function display(output) {
console.log(output);
clunkCounter = clunkCounter + 1;
debugger;
}
var clunkCounter = 0;
thingamajig(5);
console.log(clunkCounter);
Try it out!
Here are the docs about debugger.
PRO TIP:
You can literally just copy paste the code into your chrome console and it will start the chrome debugger running the script.

Because aviya.developer has already shared with you how to debug the program, I'll talk to you about the algorithm. I would suggest you study up on programming fundamentals a bit more, because it seems like you might now have a good grasp on how loops work. This algorithm relies on the variables facky, and size to do the factorial calculation, which we then pass to the display method. So you can repeat that for a few iterations and you should be able to start to understand the flow of the program. The factorial part is the while loop in the thingamajig method.
facky = facky * size;
facky is initialized to 1, and our size is 5.
The formula for a factorial can be found easily online:
n!=n×(n−1)×(n−2)...×2×1
5! = 5 * 4 * 3 * 2 * 1 = 120
Iteration 1: 1 * 5 = 5
Iteration 2: 5 * 4 = 20
Iteration 3: 20 * 3 = 60
Iteration 4: 60 * 2 = 120
Iteration 5: 120 * 1 = 120
This is the value that we will call the function clunk with.
clunk also has a while loop, which has a termination condition of num > 0. This means we will continue to iterate while this condition is true. Once it is no longer true, the iteration will stop.
This means, we will call the method displaywith a value of "clunk" 120 times before the iteration ends.
When you are analyzing an algorithm, it's important to figure out the key components/variables/operations of that algorithm, and keep track of how they change over time or through iterations. This will indicate when the end-goal is reached.

Related

Fibonacci for large numbers in Javascript

I have the following code:
function fib(n) {
let first=BigInt(0);
let snd=BigInt(1);
let currentNumber;
let countMax=Math.abs(n)+1;
let counter=2;
if(n==0){
return first;
}
else if (n==1||n==-1){
return snd;
}
while(counter<countMax)
{
currentNumber=first+snd;
first=snd;
snd=currentNumber;
counter++;
}
if((n<0) && (n % 2 ==0))
{
return -currentNumber;
}
return currentNumber;
}
That returns the fibonacci number for the given (n).
My issue is that I have to improve the performance of this code. I tried to use different fibonacci formulas (exponential ones) but I lose a lot of precision cause phi number has infinite decimals, so I have to truncate and for big numbers I lost a lot of precision.
When I execute for instance fib(200000) I get the huge number but the code spends more than 12000 ms.
For other hand I tried using recursion but the performance decreases.
Could you provide me an article or clue to follow?
Thanks & Regards.
First of all, you can refer the answer here which says that
Fib(-n) = -Fib(n)
Here's the recursive implementation which is not efficient as you mentioned
function fib(n) {
// This is to handle positive and negative numbers
var sign = n >= 0 ? 1 : -1;
n = Math.abs(n);
// Now the usual Fibonacci function
if(n < 2)
return sign*n;
return sign*(fib(n-1) + fib(n-2));
}
This is pretty straightforward and I leave it without explaining because if you know Fibonacci series, you know what the above code does. As you already know, this is not good for very large numbers as it recursively calculate the same thing again and again. But we'll use it in our approach later on.
Now coming towards a better approach. See the below code similar to your code just a bit concise.
function fib(n) {
if(n == 0)
return 0;
var a = 1;
var b = 1;
while(n > 2) {
b = a + b;
a = b - a;
}
// If n is negative then return negative of fib(n)
return n < 0 ? -1*b : b;
}
This code is better to use when you want to call this function only a few times. But if you want to call it for frequently, then you'll end up calculating the same thing many times. Here you should keep track of already calculated values.
For example, if you call fib(n) it will calculate nth Fibonacci number and return it. For the next time if you call fib(n) it will again calculate it and return the result.
What if we store this value somewhere and next time retrieve it whenever required?
This will also help in calculating Fibonacci numbers greater than nth Fibonacci number.
How?
Say we have to calculate fib(n+1), then by definition fib(n+1) = fib(n) + fib(n-1). Because, we already have fib(n) calculated and stored somewhere we can just use that stored value. Also, if we have fib(n) calculated and stored, we already have fib(n-1) calculated and stored. Read it again.
We can do this by using a JavaScript object and the same recursive function we used above (Yes, the recursive one!). See the below code.
// This object will store already calculated values
// This should be in the global scope or atleast the parent scope
var memo = {};
// We know fib(0) = 0, fib(1) = 1, so store it
memo[0] = 0;
memo[1] = 1;
function fib(n) {
var sign = n >= 0 ? 1 : -1;
n = Math.abs(n);
// If we already calculated the value, just use the same
if(memo[n] !== undefined)
return sign*memo[n];
// Else we will calculate it and store it and also return it
return sign*(memo[n] = fib(n-1) + fib(n-2));
}
// This will calculate fib(2), fib(3), fib(4) and fib(5).
// Why it does not calculate fib(0) and fib(1) ?
// Because it's already calculated, goto line 1 of this code snippet
console.log(fib(5)); // 5
// This will not calculate anything
// Because fib(-5) is -fib(5) and we already calculated fib(5)
console.log(fib(-5)); // -5
// This will also not calculate anything
// Because we already calculated fib(4) while calculating fib(5)
console.log(fib(4)); // 3
// This will calculate only fib(6) and fib(7)
console.log(fib(7)); // 13
Try out some test cases. It's easy to understand why this is faster.
Now you know you can store the already calculated values, you can modify your solution to use this approach without using recursion as for large numbers the recursive approach will throw Uncaught RangeError. I leave this to you because it's worth trying on your own!
This solution uses a concept in programming called Dynamic Programming. You can refer it here.
If you just add the previous value to the current one and then use the old current value as the previous one you get a significant improvement in performance.
function fib(n) {
var current = 1;
var previous = 0;
while (--n) {
var temp = current;
current += previous;
previous = temp;
}
return current;
}
console.log(fib(1)); // 1
console.log(fib(2)); // 1
console.log(fib(3)); // 2
console.log(fib(4)); // 3
console.log(fib(5)); // 5
You can also use an array in the parent scope to store the previous values to avoid redoing the same calculations.
var fibMap = [1, 1];
function fib(n) {
var current = fibMap[fibMap.length - 1];
var previous = fibMap[fibMap.length - 2];
while (fibMap.length < n) {
var temp = current;
current += previous;
previous = temp;
fibMap.push(current);
}
return fibMap[n - 1];
}
console.log(fib(1)); // 1
console.log(fib(2)); // 1
console.log(fib(3)); // 2
console.log(fib(4)); // 3
console.log(fib(5)); // 5
Benchmark for getting the 1000th number 3 times

JavaScript loop using set amount of steps while skipping specific step

I am trying to create a loop that allows you to go up in increments of one each time using "x" amount of steps while skipping a specific step. example 1 would be you have 2 actions and need to skip step 2. so you would go from 0 to 1 and then 1 to 3. example 2 would be you have 3 actions and need to skip step 3 so you could either go from 0 to 1, wait 1 round, then go from 1 to 4 since you would be skipping up two. or you could wait at 0 then skip to 2 and then skip to 5.
i know I am close using a while loop with continue but it doesn't quite work like expected.
function maxStep(n, k) {
let step = n
let bad = k
let total = 0
while (total <= step) {
total += 1
if (total === bad) {
continue;
}
total += 1
return total
}
}
Hello and welcome #jaronow!
First, continue skips you to the next iteration of the while. So what you've written here...
if (total === bad) {
continue;
}
total += 1
...actually means, "If this is a bad number of steps, then skip adding 1." But you mean the opposite, don't you?
if (total === bad) {
total += 1
}
This now says, "If this is a bad number of steps, add another 1." There, so now we have
function maxStep(n, k) {
let step = n
let bad = k
let total = 0
while (total <= step) {
total += 1
if (total === bad) {
total += 1 // Put this here instead of continue.
}
return total
}
}
Now, where you put this is odd:
return total
This actually exits the entire function the first time it's encountered. Surely you mean to calculate total by running through your loop as many times as needed, then return the result at the end, like this:
function maxStep(n, k) {
let step = n
let bad = k
let total = 0
while (total <= step) {
total += 1
if (total === bad) {
total += 1
}
}
return total // Moved this out.
}
Finally, there's two subtle issues (noticed the second one later). First, if you take that "extra step" because you've encountered a bad step, you need to increase step as well, since it's the maximum number of steps you plan to take. But also, once you reach that number of steps, you don't want to enter the loop again and add another to total, so you need to use < instead of <=. (You'll find it a common pattern in programming that when you intend to do things N times, you write your loops saying < N, not <= N.)
function maxStep(n, k) {
let step = n
let bad = k
let total = 0
while (total < step) {
total += 1
if (total === bad) {
total += 1
step += 1 // Add this.
}
}
return total
}
Otherwise, your total will always end up at the original number of steps.
There are other shorter, possibly more clever ways of solving this problem, but I'm aiming to teach by sticking to your formulation.
Not something you have to care about, but in case you want to see, a seasoned programmer may "refactor" your code this way:
function getStepsTaken(desiredStepsToTake, badNumberOfSteps) {
let stepsToTake = desiredStepsToTake
// let bad = k (don't need this line)
let stepsTaken = 0
while (stepsTaken < stepsToTake) {
stepsTaken += 1
if (stepsTaken === badNumberOfSteps) {
stepsTaken += 1
stepsToTake += 1
}
}
return stepsTaken
}
You may find it ugly, and indeed it's much more verbose, but it's always better to make things very clear, even if just for yourself and you rename the variables later.
Solid attempt though, keep it up.

Javascript code for making my browser slow down

I'm writing a library for WebWorkers, and I want to test the difference between running a script in the main page thread, versus in one or more workers. The problem is: I can't find out of hand a short function which will strain my browser enough that I can observe the difference.
A quick search didn't return much, but it might just be that I don't really know what to search for; usually I try to optimise my code, not make it slower...
I'm looking for algorithms or patterns that can be easily implemented in pure Javascript, that do not depend on the DOM or XHR, and which can have an argument passed to limit or specify how far the calculation goes (no infinite algorithms); 1s < avg time < 10s.
Extra points if it can be built without recursion and if it does not incur a significant memory hog while still being as processor intensive as possible.
Try using the obvious (and bad) recursive implementation for the Fibonacci sequence:
function fib(x) {
if (x <= 0) return 0;
if (x == 1) return 1;
return fib(x-1) + fib(x-2);
}
Calling it with values of ~30 to ~35 (depending entirely on your system) should produce good "slow down" times in the range you seek. The call stack shouldn't get very deep and the algorithm is something like O(2^n).
/**
* Block CPU for the given amount of seconds
* #param {Number} [seconds]
*/
function slowdown(seconds = 0.5) {
const start = (new Date()).getTime()
while ((new Date()).getTime() - start < seconds * 1000){}
}
slowdown(2)
console.log('done')
Calling this method will slow code down for the given amount of seconds (with ~200ms precision).
Generate an array of numbers in reverse order and sort it.
var slowDown = function(n){
var arr = [];
for(var i = n; i >= 0; i--){
arr.push(i);
}
arr.sort(function(a,b){
return a - b;
});
return arr;
}
This can be called like so:
slowDown(100000);
Or whatever number you want to use.
Check out the benchmarking code referenced by the Google V8 Javascript Engine.
For some reason Bogosort comes to mind. Basically it's a sorting algorithm that consists of:
while not list.isInOrder():
list.randomize()
It has an average complexity of O(n * n!) with little memory, so it should slow things down pretty good.
The main downside is that its running time can be anywhere from O(n) to O(inf) (though really, O(inf) is pretty unlikely).
Everyone seems determined to be complicated. Why not this?
function waste_time(amount) {
for(var i = 0; i < amount; i++);
}
If you're concerned the browser will optimize the loop out of existence entirely, you can make it marginally more complicated:
function waste_time(amount) {
var tot = 0;
for(var i = 0; i < amount; i++)
tot += i;
}
Compute lots of square roots manually?
function sqrt(number, maxDecimal) {
var cDecimal = -1;
var cNumber = 0;
var direction = -1;
while(cNumber * cNumber !== number && cDecimal < maxDecimal) {
direction = -direction;
cDecimal++;
while((cNumber * cNumber - number) / Math.abs(cNumber * cNumber - number) === direction) cNumber += direction * Math.pow(10, -cDecimal);
}
return Math.abs(cNumber);
}
function performTest() {
for(var i = 0; i < 10000; i++) {
sqrt(i, 3);
}
}
Maybe this is what you are looking for:
var threadTest = function(durationMs, outputFkt, outputInterval) {
var startDateTime = (new Date()).getTime();
counter = 0,
testDateTime = null,
since = 0,
lastSince = -1;
do {
testDateTime = (new Date()).getTime();
counter++;
since = testDateTime - startDateTime;
if(typeof outputFkt != 'undefined' && lastSince != since && testDateTime % outputInterval == 0) {
outputFkt(counter, since);
lastSince = since;
}
} while(durationMs > since);
if(typeof outputFkt != 'undefined') {
outputFkt(counter, since);
}
return counter;
}
This method will simply repeat a check in a loop
durationMS - duartion it should run in miliseconds
OPTIONAL:
outputFkt - a callback method, for logging purpose function(currentCount, milisecondsSinceStart)
outputInterval - intervall the output function will be called
I figured since you do not want to test a real function, and even NP-Hard Problems have a ratio between input length and time this could be a easy way. You can measure performance at any interval and of course receive the number of loops as a return value, so you can easily measure how much threads interfere each others performance, with the callback even on a per cycle basis.
As an example here is how i called it (jQuery and Dom usage are here, but as you can see optional)
$(document).ready(function() {
var outputFkt = function(counter, since) {
$('body').append('<p>'+counter+', since '+since+'</p>');
};
threadTest(1000, outputFkt, 20);
});
A last Warning: Of course this function can not be more exact than JS itself. Since modern Browsers can do much more than one cycle in one Milisecond, there will be a little tail that gets cut.
Update
Thinking about it... actually using the ouputFkt callback for more than just output could give great insight. You could pass a method that uses some shared properties, or you could use it to test great memory usage.

how restricted is recursion in javascript?

I guess its to stop browsers getting nailed all the time by duff code but this:
function print(item) {
document.getElementById('output').innerHTML =
document.getElementById('output').innerHTML
+ item + '<br />';
}
function recur(myInt) {
print(myInt);
if (int < 10) {
for (i = 0; i <= 1; i++) {
recur(myInt+1);
}
}
}
produces:
0
1
2
3
4
5
6
7
8
9
10
10
and not the big old mess I get when I do:
function recur(myInt) {
print(myInt);
if (int < 10) {
for (i = 0; i <= 1; i++) {
var x = myInt + 1;
setTimeout("recur("+x+")");
}
}
}
Am I missing something or is this how you do recursion in JS? I am interested in navigating trees using recursion where you need to call the method for each of the children.
You are using a global variable as loop counter, that's why it only loops completely for the innermost call. When you return from that call, the counter is already beyond the loop end for all the other loops.
If you make a local variable:
function recur(int) {
print(int);
if (int < 10) {
for (var i = 0; i <= 1; i++) {
recur(int + 1);
}
}
}
The output is the same number of items as when using a timeout. When you use the timeout, the global variable doesn't cause the same problem, because the recursive calls are queued up and executed later, when you have exited out of the loop.
I know what your doing wrong. Recursion in functions maintains a certain scope, so your iterator (i) is actually increasing in each scope every time the loop runs once.
function recur(int) {
print(int);
if (int < 10) {
for (var i = 0; i <= 1; i++) {
recur(int+1);
}
}
}
Note it is now 'var i = 0' this will stop your iterators from over-writing eachother. When you were setting a timeout, it was allowing the first loop to finish running before it ran the rest, it would also be running off the window object, which may remove the closure of the last iterator.
Recursion is very little restricted in JavaScript. Unless your trees are very deep, it should be fine. Most trees, even with millions of elements, are fairly wide, so you get at most log(n) recursive calls on the stack, which isn't noramally a problem. setTimeout is certainly not needed. As in your first example, you're right that sometimes you need a guard clause to guarantee that the recursion bottoms out.

Javascript for loop and setTimeout issue

So I thought that the following code would be really simple but has become a big headache. It should be a loop that will change the opacity of and object so that it fades away.
function doSomething()
{
var i = 10;
for(i = 10; i >=0; i = i - 1)
{
setTimeout("setOpacity('t1',"+ i +")", 100*i);
WRITE 1
}
}
function setOpacity(elem, hmm)
{
WRITE 2
document.getElementById(elem).style.opacity = (10 - hmm)/10;
document.getElementById(elem).style.filter = 'alpha(opacity=' + (10 - hmm)*10 + ')';
}
So the problem is that the for loop is counting down from 10 to 0 and this has been confirmed by a print statement located at WRITE 1. However in the setOpacity method the numbers being received are starting at 0 and counting to 10 and this has been confirmed by a print statement at WRITE 2.
I would like to know why this is happening and how I can fix it. I believe it has something to do with the setTimeout call executing the method call after the end of the loop, but if that is so then why are the values being passed to setOpacity incrementing?
Any help is much appreciated.
The values being passed to setOpacity are increasing because you are passing different timeouts. The result of your loop is essentially the following:
setTimeout("setOpacity('t1', '10')", 1000)
setTimeout("setOpacity('t1', '9')", 900)
setTimeout("setOpacity('t1', '8')", 800)
....
setTimeout("setOpacity('t1', '0')", 0)
The result is that they are called in reverse order based on the timings. So the last call gets executed in 0ms (after the function finishes), resulting in 0 as hmm, followed by 1, 2, 3 ...
To fix this you need to change 100*i to 100 * (10 - i)

Categories

Resources