JavaScript loop using set amount of steps while skipping specific step - javascript

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.

Related

Why does my JavaScript solution to problem 2 (project euler) show infinity on the console?

let arr=[0,1];
let sum=0;
for(let i=2;i<4000000;i++) {
arr.push(arr[i-1]+arr[i-2]);
}
for (let i=0;i<arr.length;i++) {
if (arr[i]%2==0) {
sum+=arr[i];
}
}
console.log(sum);
By considering the terms in the Fibonacci sequence whose values do not
exceed four million, find the sum of the even-valued terms.
My solution to this question is wrong and I can't figure out why at all. I am not that experienced so please if anyone can explain in a simple way why my code is wrong. What can I do to fix it??
Note: I haven't hadn't included code in this answer because I figure the point of what you're doing is to learn to code these things. (Now you've gotten most of the way there, I did add a solution at the end.)
The problem is that your sums quickly go beyond the range of what JavaScript's number type can represent, reaching the point where they just are represented by Infinity. The number type only has 53 effective significant bits in which to hold numbers. You're exceeding that:
let seen4M = false;
let seenInfinity = false;
let arr=[0,1];
let sum=0;
for(let i=2;i<4000000;i++) {
const num = arr[i-1]+arr[i-2];
if (!seen4M && num > 4_000_000) {
console.log(`Too big: ${num}`);
seen4M = true;
} else if (!seenInfinity && !isFinite(num)) {
console.log(`Overflowed just after ${arr[i-1]}`);
seenInfinity = true;
}
arr.push(num);
}
for (let i=0;i<arr.length;i++) {
if (arr[i]%2==0) {
sum+=arr[i];
}
}
console.log(sum);
You're doing four million (minus two) loops, but the question asks you to consider the Fibonacci numbers whose values are less than or equal to four million (4M), which is a very different thing and is reached much more quickly. So instead of (nearly) 4M loops, stop when your code determines that the next number is > 4M.
Also note that there's no reason to use an array for this, and doing so will consume a lot of memory unnecessarily. Instead, just remember the penultimate and ultimate values, and shuffle them in the loop. Maintain sum in the first loop rather than using a second one.
In a comment you showed that you'd solved it using an array but couldn't see how to solve it without using an array. Here's how to do that (see comments):
// The penultimate (second-to-last) Fibonacci number we've done
let pen = 0;
// The ultimate (last) Fibonacci number we've done
let ult = 1;
// The sum so far
let sum = 0;
// A variable for each number as we go
let num;
// Create the next number and keep looping if it's less than or
// equal to four million
while ((num = pen + ult) <= 4_000_000) {
// We have a new number (`num`), count it if appropriate
if (num % 2 == 0) {
sum += num;
}
// Now that we have a new number, shuffle the last two:
// our ultimate number is our penultimate number, and
// our ultimate number is the new one
pen = ult;
ult = num;
}
console.log(sum);

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

Traverse an object or array to determine if elements fit within ranges

I am building a decorator for arrays of items, the array of objects is meant to be slotted into a defined range of values if it fits there.
Currently, I am doing this using some conditionals to check for the range but the code does not feel clean enough to me.
Does anyone have any suggestions about how write this code in a more concise and expandable way?
Example of current setup...
thingsToSort.forEach(function(thing) {
if (thing > 1 || thing < 3) {
// set the item to 1
}
if (thing > 3 || thing < 5) {
// set to 3
}
})
Note: I am really looking for a better way to loop through this logic and determine if object falls in the range.
One another implementation.
Created a function to represent the Range, Range
A function to identify the range and take appropriate action. setcompareRange
Notice the usage of the some method in the function compareRange. Since a number can be found in one range only, All the ranges are not evaluated and till the matched range traversal is done.
function Range(min, max){
this.min = min;
this.max = max;
}
var rangeArray = [ new Range(1,3), new Range(3,5)];
function compareRange(c,i,arr){
var result = rangeArray.some(x=> {
return setcompareRange(c, x.min, x.max)
});
}
function setcompareRange(thing, min, max){
if (thing > min && thing < max) {
// set the item to 1
console.log("set thing = " + thing + " in range = " + min);
return true;
}
}
var thingsToSort = [2,4];
thingsToSort.forEach(compareRange);
I would first double-check your logic...
thingsToSort.forEach(function(thing) {
This conditional will set ANYTHING greater than 1 to 1, and ignore the second condition (thing < 3):
if (thing > 1 || thing < 3) {
// set the item to 1
}
You should be using an && operator to AND these two conditions:
if (thing > 1 && thing < 3) {
// set the item to 1
}
The same thing goes for this conditional which will set ANYTHING greater than 3 to 3.
if (thing > 3 || thing < 5) { //should be &&
// set to 3
}
})
You are also not breaking the loop after meeting a conditional. This means that even though you have already determined that a thing meets the first condition, you are still checking to see if it meets the other conditions. This wastes resources. Use else if to prevent this:
if (thing > 1 && thing < 3) {
// set the item to 1
}
else if (thing > 3 && thing < 5) {
// set to 3
}
Other than that, it's already pretty clean. This is very similar to the classic fizzbuzz problem, of which, there are many possible refactorings

