6

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.

Progo
  • 3,452
  • 5
  • 27
  • 44
  • It's because have you a huge number. – Miguel Q. Jan 14 '14 at 23:39
  • Test here http://www.numberempire.com/factorialcalculator.php – Miguel Q. Jan 14 '14 at 23:40
  • Check for infinity and return 9007199254740992 instead `if (facorial(500) == Number.POSITIVE_INFINITY) return 9007199254740992` – adeneo Jan 14 '14 at 23:41
  • The MAX_VALUE property has a value of approximately 1.79E+308. Values larger than MAX_VALUE are represented as "Infinity". http://stackoverflow.com/questions/5660258/is-there-any-limitation-for-integer-in-javascript – Marko Jan 14 '14 at 23:42
  • http://jsfiddle.net/34PxK/ – adeneo Jan 14 '14 at 23:45
  • 3
    @adeneo: How is returning "`MAX_INT`" making anything better? `throw new Error("reached maximum integer precision with 'factorial("+n+")'")` seems much more helpful here. – Bergi Jan 14 '14 at 23:58
  • It prevents Infinity as an answer and return the highest number in javascript instead. Throwing an error is another option, depends on what it's used for I suppose, if an integer is always expected, throwing an error doesn't seem like the best idea. – adeneo Jan 15 '14 at 00:01
  • @MiguelQ. Could you tell me how the factorial calculator works? – Progo Jan 15 '14 at 00:04
  • @Progo I think factorial calculator calculates respective number in server side. – Miguel Q. Jan 15 '14 at 00:08
  • 500! is a stupendously large value that is more than the number of nanoseconds since the begining of the universe. INFINITY seems a sensible approximation to me. – RobG Jan 15 '14 at 00:11
  • This implementation of factorial is hopelessly naive. You should be using lngamma instead and memoizing. What do you plan to do with 500! would be my question. – duffymo Jun 17 '21 at 00:15

6 Answers6

7

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:

1220136825991110068701238785423046926253574342803192842192413588385845373153881997605496447502203281863013616477148203584163378722078177200480785205159329285477907571939330603772960859086270429174547882424912726344305670173270769461062802310452644218878789465754777149863494367781037644274033827365397471386477878495438489595537537990423241061271326984327745715546309977202781014561081188373709531016356324432987029563896628911658974769572087926928871281780070265174507768410719624390394322536422605234945850129918571501248706961568141625359056693423813008856249246891564126775654481886506593847951775360894005745238940335798476363944905313062323749066445048824665075946735862074637925184200459369692981022263971952597190945217823331756934581508552332820762820023402626907898342451712006207714640979456116127629145951237229913340169552363850942885592018727433795173014586357570828355780158735432768888680120399882384702151467605445407663535984174430480128938313896881639487469658817504506926365338175055478128640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Jos de Jong
  • 6,602
  • 3
  • 38
  • 58
  • +1 for taking the time to put an example together. Note, however, that that library might not be production-ready. – Sam Jan 15 '14 at 21:47
  • The libraries API isn't yet stabilized (hence the library hasn't reached v1.0), but the library is well tested and used for example by http://www.numerics.info which has a user base of 400.000 users. – Jos de Jong Jan 16 '14 at 12:07
2

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! = 1220136825991110068701238785423046926253574342803192842192413588385845373153881997605496447502203281863013616477148203584163378722078177200480785205159329285477907571939330603772960859086270429174547882424912726344305670173270769461062802310452644218878789465754777149863494367781037644274033827365397471386477878495438489595537537990423241061271326984327745715546309977202781014561081188373709531016356324432987029563896628911658974769572087926928871281780070265174507768410719624390394322536422605234945850129918571501248706961568141625359056693423813008856249246891564126775654481886506593847951775360894005745238940335798476363944905313062323749066445048824665075946735862074637925184200459369692981022263971952597190945217823331756934581508552332820762820023402626907898342451712006207714640979456116127629145951237229913340169552363850942885592018727433795173014586357570828355780158735432768888680120399882384702151467605445407663535984174430480128938313896881639487469658817504506926365338175055478128640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

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

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
1

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.

Community
  • 1
  • 1
Sam
  • 40,644
  • 36
  • 176
  • 219
1

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>
n0ahz
  • 107
  • 9
  • Hey dude, thanks for posting your answer. I got pretty sick and tired of dealing with bug number libraries and browsers crashing, so I switched to Python. Python is great for calculating and computing because when working with integers, it won't give overflow errors or even go into scientific notation. Python is also pretty fast and memory efficient. Just recently I was trying to calculate the factorial of some large number, I forget exactly, but python worked its way though and calculated the several million digit long factorial. Thanks again for posting your answer. +1. – Progo Jun 08 '14 at 12:42
  • Welcome....i myself am learning python atm as server side coding....python really is cool...this factorial problm was just bugging me on javascript....this is just a workaround...even python becomes idle (:P) when inspecting the factorial of ultra high numbers...but this code dont crash the browser and takes minimal time to display the result... – n0ahz Jun 10 '14 at 14:38
  • What I would do, if you even run into this problem again, is have a server side factorial program writhed in Python, Java, C, C+, C++, or C# and use Ajax to communicate between the client and the server. – Progo Jun 11 '14 at 01:39
0

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.

zoldxk
  • 2,632
  • 1
  • 7
  • 29
0

Hi this is due to the nature of java script as it can't represents number above 253-1 reference so to solve this either wrap the number with BigInt(n) or add to the number >> 3n

const factorial = (n) => {
n = BigInt(n)
if ( n < 1 ) return 1n
return factorial(n - 1n) * n 
}
Amer21
  • 21
  • 2