简体   繁体   中英

JavaScript factorial prevent infinity

I have been using this function for calculating factorial numbers in JavaScript:

var f = [];
function factorial (n) {
  if (n == 0 || n == 1)
    return 1;
  if (f[n] > 0)
    return f[n];
  return f[n] = factorial(n-1) * n;
}

All seemed to be going well until I tried the number 500 . It returned infinity .

Is there a way that I can prevent infinity as an answer?

Thank you.

You indeed need to use bignumbers. With math.js you can do:

// configure math.js to work with enough precision to do our calculation
math.config({precision: 2000});

// evaluate the factorial using a bignumber value
var value = math.bignumber(500);
var result = math.factorial(value);

// output the results
console.log(math.format(result, {notation: 'fixed'}));

This will output:

500! is, for lack of a better term, "[bleep]ing huge".

It is far, far beyond what can be stored in a double-precision float, which is what JavaScript uses for numbers.

There's no way to prevent this, other than use numbers that are reasonable :p

EDIT: To show you just how huge it is, here's the answer:

500! =

That right there is a 1,135-digit number. For comparison, double-precision floats can handle about 15 digits of precision.

You could consider using an arbitrary precision numeric library. This is a question of its own, though. Here's one related question: https://stackoverflow.com/questions/744099/is-there-a-good-javascript-bigdecimal-library .

I dont know if anyone has solved this elsewise... I'm a novice beginner in coding and dont know all the aspects. But after I faced this factorial problem myself, i came here when searching for the answer. I solved the 'infinity' display problem in another way. I dont know if its very efficient or not. But it does show the results of even verry high intergers.

Sorry for any redundancy or untidiness in the code.

<!DOCTYPE html>

<html>
    <head>
        <title>Factorial</title>
        <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'></script>
    </head>

    <body>
        <input type='text' id='number' />
        <input type='button' value='!Factorial!' id='btn' />

        <script>
        var reslt=1;
        var counter=0;  
        var mantissa=0; //stores the seperated matissa 
        var exponent=0; //stores the seperated exponent

            $(document).ready(function (){
                $('#btn').click(function (){
                    var num=parseFloat($('#number').val()); //number input by user

                    for(i=1;i<=num;i++){
                        reslt=reslt*i;
                        //when the result becomes so high that the exponent reaches 306, the number is divided by 1e300
                        if((parseFloat(reslt.toExponential().toString().split("e")[1]))>=300){
                            reslt=reslt/1e300; //the result becomes small again to be able to be iterated without becoming infinity
                            counter+=1; //the number of times that the number is divided in such manner is recorded by counter
                        }
                    }

                    //the mantissa of the final result is seperated first
                    mantissa=parseFloat(reslt.toExponential().toString().split("e")[0]);
                    //the exponent of the final result is obtained by adding the remaining exponent with the previously dropped exponents (1e300)
                    exponent=parseFloat(reslt.toExponential().toString().split("e")[1])+300*counter;

                    alert(mantissa+"e+"+exponent); //displays the result as a string by concatenating

                    //resets the variables and fields for the next input if any
                    $('#number').val('');
                    reslt=1;
                    mantissa=0;
                    exponent=0;
                    counter=0;
                });
            });
        </script>
    </body>
</html>

Javascript numbers can only get so big before they just become "Infinity". If you want to support bigger numbers, you'll have to use BigInt .

Examples:

 // Without BigInt console.log(100 ** 1000) // Infinity // With BigInt // (stackOverflow doesn't seem to print the result, // unless I turn it into a string first) console.log(String(100n ** 1000n)) // A really big number

So, for your specific bit of code, all you need to do is turn your numeric literals into BigInt literals, like this:

 var f = []; function factorial (n) { if (n == 0n || n == 1n) return 1n; if (f[n] > 0n) return f[n]; return f[n] = factorial(n-1n) * n; } console.log(String(factorial(500n)));

You'll find that you computer can run that piece of code in a snap.

Some improves in your code

function factorial (n) {
  if (n === 0 || n === 1)
    return 1;

  return factorial(n-1) * n;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM