1

I am trying this simple code to calculate factorial of 5. But I am getting "undefined" as the result. I am aware of other methods but what is wrong with this?

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title> Learning </title>
<head>
<body>
<h2> Welcome<h2>
<p id="demo"></p>
<script>
var fact=5;
function calfact(num)
{
 if(num!=1)
  {
   fact=fact*(num-1);
   num=num-1;
   calfact(num);
  }
 else
  {
   return fact;
  }
}

document.getElementById("demo").innerHTML=calfact(5);
</script>
</body>
</html>         
Shivam Mishra
  • 1,731
  • 2
  • 11
  • 29

3 Answers3

2

If you want a result from a recursive function, all code paths through the function must return something. Your code isn't returning anything in the num!=1 case. It should be returning the result of calling itself, e.g. (see the *** line):

var fact=5;
function calfact(num)
{
 if(num!=1)
  {
   fact=fact*(num-1);
   num=num-1;
   return calfact(num); // ***
  }
 else
  {
   return fact;
  }
}

Your function is using a global variable, which isn't a great idea as it means the funtion isn't self-contained; and isn't a true factorial function, because you're effectively using two inputs (fact — the global  and num, the argument)

If you want a true factorial, you don't need a global variable, just work from the argument itself:

function factorial(num) {
    if (num < 0) {
        throw new Error("num must not be negative");
    }
    if (num <= 1) {
        // Both 1! and 0! are defined as 1
        return 1;
    }
    return num * factorial(num - 1);
}
console.log(factorial(5)); // 120

Or of course, more compactly:

function factorial(num) {
    if (num < 0) {
        throw new Error("num must not be negative");
    }
    return num <= 1 ? 1 : num * factorial(num - 1);
}

(More about 0!: https://en.wikipedia.org/wiki/Factorial)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • By "code paths", you mean all blocks? Thanks, btw! It solved the thing. – Shivam Mishra Apr 15 '17 at 13:47
  • @ShivamMishra: A "code path" is a way execution could move through a function (like following a walking path). So for instance, when `num` is `1`, we walk one path through the function (the one using the `else` block in your original function). When `num` is not 1, we walk a different path through the function. – T.J. Crowder Apr 15 '17 at 13:49
  • Got it.I expected the code to follow my intuition. Also, thanks for mentioning not to use the global variable. – Shivam Mishra Apr 15 '17 at 14:02
1
var fact=5;
function calfact(num){
   if(num!=1){
      fact=fact*(num-1);
      num=num-1;
      return calfact(num);//the missing thing
   }else{
      return fact;//why fact? i think it should be 1
   }
 }

By the way, your approach is maybe working, but really bad style.May do this:

function calfact(num){
  if(num!=1){
    return calfact(num-1)*num;
  }else{
    return 1;
 }
}

Or short:

calfact=num=>num==1?1:calfact(num-1)*num;
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
0

You can use Tail Recursion, which is more efficient in case of memory.

const factorial = (n, acc = 1) => n == 0 || n == 1 ? acc : factorial(n - 1, acc * n);

console.log(factorial(10))
  • Or it might be if the the engines actually implemented it. Right now it's [only Safari](https://kangax.github.io/compat-table/es6/#test-proper_tail_calls_(tail_call_optimisation)) that has done so. – Scott Sauyet Oct 25 '22 at 12:59