How to make an infinite for loop (for(;;)) not crash?

I'm new to JS, so most of my code hasn't worked. I've made a program to find out every prime number, but every time I use it, it crashes. Is there any way to make this code not crash upon running?
var i = 0;
for (;;) {
if (i % 2 === 0 || i % 3 === 0 || i % 5 === 0 || i % 7 === 0) {
i++;
}
else {
return i;
i++;
}
}
The correct approach is to use a single timer. Using setInterval, you can achieve what you want as follows:
window.onload = function start() {
primes();
}
function primes() {
var i = 0;
window.setInterval(function () {
if (i % 2 === 0 || i % 3 === 0 || i % 5 === 0 || i % 7 === 0) {
i++;
} else {
console.log(i);
i++;
}
}, 1000); // repeat forever, new value every 1 second
}
This will print the values to the console once a match is found (It does a check every second). But you can adjust this on the second parameter of the setInterval function.
If you want the results on the actual page, you can replace the console.log() with document.createTextNode().
Also, i have not checked this or know if the algorithm is right. Just adapted from your code.
List of fixes:
You manually update i and use a blank for loop instead of using the for loop normally, but having the middle condition always return true (a while loop could be used here also, but would still require manually updating i) as you don't plan on stopping. However, you can actually just put the whole thing in a timer instead of a loop, like #Leonel Atencio did.
You use return outside of a function, and if you did put this code inside of a function, it would just return the first prime number every time, so it would always return 1.
The formula is incorrect, only checking for some examples of primes; As #Alexandru-Ionut Mihai said, 121 would be considered prime, even though it is 11x11.
Fixed:
var primes = [];
var i = 1; //Start at 2; since "i" is incremented at the start of the function, this won't start it at 1, which would cause problems (the array would only have 1 in it, since all other whole numebrs are divisible by one)
setInterval(primeFunc,100);
function primeFunc(){
i++; //Increment current number
isPrime=true; //Assume prime
for(var j=0;j<primes.length;j++){ //Rule out non-primes with the power of modulo
if(i%primes[j]==0) { //If the current number can be divided (is divisible) by any previous prime...
//...then it's not a prime, so cancel any further chacks and move on
isPrime=false;
break;
}
}
if(isPrime){
//The current number is not divisible by any other primes, so it is itself a prime; if it was divisible, isPrime would be set to false by our loop above
primes.push(i);
output.innerHTML=primes;
}
}
<span id="output"></span>

Basic JavaScript Algorithm, Fibonacci series

Sum all the odd numbers of the Fibonacci Series up to and including the given number.
I can't figure out the syntax for the problem I'm having. The problem, The for loop, loop ends when it is greater than or equal to the value of the num, instead I want it to end with the, to be generated values of the start.
Is there any way to make it work?
function sumFibs(num) {
var odd = [1]; // Odd numbers of the Fibonacci series
var start = [0,1]; // Fibonacci series
// Generating the series and filtering out the odd numbers
for(i=1;i<num;i++) {
var sum = 0;
sum = start[i] + start[i-1];
start.push(sum);
if(sum%2 != 0) {
odd.push(sum);
}
}
// Generating sum of the odd numbers
var main = 0; // sum of the odd numbers
for(i=0;i<odd.length;i++) {
main += odd[i]
}
console.log(start);console.log(odd);return main
}
sumFibs(4);
It should be like that if I understand correctly
while(start.length<num)
{
your code will be here
}
Instead of working with two arrays, maybe it's less confusing to work with one and use Array.prototype.reduce to sum only the odd values.
function sumFibs(num) {
var fib = [0, 1];
var sum = 0;
var i = 2;
while (true) {
sum = fib[i-2] + fib[i-1];
if (sum > num) {
break;
}
fib.push(sum);
i++;
}
return fib.reduce(function(v0, v) {
return v0 + (v % 2 === 0 ? 0 : v);
}, 0);
}
Have a look at my attempt at this:
http://jsfiddle.net/copet80/xejz4ka2/
Isnt this a Project Euler question?
If I understand the problem right then your problem is in the for loop. More specific in its condition. The for loop in your case will repeat itself so many times how num is -1 because you start at i = 1 and i < num. So in you case it will repeat istself 12 times and reach a much higher number than 13 if I understand the problem right.
First of, Im a beginner but I was taught that you use a for loop if you know how many times something has to repeat. In this case you dont know how many times you have to repeat the for loop because you dont know when you reach the number 13.
In this case a while loop would be better I think and you set the condition for you number. So for example:
while(sum<=num){}
or like somone before me said:
while (true){
if(sum<num){
break;
}
This 2 codes will end if the SUM will exceed 13. I belive you dont want the Fibonaci number too exceed 13. In this scenario you have to make other conditions but im feeling its project euler i wont give tha answer here.
Again. you have the loop condition to end if the fib number exceeds 13. Your code looks for 13-1 fibonacci numbers.

Categories

Resources