I want to print the first 5 numbers in the Fibonacci sequence starting with 1 and 2. I expect this code to print 1,2,3,5,8 when I click the button, but somehow it only prints the last number which is 8 in this case. And if I click the button many times after that, it always prints 2. Why does it behave that way?
/*
Fibonacci sequence is calculated by the formula An = An-1 + An-2
#param prev An-2
#param next An-1
#param n the first n numbers to print
*/
var count = 0; // keeps track of which number we are on
function fibonacci(prev, next, n) {
// Need to subtract 2 or else it will print the first 7 numbers instead of 5
return count++ < n - 2 ? fibonacci(Math.max(prev,next), prev+next, n) + "," : next;
}
document.querySelector('button').addEventListener('click', function() {
console.log(fibonacci(1, 2, 5));
});
<button>Click me</button>
You only use console.log with the last result. If you want to log all of them, you should use it inside the recursive function.
And the second time you click the button, it doesn't work because count is global. You could reset it to 0 inside the event listener, but better avoid globals.
function fibonacci(current, next, n) {
if(n > 0) {
console.log(current);
fibonacci(next, current + next, n-1);
}
}
document.querySelector('button').addEventListener('click', function() {
fibonacci(1, 2, 5);
});
<button>Click me</button>
You console.log() the return value of fibonacci(1,2,5), which is exactly one number. You do not print anything anywhere in your recursive function calls. So, obvioulsly, only tha final result of your function will be printed.
If you want intermediary results, console.log(prev) before your return statement in fibonacci().
This solves your first issue.
For the second issue, you need to keep in mind how your variables work. countis defined outside of the fuction fibonacci, and therefore not automatically reset or anything just because the function ends. This means: after the funciton ran for the first time (and as a side effect, setting count to 3), the variable count will keep it's value 3. The next time you run the function, count++ < n - 2 will evaluate to false right away, because 4 < 3 is false. So it will return next, which is 2 on the first iteration.
To fix this, restrucutre your function in a way that it resets count to 0 when the last recursion is done, before it returns next ( you cannot do this within the ternary statement, you need to refractore it to a regular if-else)
Let's use newest technologies.
<!DOCTYPE html>
<html>
<head>
<title>Fibonacci</title>
<meta charset="utf-8" />
<script type="text/javascript">
'use strict';
function* fibonacci(cur, nxt) {//generator function
//let cur=0,nxt=1;
yield cur;
yield nxt;
while(true){
[cur,nxt]=[nxt,cur+nxt];//swap
yield nxt;
}
}
function getNumbers(){
var a = document.getElementById('cur').value-0;//instead of parseInt
var b = document.getElementById('nxt').value-0;
var n = document.getElementById('cnt').value-0;
var fi = fibonacci(a,b);//init generator
var fiNums = [];//init result array
for (var i = 0; i < n; i++) {
var tmp=fi.next();//{value:1, done:false}
fiNums.push(tmp.value);
}
//output result
document.getElementById('output').innerHTML = fiNums.join(', ');
}
//get all series in once
function getNumbersOld(){
var a = document.getElementById('cur').value-0;
var b = document.getElementById('nxt').value-0;
var n = document.getElementById('cnt').value-0;
var fiNums = [b,a];
for (var i = 2; i < n; i++) {
fiNums.unshift(fiNums[0]+fiNums[1]);
}
document.getElementById('output').innerHTML = fiNums.reverse().join(', ');
}
</script>
</head>
<body>
Generate Fibonacci series <br />
Current:<input type="number" id="cur" value="1" />
Next:<input type="number" id="nxt" value="1" />
Count:<input type="number" id="cnt" value="5" />
<button onclick="getNumbersOld()">Get Numbers</button>
<div id="output"></div>
</body>
</html>
Based on the answers regarding the global variable and how I didn't print the result of each recursive call from others, I was able to obtain a final correct solution to my problem.
function fibanocci(prev, next, n) {
/*
n - 2 is here so it will print the first n numbers in the Fibonacci sequence
instead of n + 2 numbers because we have to account for the 2 initial numbers,
1 and 2 in this case, and I don't want the client to account for these 2 initial
numbers themselves. Math.abs(n-2) so the recursion will stop when n is 1 so the
call stack will not get bloated and throw an exception.
*/
return n > Math.abs(n-2) ? prev + "," + fibanocci(Math.max(prev,next), prev + next, --n) : prev;
}
document.querySelector('button').addEventListener('click', function() {
console.log(fibonacci(1, 2, 5));
});
Related
I am working on making a bingo game. I've gotten as far as being able to get a random number generated and displayed at the click of a button. My only issue is that some values will end up being generated more than once. THAT IS THE PART I'M POSTING THIS QUESTION FOR. EVERY VALUE SHOULD ONLY BE GENERATED & DISPLAYED ONCE UNTIL THE GAME IS RESET. Does anybody have any example code, preferably for how to use something like the splice() method that I keep hearing brought up?
I CAN ALREADY GENERATE THE RANDOM NUMBER FROM THE SET AND DISPLAY IT. I'M ONLY LOOKING TO MAKE SURE THAT NUMBERS THAT ARE GENERATED ARE NOT REPEATED.
<head>
<title>BINGO</title>
</head>
<body>
<div id="bingo">
<script>
let numbers = new Set()
.add("B1")
.add("B2")
.add("B3")
.add("B4")
.add("B5")
.add("B6")
.add("B7")
.add("B8")
.add("B9")
.add("B10");
let called = Array.from(numbers);
let display = new Array();
function getRandomNum()
{
function rando()
{
for (let i = called.length - 1; i > 0; i++)
{
const j = Math.floor(Math.random() * called.length);
const number = called[i];
called[i] = called[j];
called[j] = number;
return number;
//let show = called[Math.floor(Math.random() * called.length)];
//return show;
}
//document.getElementById('bingo').innerHTML = display[0];
}
let index = rando();
document.getElementById('bingo').innerHTML = index;
display.push(index);
}
function show()
{
for(let n = 0; n < display.length; n++)
{
document.getElementById('reveal').innerHTML += "<br/>" + display[n] + "<br/>";
}
}
</script>
</div>
<div id="button">
<button onclick="getRandomNum()">Random Number</button>
</div>
<br/>
<br/>
<br/>
<div id="reveal">
<button onclick="show()">Numbers Called</button>
</div>
</body>
</html>
Looking for some help to prevent number generated from being repeated (EXAMPLE CODE PREFERRED)
You could create an array in which you store all numbers which have already been selected. Then, when randomly selecting a new number, continue to randomize until a number has been selected which is not within that array of already-chosen numbers.
Here's a code example which illustrates this idea, picking numbers between 0 and 9, not allowing repeat numbers. The process is broken down below.
var alreadyPicked = [];
var max = 10;
function random() {
let unique = false;
while (!unique && alreadyPicked.length < max) {
let randNumber = Math.floor(Math.random() * max);
if (alreadyPicked.includes(randNumber) == false) {
unique = true;
alreadyPicked.push(randNumber);
}
}
}
An array, alreadyPicked, is declared. It serves to keep track of which numbers have already been selected, so that they won't be selected twice.
The number max is declared. It is used to prevent an infinite loop when there are no more random numbers to choose.
Random numbers are chosen in the while loop, which loops either until the unique boolean is set to true or until the length of the alreadyPicked array has reached the max length, which happens when there are no more unique numbers to select.
Once a number is obtained, the statement alreadyPicked.includes(randNumber) checks to see whether the randNumber is among those numbers already selected and stored in alreadyPicked.
If this is false, this means a unique number has been selected. unique is then set to true to break the loop, and the number is pushed to alreadyPicked so that it won't be selected again.
<head>
<title>BINGO</title>
</head>
<body>
<div id="bingo">
<script>
let numbers = ["B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "B10"]
let display = [];
function getRandomNum() {
function rando() {
for (var i = 0; i < numbers.length; i++) {
const j = Math.floor(Math.random() * numbers.length);
const number = numbers[j];
if (number) {
numbers.splice(j, 1);
}
if (numbers.length < 0) {
return
} else {
return number;
}
}
}
let index;
if (numbers.length === 0) {
index = "No more numbers"
} else {
index = rando();
display.push(index);
}
document.getElementById('bingo').innerHTML = index;
}
function show()
{
for(let n = 0; n < display.length; n++)
{
document.getElementById('reveal').innerHTML += "<br/>" + display[n] + "<br/>";
}
}
</script>
</div>
<div id="button">
<button onclick="getRandomNum()">Random Number</button>
</div>
<br/>
<br/>
<br/>
<div id="reveal">
<button onclick="show()">Numbers Called</button>
</div>
</body>
</html>
Here is the example with splice.
Forget everything you done .
Start creating an array using range function, set number of numbers as you like .
Than, you need to use a seed to make the pseudo-randomness better .
So, instead of rand, you gotta use SHUFFLE,
so you set array on range as 1 to 90, set the seed, than use shuffle to shuffle the array.. than you got all numbers in a random order (corresponding to the seed) .
You gotta change the seed to have another result .
The order of the numbers is the result .
as .. ball 1 : 42 ... ball 2: 10.... ball 3: 50.... ball 1 is 0 in the array. ;)
You can also use slice function and create a for / each loop, incrementing the slice factor, so you loop
slice array 0,1 the the result .. ball 1...
slice array 0.2 ball 2...
slice array 0.3
Thats the logic, i hope you understand, if so .. it ill help you a lot .
The way I did this was to shuffle an array of numbers from 1-90 and then call those numbers in sequence. They've already been shuffled, so they're already random.
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
I have a hopefully pretty easy problem. I'm trying to create a JS function on my app where there's a number in HTML and every time it is clicked, another number is subtracted from it and the result displays.
(So far this much works.)
Then the action should be repeatable so the number keeps getting smaller.
(This part doesn't work yet.)
Finally, there's a reset button that, when clicked, resets the original number to a random number.
(The random number is found correctly, but when you click to subtract it subtracts from the original number, not from the randomly-chosen replacement number.)
Here's a partially-working JSFiddle
var s = document.getElementById('incrimentOfNumber').innerHTML
var n = document.getElementById('countdownNumber').innerHTML
var n = n - s;
document.getElementById("countdownNumber").onclick = function updateNumber(){
this.innerHTML = n;
}
document.getElementById("resetCountdown").onclick = function resetCountdown(){
var n = Math.floor(Math.random() * 500) + 200;
document.getElementById("countdownNumber").innerHTML = n;
}
<h3>Count down from the number you see in incriments of <span class="incrimentOfNumber" id="incrimentOfNumber">7</span>.
<br />Tap the number to see the correct answer.
<br />Repeat as needed.
</h3>
<div class="countdownNumber">
<h1 id="countdownNumber">284</h1>
</div>
<div class="btn" id="resetCountdown">Reset</div>
Can anyone (1) double check what I've done to make sure I'm not doing things in a stupid way and (2) help me figure out how to get the repeatable action functioning?
The issue is you are calculating value of n only once, it should be calculated on every click thus change you countdown click function to:
document.getElementById("countdownNumber").onclick = function updateNumber(){
var s = document.getElementById('incrimentOfNumber').innerHTML
var n = document.getElementById('countdownNumber').innerHTML
n = n - s;
this.innerHTML = n;
}
Here is a working demo:
https://jsfiddle.net/m3q8fn2x/
If you are still struggling with this ,then consider the fact that when you declare a variable inside an event function its starting value is always the same , when the event is triggered. So consider this fact and declare variables outside the event function's scope.
const togglerBtn = document.getElementById("togglerBtn");
let temp = false;
togglerBtn.addEventListener("click", () => {
// alert();
if (!temp) {
togglerDiv.style.transform = "translateY(48px)";
return (temp = true);
} else if (temp) {
togglerDiv.style.transform = "translateY(-500px)";
return (temp = false);
}
});
Here is your working code:
You need to put the n = n - s part into the update number function so its called each time you click.
var s = document.getElementById('incrimentOfNumber').innerHTML
var n = document.getElementById('countdownNumber').innerHTML
document.getElementById("countdownNumber").onclick = function updateNumber() {
n = n - s;
this.innerHTML = n;
}
document.getElementById("resetCountdown").onclick = function resetCountdown(){
n = Math.floor(Math.random() * 500) + 200;
document.getElementById("countdownNumber").innerHTML = n;
}
<h3>Count down from the number you see in incriments of <span class="incrimentOfNumber" id="incrimentOfNumber">7</span>.
<br />Tap the number to see the correct answer.
<br />Repeat as needed.
</h3>
<div class="countdownNumber">
<h1 id="countdownNumber">284</h1>
</div>
<div class="btn" id="resetCountdown">Reset</div>
I'm trying to implement Heap's algorithm to find different permutations of a string and found a strange behaviour with a for loop, here's the code
function permAlone(str) {
var strArr = str.split(''),
permutations = [];
function swap(strArr, x, y) {
var tmp = strArr[x];
strArr[x] = strArr[y];
strArr[y] = tmp;
}
function generate(n) {
if (n === 1) {
permutations.push(strArr.join());
} else {
for (var i = 0; i != n; i++) {
generate(n - 1);
swap(n % 2 ? 0 : i, n - 1);
}
}
}
generate(strArr.length);
return permutations;
}
console.log(permAlone('aab'));
In the for loop within the generate function, if I put i = 0 the output of the script is ['a,a,b', 'a,a,b'] but if I put var i = 0 the output is ['a,a,b', 'a,a,b', 'a,a,b', 'a,a,b', 'a,a,b', 'a,a,b'].
I understand that var i would create a local variable for the loop, but don't understand in this case why it would change how the loop functions as there is no i variable declared anywhere else in the script.
Thanks any help appreciated.
The reason the behaviour changes if you have a global i variable is that you have multiple recursive calls to generate() all trying to control their own partially complete for loops with the same variable, and all setting i back to 0 when they start.
Picture what happens on the second iteration of the for loop: i is 1 because it has just been incremented, but then immediately a recursive call to generate() starts its own loop and sets i back to 0 again.
If you create a local variable with var then each for loop in each recursive call is independent of all the others.
Try stepping through the code with the debugger, or try adding the following as the first line inside the for loop and watch what happens to the variables when the code runs:
console.log('n:' + n + '; i: '+i);
Below is just a section of my code but I know it's problematic because I can't get it to return any value except 'undefined'. I have been over this for hours and cannot figure it out.
I want to be able to input a number and have its factors pushed to an array. I have tested it by alerting the first item in the array and I get nothing. I'm sure this is a pretty easy but I just can't figure it out. Here is the code:
var numberInQuestion = prompt("Of what number are you wanting to find the largest prime factor?");
//determine factors and push to array for later use
var factorsArray = [];
function factors(numberInQuestion){
for(var i = 2; i < numberInQuestion-1; i++){
if(numberInQuestion % i === 0){
return factorsArray.push[i];
} else {
continue;
}
}
};
factors(numberInQuestion);
alert(factorsArray[0]);
Thanks for any help!
you can only return one value
you must use (), not [] for calling push
factorsArray should be local to factors (put the definition inside the function)
the else { continue; } is useless
Here is the fully corrected code:
var numberInQuestion = prompt("Of what number are you wanting to find the factors of?");
//determine factors
function factors(numberInQuestion){
var factorsArray = []; // make it local
for (var i = 2; i < numberInQuestion-1; i++){
if(numberInQuestion % i === 0){
factorsArray.push(i); // use (), and don't return here
} // no need for else { continue; } because it's a loop anyway
}
return factorsArray; // return at the end
};
var result = factors(numberInQuestion); // assign the result to a variable
alert(result);
Here's a JSFiddle.
You have an error in your pushing syntax. Correct syntax for pushing is -
factorsArray.push(i);
Also returning immediately from the function after finding the first divisor will not give you the full list. You probably want to return after you've found out all the divisors.
Taking all of the above into consideration, you should rewrite your function as follow -
function factors(numberInQuestion){
for(var i = 2; i < numberInQuestion - 1; i++){
if(numberInQuestion % i === 0) {
factorsArray.push(i);
}
}
}
and you will be OK.
You've coded this so that when you find the first factor your function returns immediately. Just get rid of the return keyword in that statement. (What "return" means in JavaScript and other similar languages is to immediately exit the function and resume from where the function was called.)
Oh, also, you call functions (like .push()) with parentheses, not square brackets.
The function should not return when pushing to the array. Return the array after executing the loop. The else clause is also unnecessary.
var numberInQuestion = prompt("Of what number are you wanting to find the largest prime factor?");
function factors(numberInQuestion){
var factorsArray = [];
for(var i = 2; i < numberInQuestion-1; i++){
if(numberInQuestion % i === 0 && isPrime(i)){
factorsArray.push(i);
}
}
return factorsArray;
};
var factors = factors(numberInQuestion);
alert(factors[factors.length-1]);
//From: http://stackoverflow.com/questions/11966520/how-to-find-prime-numbers
function isPrime (n)
{
if (n < 2) return false;
var q = Math.sqrt (n);
for (var i = 2; i <= q; i++)
{
if (n % i == 0)
{
return false;
}
}
return true;
}
Given the purpose of the example two items must be considered
The code does not determine if the number is actually prime. The code will return the smallest factor possible since the loop starts at two and increments, then returns the first element in the array. The largest factor would actually be the last element in the array. I have corrected the example to find the greatest prime factor. You can test it via this fiddle: http://jsfiddle.net/whKGB/1/