I am trying to get factorial of all the numbers of array(recurArray) using recursion and without loops.
I am getting Error "Maximum call stack size exceeded"
I think there is some issue with the for loop logic, would be helpful if someone can explain the cause of error and how to fix it
Thanks.
//code
function recur(){
var n;
var result;
if(n == 1)
return 1;
var recurArray = [5,6,7,8,9];
for (var i = 0;i<recurArray.length;i++){
n = recurArray[i];
result = n * recur(n-1);
n=n-1;
}
console.log("val of n " + n + "value of i " + i);
return result;
}
recur();
Your recur() function should probably take n as an argument, otherwise n will never be 1 (if(n == 1) return 1;) and your function will keep calling itself until it crashes.
Try function recur(n){ instead.
As you have array, you should use loop.
function recur(x) {
if(x==0) {
return 1;
}
return x * recur(x-1);
}
function getFact() {
var recurArray = [5,6,7,8,9];
for (var i = 0;i<recurArray.length;i++){
console.log(recur(recurArray[i]));
}
}
getFact();
In Each occurence you reset the factorial so it keep rolling for fact(5) you need to have a function that calculate the factorial and an other one for the loop over your array like this :
function recur(n){
if(n == 1){
return 1;
} else {
return n* recur(n-1);
}
}
var recurArray = [5,6,7,8,9];
for (var i = 0;i<recurArray.length;i++){
n = recurArray[i];
result = recur(n);
console.log("factorial of n " + n + " is " + result);
}
Try something like this:
function factorial(number) {
var temp;
if(number <= 1) return 1;
temp = number * factorial(number - 1);
return temp;
}
In this case factorial(5); will return !5 . Recursive functions are not supposed to have loops inside(They can, but the execution time would be horrendous).
Also recursive functions call themselves with different parameters(otherwise you would overflow the browser stack). In your case you call recursive() an infinite amount of times and the loop always starts from 5 , infinitely. The passed parameter is what stops the recursion.
Related
I've got an infinite loop inside my while loop and I can't find the cause.
It's a simple function that returns the sum of the argument's digits. I use a while loop because it needs to add up the digits until it lands at a one digit number.
I made sure that I added a statement that would make sure that at a certain point the loop will break., But it obviously doesn't.
function digital_root(n) {
num = n;
sum = 0;
while (num.toString().length>1){
for (i=0; i<num.toString().length; i++) {
sum += parseInt(num.toString()[i])
}
num = sum;
}
return sum;
}
digital_root(456)
I get a warning that I have an infinity loop on line 4 (while loop).
I hoped that num=sumwould reassign the new integer (with reduced number of digits) to the numvariable and thus at some point break out of the loop. Is this wrong?
What further confuses me is that most of the JS editors I've used to debug the problem return an output, but it takes ages. So is it an infinite loop or is it not?
You have a nested loop structure where the first condition is always true.
For getting only a number below 10, you could call the function again as recursion.
function digital_root(n) {
var num = n.toString(), // declare and use the string value
sum = 0,
i;
for (i = 0; i < num.length; i++) {
sum += parseInt(num[i], 10)
}
return sum > 9
? digital_root(sum)
: sum;
}
console.log(digital_root(456));
After re-reading the question I noticed that you're trying to reduce an integer down to a single number. The issue with your code was that sum was set to 0, only before the while loop. Meaning that it didn't reset for the second, third, ... run.
Moving sum = 0 into the while loop resolves this issue. I've also added variable declarations at the top to avoid setting global variables.
function digital_root(n) {
var num, sum, i;
num = n;
while (num.toString().length > 1) {
sum = 0;
for (i = 0; i < num.toString().length; i++) {
sum += parseInt(num.toString()[i]);
}
num = sum;
}
return sum;
}
console.log(digital_root(456));
Here written in a recursive manner, a style that I personally more prefer:
function digital_root(integer) {
// guard against things that might result in an infinit loop, like floats
if (!Number.isInteger(integer) || integer < 0) return;
const chars = integer.toString().split("");
if (chars.length == 1) return integer;
return digital_root(
chars.map(char => parseInt(char))
.reduce((sum, digit) => sum + digit)
);
}
console.log(digital_root(456));
Since you already got the answer, here is another way to meet the result
function digital_root(n) {
// convert the number to string
// use split to create an array of number viz ['4','5','6']
// use reduce to sum the number after converting to number
// 0 is the initial value
return n.toString().split('').reduce((a, c) => a + parseInt(c, 10), 0)
}
console.log(digital_root(456))
Avoiding all the nested loops that lead to a situation such as that you're facing, I'd rather do it in a more readable way.
function digital_root(n) {
sum = n;
while(sum.toString().length > 1) {
sum = sum.toString()
.split('')
.map(digit => parseInt(digit, 10))
.reduce((acc, cur) => acc + cur);
}
return sum;
}
console.log(digital_root(456));
I'm trying to create a simple program in javascript where the Fibonacci square can be created by a random number sequence but I can't seem to connect both parts of my code. The first side being: the call for a random number and the second part: calculating the Fibonacci square.
var n = function getRandomNum() {
return Math.floor(Math.random()*100) +1;
}
function fib(x) {
if (x < 2) {
return x;
} else {
return fib(x - 1) + fib(x - 2);
}
}
console.log(fib(n));
Tell me where I'm going wrong. These are the errors I get when I run it.
RangeError: Maximum call stack size exceeded
at fib:7:13
at fib:11:12
at fib:11:12
at fib:11:12
at fib:11:12
at fib:11:12
Aside from not invoking the random number generator, you're using a very poorly optimized algorithm. If you think through all the redundant calls that need to take place, you'll see why the stack limit is reached.
var n = function getRandomNum() {
return Math.floor(Math.random() * 100) + 1;
}(); // <-- quick inline invocation... not normally how you'd use this.
console.log(n);
function fib(x) {
function _fib(x, a, b) {
if (x < 2) {
return a;
}
return _fib(x - 1, b, a + b);
}
return _fib(x, 0, 1);
}
console.log(fib(n));
Since you don't call n function, you should call it like the following.
var n = function getRandomNum() {
return Math.floor(Math.random()*100) +1;
}
function fib(x) {
if (x < 2) {
return x;
} else {
return fib(x - 1) + fib(x - 2);
}
}
console.log(fib(n));
But, there's a huge problem in your code, as #rock star mentioned, there's no any optimizing process in your code. That is why your code has caused the problem on memory leak
To avoid this, you can simply use memoization, click this link you don't have any clue on it.
Javascript Memoization Explanation?
So, your code can be improved like the folloiwng, by adapting memoization algorithm.
var n = function getRandomNum() {
return Math.floor(Math.random()*100) +1;
}
var result = [];
result[0] = 1;
result[1] = 1;
function fib(x) {
var ix, ixLen;
for(ix = 0, ixLen = x; ix < ixLen; ix++){
if(!result[ix]){
result[ix] = result[ix-2] + result[ix-1];
}
}
console.log('n:', x, ' result: ', result[ix-1]);
return result[ix-1];
}
console.log(fib(n()));
Compare the result with this site.
http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibtable.html
I have range function and output functions they works correct,now I want create sum function for using as callbac function in range function,but when some function executed local variable let us say total or sum initialize 0(zero),how can solve this problem?
function range(start,end,callback,step) {
// body...
step=step || 1;
for(i=start;i<=end;i=i+step){
callback(i);
}
}
function output(a) {
// body...
console.log(a);
}
function sum(m){
var total=0;
// some code
}
range(1,5,output);
range(1,5,sum);
function range(start,end,callback,step) {
// body...
var aggregate;
step=step || 1;
for(i=start;i<=end;i=i+step){
aggregate = callback(i, aggregate);
}
}
function output(a) {
// body...
console.log(a);
}
function sum(m, aggregate){
return m + aggregate;
}
range(1,5,output);
range(1,5,sum);
This way you could even do cool stuff like
function conc(m, aggregate) {
return aggregate + m.toString();
}
range(1,5,conc,2); //prints 135
Continuition style code, like you've started it with range(), can get really weird and cumbersome.
And please, please, mind defining your local variables. like i
function range(start,end,callback,step) {
step=step || 1;
for(var i=start; i<=end; i=i+step)
callback(i);
}
function output(...label) {
return function(...args){
console.log(...label, ...args);
}
}
function sum(callback){
var total = 0;
return function(value){
//will log ever intermediate total, because sum() has no way to tell when the sequence is over.
callback(total += +value || 0);
}
}
range(1,5,output('range:'));
range(1,5,sum(output('sum:')));
In this case, I'd prefer using a generator instead, although the higher order functions get obsolete.
function *range(start,end,step) {
step = +step || (end < start? -1: 1);
for(var value = start, count = (end - start) / step; count-- >= 0; value += step)
yield value
}
function sum(iterator){
var total = 0, v;
for(v of iterator) total += +v || 0;
return total;
}
console.log("range:", ...range(1,5))
console.log("sum of range:", sum(range(1,5)))
//just to show that this works with your regular array as well
console.log("sum of array:", sum([1,2,3,4,5]));
//and some candy, as requested by Bergi ;)
//I like to stay with the interfaces as close as possible to the native ones
//in this case Array#reduce
var fold = (iterator, callback, start = undefined) => {
var initialized = start !== undefined,
acc = start,
index = 0,
value;
for(value of iterator){
acc = initialized?
callback(acc, value, index):
(initialized=true, value);
++index;
}
if(!initialized){
throw new TypeError("fold of empty sequence with no initial value");
}
return acc;
}
//and the ability to compose utility-functions
fold.map = (callback, start = undefined) => iterator => fold(iterator, callback, start);
console.log(" ");
var add = (a,b) => a + b; //a little helper
console.log('using fold:', fold(range(1,5), add, 0));
//a composed utility-function
var sum2 = fold.map(add, 0);
console.log('sum2:', sum2( range(1,5) ));
Clearly a range function should not take a callback but be a generator function in modern JavaScript, however you were asking how to write such a callback.
You've already tagged your questions with closures, and they are indeed the way to go here. By initialising a new total within each call of the outer function, you don't need to worry about how to reset a global counter.
function makeSum() {
var total=0;
return function(m) {
total += m;
return total; // so that we can access the result
}
}
var sum = makeSum();
range(1, 5, sum);
output(sum(0));
Won't simply calling the callback on the range array suffice if the callback is not undefined? Like this:
> function range(n, callback) {
const r = [...Array(n).keys()]
if (callback) {
return callback(r)
}
return r
}
> function sum(arr) {
return arr.reduce((a, b) => a + b, 0)
}
> range(10)
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
> range(10, sum)
> 45
Why isn't this working? I'm getting a stack too deep error:
var countRecursion = function(array) {
var sum = 0
var count = 0
sum += array[count]
count ++
if (count < array.length) {
countRecursion(array);
} else {
return sum
}
}
You made a mistake and reset sum and counter inside the recursive block. I simply moved them outside.
var countRecursion = function(array) {
sum += array[count]
count ++
if (count < array.length) {
countRecursion(array);
} else {
return sum
}
}
var sum = 0
var count = 0
countRecursion([1,2,3]);
alert(sum);
This code is not recursive but iterative. I am not 100% sure if that's what you really wanted. But since you mentioned it, some people down voted my answer since I only fixed your code, but didn't made it recursive I guess. For completeness, here is recursive version of your code:
var countRecursion = function(array, ind) {
if (ind < array.length) {
return array[ind] + countRecursion(array, ind + 1);
} else {
return 0;
}
}
var sum = 0
var count = 0
sum = sum + countRecursion([1,2,3, 5, 6, 7], count);
alert(sum);
For recursion: pass data up, return data down.
The original code has a different count variable, being a local variable defined in the function, that is initial set to 0. As such the base case is never reached and the function recurses until the exception is thrown.
In addition to using a variable from an outer scope (or another side-effect) this can also be addressed by by following the recommendation on how to handle recursion, eg.
var countRecursion = function(array, index) {
index = index || 0; // Default to 0 when not specified
if (index >= array.length) {
// Base case
return 0;
}
// Recurrence case - add the result to the sum of the current item.
// The recursive function is supplied the next index so it will eventually terminate.
return array[index] + countRecursion(array, index + 1);
}
I see what you're thinking.
The issue with your code is that everytime you call countRecursion, count goes back to 0 (since it's initialized to 0 within your function body). This is making countRecursion execute infinitely many times, as you're always coming back to count = 0 and checking the first term. You can solve this by either:
Initializing count outside the function body, that way when you do count++, it increases and doesn't get reset to 0.
Passing count along with array as a parameter. That way, the first time you call the function, you say countRecursion(array, 0) to initialize count for you.
Note that you have to do the same for sum, else that will also revert to zero always.
Finally, (and this doesn't have to do with the stack error) you have to actually call return countRecursion(array) to actually move up the stack (at least that's how it is in C++ and what not - pretty sure it applies to javascript too though).
Array sum using recursive method
var countRecursion = function(arr, current_index) {
if(arr.length === current_index) return 0;
current_index = current_index || 0;
return countRecursion(arr, current_index+1) + arr[current_index];
}
document.body.innerHTML = countRecursion([1,2,3,4,5, 6])
i'm in the process of trying to write a function that converts an amount into a specified number of coins. For this I'm calling a function on itself (I think this is recursive programming?). I'm having 2 problems.
When i call the function on itself in the else section of the if statement I get the error message. "Maximum call stack size exceeded" ? Not sure why this is as the call above is the same and works fine when this second call is commented out.
Also when the second call is commented out and the function runs the variable total should be increasing by 1 with each call. However it doesn't make it past 1. I thought this may be because the variable was being reset at the top to 0 with each call. However the remainder variable is also set to 0 decreases its value each time.
Can anyone explain what is happening here ? How is this problem best solved ?
Thanks
function amountCoins(amt, coins) {
var remainder = 0;
total = 0;
if(amt >= coins[0]) {
total += 1;
remainder = (amt - coins[0]);
return amountCoins(remainder, coins);
} else {
coins.shift();
//return amountCoins(remainder,coins);
}
alert(total);
}
amountCoins(121,[20,15,6,1]);
You can use .reduce() for this as an alternative.
And we don't really need loops where simple math can handle it.
var total = [20,15,6,1].reduce(function(obj, denomination) {
return {
total: obj.total + Math.floor(obj.amount / denomination),
amount: obj.amount % denomination
};
}, {amount:121, total:0}).total;
Or iterate the array.
var arr = [20,15,6,1], amount = 121, total = 0;
for (var i = 0; i < arr.length; ++i) {
total += Math.floor(amount / arr[i]);
amount %= arr[i];
}
I'd use a regular for loop instead, if I was you:
var amt = 121;
var coins = [20, 15, 6, 1];
var coinsUsed = {};
var totalCoins = 0;
for (var i = 0; i < coins.length; i++) {
if (coins[i] <= amt) {
coinsUsed[coins[i]] = Math.floor(amt / coins[i]);
amt -= coinsUsed[coins[i]] * coins[i];
totalCoins += coinsUsed[coins[i]];
} else {
coinsUsed[coins[i]] = 0;
}
}
console.log(coinsUsed, totalCoins);
Output:
Object {
1: 1,
6: 0,
15: 0,
20: 6
}
7
The problem is that your algorithm never ends. Every recursive function must have an end, if not it will produce a stack overflow (xD), because recursive calls are stored in a stack.
This would be a solution:
function amountCoins(amt, coins, total) {
var remainder = 0;
total = total || 0; //Default value 0 (for the first call)
if(coins.length == 0) return total; //This is the ending condition (no coins)
if(amt >= coins[0]) {
total += 1;
remainder = (amt - coins[0]);
return amountCoins(remainder, coins, total);
} else {
coins.shift();
return amountCoins(remainder, coins, total);
}
}
var coins = amountCoins(121,[20,15,6,1]); //Returns: 6
alert(coins);
As you can see, I turned total into a param so we can store it from call to call.
Hope this helps. Cheers
i think this is what you are trying to do:
function amountCoins(amt, coins) {
var remainder = 0;
if(coins.length == 0) {
return 0;
} else if(amt >= coins[0]) {
remainder = (amt - coins[0]);
return amountCoins(remainder, coins)+1;
} else {
coins.shift();
return amountCoins(remainder,coins);
}
}
var total = amountCoins(121,[20,15,6,1]);
alert(total)
There are a few things here
A recursive algorithm needs a terminating condition. ie. when the function is calling itself recursively it should stop the chain at some point. If it doesnt, the program will run out of memory to accomodate all the calls in the chain. Because this is a potentially dangerous condition, programming languages like javascript limit the depth of a recursive call. This is what is meant by the Maximum call stack size exceeded error.
In your program, logically, the terminating condition is when we run out of coins. so a
coins.length == 0 check that returns a 0 total (which in turn seeds the upward chain) will fix the problem
Usually in recursive algorithms the result is passed backwards, up the call chain and not stored in an external variable. So the incrementing total value is expressed with a return statement like return amountCoins(remainder, coins)+1;
Finally, this problem can be much easily implemented with for loops. Try to think by unwinding the recursive call chains and you'll figure out a loop solution.
You must return total not only if no coins left, but also if the last coin's value is bigger then the remaining value:
function amountCoins(amt, coins, total) {
total = total || 0;
if (coins.length == 0 || (amt < coins[0] && coins.length == 1)) return total;
if (amt >= coins[0]) {
total += 1;
remainder = (amt - coins[0]);
return amountCoins(amt - coins[0], coins, total);
} else {
coins.shift();
return amountCoins(remainder, coins, total);
}
}
This correction to your original code will work:
function amountCoins(amt, coins, total) {
total = total || 0;
if (amt === 0) return total;
// throw out all the coins that are too big
while (amt < coins[0]) coins.shift();
// use the largest coin possible, then recurse
total += 1;
remainder = amt - coins[0];
return amountCoins(remainder, coins, total);
}
alert(amountCoins(121,[20,15,6,1])); // alerts 7
It has the advantage of avoiding unnecessary if ... else statements, and the logic is bit clearer imo