'Most efficient way to write Combination and Permutation calculator in Javascript

I have a math website http://finitehelp.com that teaches students Finite Math. I thought it would be cool to include a calculator so I made one for combinations and permutations in Javascript. Live calculator is at http://finitehelp.com/finite-calculator.html. I know next to nothing about Javascript and would venture to guess there is a much more efficient way to write the following particularly because of the excessive use of variables. If someone could please help me I would be very grateful.

<script type="text/javascript">
// calculate n!
Math.factorial = function(n)
{
    if(typeof n == 'string') n = Number(n);
    if(typeof n != 'number' || isNaN(n))
    {
        alert("Factorial requires a numeric argument.");
        return null;
    }
    if (n < 2) return 1;
    return (n * Math.factorial(n-1));
}
Math.divide = function(a,b)
{
    return a/b;
}
</script>

<form class="form" name="combination" action="">
    <p>C(<input type="text" value="n" name="T1" size="1">,<input type="text" value="r" name="T2" size="1">)
    <input type="button" value="Calculate"
     onclick="var n = T1.value; var r = T2.value; var n_minus_r = parseFloat(n) - parseFloat(r); var numerator = Math.factorial(T1.value); var n_minus_r_fact = Math.factorial(n_minus_r); var r_fact = Math.factorial(r); var denominator = n_minus_r_fact * r_fact; T3.value = Math.divide(numerator,denominator); return true;">
    = <input type="text" name="T3" size="12" readonly></p>
</form>


Solution 1:[1]

If you're concerned about efficiency, you'd probably want to re-implement the factorial as an iterative function rather than a recursive one. The recursive version will use a lot more memory and CPU time than the iterative version.

function factorial(n) { 
  var x=1; 
  var f=1;
  while (x<=n) {
    f*=x; x++;
  }
    return f;
}

You also shouldn't be adding your own functions to the Math namespace. It's not a good habit to get into.

Solution 2:[2]

As we know, combinations is short for(https://en.wikipedia.org/wiki/Combination):

enter image description here

So the fastest combinations implement is below(only if n is small):

// r*(r-1)*...*2*1
function factorial(r) {
  let s = 1;
  while (r > 1) s *= r--;
  return s;
}

function combinations(n,r){
    let s = 1;
    let i = r;
    // n*(n-1)*....*(n-r+1)
    while(i<n) s*=++i;
    return s/factorial(n-r)
}
console.log(combinations(100,2) === 4950) // false

Note: math float operation has Precision limit, for example combinations(100,2)==4950 is false. But https://www.wolframalpha.com/input?i=100+choose+2 tells us it's true result is 4950.

So we should use BigInt to replace float operation:

// r*(r-1)*...*2*1
function factorial(r) {
    let s = BigInt(1);
    var i = BigInt(r)
    while (i > 1) s *= i--;
    return s;
}

// n*(n-1)*....*(n-r+1) / factorial(r)
function combinations(n, r){
    let s = BigInt(1);
    let i = BigInt(r);
    while(i<n) s*=++i;
    return s/factorial(n-r)
}
console.log(combinations(100,2) === 4950n) // true

Solution 3:[3]

Math.factorial= function(n){
    var i= n;
    while(--i) n*= i;
    return n;
}

Math.combinations= function(n, r, repeats){
    if(n< r) return 0;
    if(n=== r) return 1;
    if(repeats){
        return Math.factorial(n+r-1)/((Math.factorial(r)*Math.factorial(n-1)));
    }
    return Math.factorial(n)/((Math.factorial(r)*Math.factorial(n-r)));
}


var a= [
    'aqua', 'black', 'blue', 'fuchsia', 'gray', 'green', 'lime', 'maroon',
    'navy', 'olive', 'orange', 'purple', 'red', 'silver', 'teal', 'white',
    'yellow'
]
//how many 3 color combinations are there?
//[red,green,blue] is different than [green,red,blue]
// Math.combinations(a.length,3,true) >>969
// how many unique combinations (ignoring order) are there?
// Math.combinations(a.length,3)>>680

Solution 4:[4]

I would prefer recursive function, tail recursive may cause stackoverflow for functions like fibonacci.

Math._factorial = function(n){
  return Math._fact(n,1);
}

Math._fact= function(n,res){
  n = Number(n);
  if (n == null) {
    alert("Factorial requires a numeric argument.");
    return null;
  } else if (n < 2){
    return res;
  } else {
    return Math._fact(n-1, res*n);
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mark Bessey
Solution 2
Solution 3 kennebec
Solution 4 ymutlu