JavaScript 中最快的阶乘函数是什么?

发布于 2024-09-27 18:21:33 字数 1436 浏览 0 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

您的好友蓝忘机已上羡 2024-10-04 18:21:33

您可以搜索 (1...100)!在 Wolfram|Alpha 上预先计算阶乘序列。

前 100 个数字是:

1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000, 51090942171709440000, 1124000727777607680000, 25852016738884976640000, 620448401733239439360000, 15511210043330985984000000, 403291461126605635584000000, 10888869450418352160768000000, 304888344611713860501504000000, 8841761993739701954543616000000, 265252859812191058636308480000000, 8222838654177922817725562880000000, 263130836933693530167218012160000000, 8683317618811886495518194401280000000, 295232799039604140847618609643520000000, 10333147966386144929666651337523200000000, 371993326789901217467999448150835200000000, 13763753091226345046315979581580902400000000, 523022617466601111760007224100074291200000000, 20397882081197443358640281739902897356800000000, 815915283247897734345611269596115894272000000000, 33452526613163807108170062053440751665152000000000, 1405006117752879898543142606244511569936384000000000, 60415263063373835637355132068513997507264512000000000, 2658271574788448768043625811014615890319638528000000000, 119622220865480194561963161495657715064383733760000000000, 5502622159812088949850305428800254892961651752960000000000, 258623241511168180642964355153611979969197632389120000000000, 12413915592536072670862289047373375038521486354677760000000000, 608281864034267560872252163321295376887552831379210240000000000, 30414093201713378043612608166064768844377641568960512000000000000, 1551118753287382280224243016469303211063259720016986112000000000000, 80658175170943878571660636856403766975289505440883277824000000000000, 4274883284060025564298013753389399649690343788366813724672000000000000, 230843697339241380472092742683027581083278564571807941132288000000000000, 12696403353658275925965100847566516959580321051449436762275840000000000000, 710998587804863451854045647463724949736497978881168458687447040000000000000, 40526919504877216755680601905432322134980384796226602145184481280000000000000, 2350561331282878571829474910515074683828862318181142924420699914240000000000000, 138683118545689835737939019720389406345902876772687432540821294940160000000000000, 8320987112741390144276341183223364380754172606361245952449277696409600000000000000, 507580213877224798800856812176625227226004528988036003099405939480985600000000000000, 31469973260387937525653122354950764088012280797258232192163168247821107200000000000000, 1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000, 126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000, 8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000, 544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000, 36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000, 2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000, 171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000, 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000, 850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000, 61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000, 4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000, 330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000, 24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000, 1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000, 145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000, 11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000, 894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000, 71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000, 5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000, 475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000, 39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000, 3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000, 281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000, 24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000, 2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000, 185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000, 16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000, 1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000, 135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000, 12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000, 1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000, 108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000, 10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000, 991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000, 96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000, 9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000, 933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

如果您仍想自己计算这些值,可以使用 memoization

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;
}

编辑:21.08.2014

解决方案 2

我认为添加一个使用 big 的 lazy 迭代 阶乘函数 的工作示例会很有用数字得到准确结果与记忆缓存作为比较

var f = [new BigNumber("1"), new BigNumber("1")];
var i = 2;
function factorial(n)
{
  if (typeof f[n] != 'undefined')
    return f[n];
  var result = f[i-1];
  for (; i <= n; i++)
      f[i] = result = result.multiply(i.toString());
  return result;
}
var cache = 100;
// Due to memoization, following line will cache first 100 elements.
factorial(cache);

我假设你会使用某种闭包来限制变量名称可见性。

参考BigNumber
沙箱JsFiddle

You can search for (1...100)! on Wolfram|Alpha to pre-calculate the factorial sequence.

The first 100 numbers are:

1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000, 51090942171709440000, 1124000727777607680000, 25852016738884976640000, 620448401733239439360000, 15511210043330985984000000, 403291461126605635584000000, 10888869450418352160768000000, 304888344611713860501504000000, 8841761993739701954543616000000, 265252859812191058636308480000000, 8222838654177922817725562880000000, 263130836933693530167218012160000000, 8683317618811886495518194401280000000, 295232799039604140847618609643520000000, 10333147966386144929666651337523200000000, 371993326789901217467999448150835200000000, 13763753091226345046315979581580902400000000, 523022617466601111760007224100074291200000000, 20397882081197443358640281739902897356800000000, 815915283247897734345611269596115894272000000000, 33452526613163807108170062053440751665152000000000, 1405006117752879898543142606244511569936384000000000, 60415263063373835637355132068513997507264512000000000, 2658271574788448768043625811014615890319638528000000000, 119622220865480194561963161495657715064383733760000000000, 5502622159812088949850305428800254892961651752960000000000, 258623241511168180642964355153611979969197632389120000000000, 12413915592536072670862289047373375038521486354677760000000000, 608281864034267560872252163321295376887552831379210240000000000, 30414093201713378043612608166064768844377641568960512000000000000, 1551118753287382280224243016469303211063259720016986112000000000000, 80658175170943878571660636856403766975289505440883277824000000000000, 4274883284060025564298013753389399649690343788366813724672000000000000, 230843697339241380472092742683027581083278564571807941132288000000000000, 12696403353658275925965100847566516959580321051449436762275840000000000000, 710998587804863451854045647463724949736497978881168458687447040000000000000, 40526919504877216755680601905432322134980384796226602145184481280000000000000, 2350561331282878571829474910515074683828862318181142924420699914240000000000000, 138683118545689835737939019720389406345902876772687432540821294940160000000000000, 8320987112741390144276341183223364380754172606361245952449277696409600000000000000, 507580213877224798800856812176625227226004528988036003099405939480985600000000000000, 31469973260387937525653122354950764088012280797258232192163168247821107200000000000000, 1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000, 126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000, 8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000, 544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000, 36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000, 2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000, 171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000, 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000, 850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000, 61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000, 4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000, 330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000, 24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000, 1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000, 145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000, 11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000, 894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000, 71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000, 5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000, 475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000, 39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000, 3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000, 281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000, 24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000, 2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000, 185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000, 16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000, 1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000, 135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000, 12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000, 1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000, 108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000, 10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000, 991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000, 96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000, 9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000, 933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

If you still want to calculate the values yourself, you can use memoization:

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;
}

Edit: 21.08.2014

Solution 2

I thought it would be useful to add a working example of lazy iterative factorial function that uses big numbers to get exact result with memoization and cache as comparison

var f = [new BigNumber("1"), new BigNumber("1")];
var i = 2;
function factorial(n)
{
  if (typeof f[n] != 'undefined')
    return f[n];
  var result = f[i-1];
  for (; i <= n; i++)
      f[i] = result = result.multiply(i.toString());
  return result;
}
var cache = 100;
// Due to memoization, following line will cache first 100 elements.
factorial(cache);

I assume you would use some kind of closure to limit variable name visibility.

Ref: BigNumber
Sandbox: JsFiddle

七颜 2024-10-04 18:21:33

你应该使用循环。

以下是通过计算 100 的阶乘 10.000 次进行基准测试的两个版本。

递归

function rFact(num)
{
    if (num === 0)
      { return 1; }
    else
      { return num * rFact( num - 1 ); }
}

迭代

function sFact(num)
{
    var rval=1;
    for (var i = 2; i <= num; i++)
        rval = rval * i;
    return rval;
}

直播地址:http://jsfiddle.net/xMpTv /

我的结果显示:
- 递归 ~ 150 毫秒
- 迭代 ~ 5 毫秒..

You should use a loop.

Here are two versions benchmarked by calculating the factorial of 100 for 10.000 times.

Recursive

function rFact(num)
{
    if (num === 0)
      { return 1; }
    else
      { return num * rFact( num - 1 ); }
}

Iterative

function sFact(num)
{
    var rval=1;
    for (var i = 2; i <= num; i++)
        rval = rval * i;
    return rval;
}

Live at : http://jsfiddle.net/xMpTv/

My results show:
- Recursive ~ 150 milliseconds
- Iterative ~ 5 milliseconds..

丑丑阿 2024-10-04 18:21:33

我仍然认为马格斯的答案是最好的。但是,如果您还想计算 0 到 1 范围内的数字的阶乘(即伽玛函数),则不能使用该方法,因为查找表必须包含无限值。

但是,您可以近似阶乘的值,而且速度相当快,至少比递归调用自身或循环它要快(尤其是当值开始变大时)。

Lanczos 的一个很好的近似方法是

JavaScript 中的一个实现(从我几个月前编写的计算器移植而来):

function factorial(op) {
 // Lanczos Approximation of the Gamma Function
 // As described in Numerical Recipes in C (2nd ed. Cambridge University Press, 1992)
 var z = op + 1;
 var p = [1.000000000190015, 76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 1.208650973866179E-3, -5.395239384953E-6];

 var d1 = Math.sqrt(2 * Math.PI) / z;
 var d2 = p[0];

 for (var i = 1; i <= 6; ++i)
  d2 += p[i] / (z + i);

 var d3 = Math.pow((z + 5.5), (z + 0.5));
 var d4 = Math.exp(-(z + 5.5));

 d = d1 * d2 * d3 * d4;

 return d;
}

您现在可以做一些很酷的事情,例如 factorial(0.41) 等,但是准确性可能会有点关闭,毕竟这是结果的近似值。

I still think Margus's answer is the best one. However if you want to calculate the factorials of numbers within the range 0 to 1 (ie the gamma function) as well, then you cannot use that approach because the lookup table will have to contain infinite values.

However, you can approximate the values of the factorials, and it's pretty fast, faster than recursively calling itself or looping it at least (especially when values start to get bigger).

A good approximation method is Lanczos's one

Here is an implementation in JavaScript (ported from a calculator I wrote months ago):

function factorial(op) {
 // Lanczos Approximation of the Gamma Function
 // As described in Numerical Recipes in C (2nd ed. Cambridge University Press, 1992)
 var z = op + 1;
 var p = [1.000000000190015, 76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 1.208650973866179E-3, -5.395239384953E-6];

 var d1 = Math.sqrt(2 * Math.PI) / z;
 var d2 = p[0];

 for (var i = 1; i <= 6; ++i)
  d2 += p[i] / (z + i);

 var d3 = Math.pow((z + 5.5), (z + 0.5));
 var d4 = Math.exp(-(z + 5.5));

 d = d1 * d2 * d3 * d4;

 return d;
}

You can now do cool stuff like factorial(0.41), etc however accuracy might be a little off, after all, it is an approximation of the result.

梦里的微风 2024-10-04 18:21:33

这是我的解决方案:

function fac(n){
    return(n<2)?1:fac(n-1)*n;
}

这是我发现的最简单的方法(更少的字符/行),只有一个具有一行代码行的函数。


编辑:
如果您确实想保存一些字符,可以使用 箭头函数 (21字节)

f=n=>(n<2)?1:f(n-1)*n

Here is my solution:

function fac(n){
    return(n<2)?1:fac(n-1)*n;
}

It's the simplest way (less characters / lines) I've found, only a function with one code line.


Edit:
If you really want to save some chars you can go with an Arrow Function (21 bytes):

f=n=>(n<2)?1:f(n-1)*n
呆萌少年 2024-10-04 18:21:33

只需一行 ES6

const factorial = n => !(n > 1) ? 1 : factorial(n - 1) * n;

const factorial = n => !(n > 1) ? 1 : factorial(n - 1) * n;


function print(value) {
  document.querySelector('.result').innerHTML = value;
}
.result {
  margin-left: 10px;
}
<input onkeyup="print(factorial(this.value))" type="number"/>

<span class="result">......</span>

Just One line with ES6

const factorial = n => !(n > 1) ? 1 : factorial(n - 1) * n;

const factorial = n => !(n > 1) ? 1 : factorial(n - 1) * n;


function print(value) {
  document.querySelector('.result').innerHTML = value;
}
.result {
  margin-left: 10px;
}
<input onkeyup="print(factorial(this.value))" type="number"/>

<span class="result">......</span>

温馨耳语 2024-10-04 18:21:33

如果您使用自然数,查找表是显而易见的方法。
要实时计算任何阶乘,您可以使用缓存来加速计算,保存您之前计算过的数字。例如:

factorial = (function() {
    var cache = {},
        fn = function(n) {
            if (n === 0) {
                return 1;
            } else if (cache[n]) {
                return cache[n];
            }
            return cache[n] = n * fn(n -1);
        };
    return fn;
})();

您可以预先计算一些值以加快速度。

Lookup table is the obvious way to go, if you're working with natural numbers.
To calculate any factorial in real-time, you can speed it with a cache, saving the numbers you've calculated before. Something like:

factorial = (function() {
    var cache = {},
        fn = function(n) {
            if (n === 0) {
                return 1;
            } else if (cache[n]) {
                return cache[n];
            }
            return cache[n] = n * fn(n -1);
        };
    return fn;
})();

You can precalculate some values in order to speed it even more.

塔塔猫 2024-10-04 18:21:33

简短而简单的递归函数(您也可以使用循环来完成,但我认为这不会对性能产生任何影响):

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

对于非常大的 n,您可以使用 斯特林近似 - 但这只会给你一个近似值。

编辑:对为什么我对此投反对票的评论会很好......

编辑2:这将是使用循环的解决方案(这将是更好的选择):

function factorial (n){
  j = 1;
  for(i=1;i<=n;i++){
    j = j*i;
  }
  return j;
}

我认为最好的解决方案是使用缓存的值,正如 Margus 提到的那样,并使用 对于较大的值,采用斯特林近似(假设您必须非常快,并且不必在如此大的数字上那么精确)。

short and easy recursive function (you could do it with a loop, too, but I don't think that would make any difference in performance):

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

for a very large n, you could use the stirlings approximation - but that will only give you an approximate value.

EDIT: a comment on why I'm getting a downvote for this would have been nice...

EDIT2: this would be the soulution using a loop (which would be the better choice):

function factorial (n){
  j = 1;
  for(i=1;i<=n;i++){
    j = j*i;
  }
  return j;
}

I think the best solution would be to use the cached values, as Margus mentioned and use the stirlings approximation for larger values (assumed you have to be realy fast and don't have to be that exact on such big numbers).

凝望流年 2024-10-04 18:21:33

最快的阶乘函数

我认为这个基于循环的版本可能是最快的阶乘函数。

function factorial(n, r = 1) {
  while (n > 0) r *= n--;
  return r;
}

// Default parameters `r = 1`,
//   were introduced in ES6

这是我的推理:

  • 递归函数,即使具有记忆功能,也具有函数调用的开销(基本上将函数推入堆栈),这比使用循环
  • While for 循环和 的性能要低while 循环具有类似的性能,没有初始化表达式和最终表达式的 for 循环看起来很奇怪;可能更好地将 for(; n > 0;) 写为 while(n > 0)
  • 只有两个参数 n使用 r,因此理论上较少的参数意味着分配内存所花费的时间更少
  • 使用递减循环来检查 n 是否为零 - 我听说计算机更擅长检查二进制数(0 和 1) 比检查其他整数时更重要

Fastest factorial function

I think that this loop-based version might be the fastest factorial function.

function factorial(n, r = 1) {
  while (n > 0) r *= n--;
  return r;
}

// Default parameters `r = 1`,
//   were introduced in ES6

And here is my reasoning:

  • Recursive functions, even with memoization, have the overhead of a function call (basically pushing functions onto the stack) which is less performant than using a loop
  • While for loops and while loops have similar performance, a for loop without an initialization-expression and final-expression looks odd; probably better to write for(; n > 0;) as while(n > 0)
  • Only two parameters n and r are used, so in theory less parameters means less time spent allocating memory
  • Uses a decremented loop which checks if n is zero - I've heard theories that computers are better at checking binary numbers (0 and 1) than they are at checking other integers
梦在深巷 2024-10-04 18:21:33

看哪,记忆器,它接受任何单参数函数并记忆它。事实证明比 @xPheRe 的 解决方案 稍快,包括缓存大小和相关检查的限制,因为我使用短路等。

function memoize(func, max) {
    max = max || 5000;
    return (function() {
        var cache = {};
        var remaining = max;
        function fn(n) {
            return (cache[n] || (remaining-- >0 ? (cache[n]=func(n)) : func(n)));
        }
        return fn;
    }());
}

function fact(n) {
    return n<2 ? 1: n*fact(n-1);
}

// construct memoized version
var memfact = memoize(fact,170);

// xPheRe's solution
var factorial = (function() {
    var cache = {},
        fn = function(n) {
            if (n === 0) {
                return 1;
            } else if (cache[n]) {
                return cache[n];
            }
            return cache[n] = n * fn(n -1);
        };
    return fn;
}());

在我的 Chrome 机器上,速度比递归版本快大约 25 倍,比 xPheRe 快 10%。

Behold, the memoizer, which takes any single-argument function and memoizes it. Turns out to be marginally faster than @xPheRe's solution, including the limit on the size of the cache and associated checking, because I use shortcircuiting and so on.

function memoize(func, max) {
    max = max || 5000;
    return (function() {
        var cache = {};
        var remaining = max;
        function fn(n) {
            return (cache[n] || (remaining-- >0 ? (cache[n]=func(n)) : func(n)));
        }
        return fn;
    }());
}

function fact(n) {
    return n<2 ? 1: n*fact(n-1);
}

// construct memoized version
var memfact = memoize(fact,170);

// xPheRe's solution
var factorial = (function() {
    var cache = {},
        fn = function(n) {
            if (n === 0) {
                return 1;
            } else if (cache[n]) {
                return cache[n];
            }
            return cache[n] = n * fn(n -1);
        };
    return fn;
}());

Approximately 25x faster on my machine in Chrome than the recursive version, and 10% faster than xPheRe's.

护你周全 2024-10-04 18:21:33

使用 ES6 非常简单

const Factorial = n => ? (n * Factorial(n-1)) : 1;

请参阅此处的示例

It is very simple using ES6

const factorial = n => n ? (n * factorial(n-1)) : 1;

See an example here

慕烟庭风 2024-10-04 18:21:33

利用 Number.MAX_VALUE Number.MAX_VALUE 171!,我们可以简单地使用一个完整的查找表,该表仅由 171 个紧凑数组元素组成,占用内存不到 1.4 KB。

运行时复杂度O(1)最小数组访问开销的快速查找函数将如下所示:

// Lookup table for n! for 0 <= n <= 170:
const factorials = [1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800,87178291200,1307674368e3,20922789888e3,355687428096e3,6402373705728e3,121645100408832e3,243290200817664e4,5109094217170944e4,1.1240007277776077e21,2.585201673888498e22,6.204484017332394e23,1.5511210043330986e25,4.0329146112660565e26,1.0888869450418352e28,3.0488834461171387e29,8.841761993739702e30,2.6525285981219107e32,8.222838654177922e33,2.631308369336935e35,8.683317618811886e36,2.9523279903960416e38,1.0333147966386145e40,3.7199332678990125e41,1.3763753091226346e43,5.230226174666011e44,2.0397882081197444e46,8.159152832478977e47,3.345252661316381e49,1.40500611775288e51,6.041526306337383e52,2.658271574788449e54,1.1962222086548019e56,5.502622159812089e57,2.5862324151116818e59,1.2413915592536073e61,6.082818640342675e62,3.0414093201713376e64,1.5511187532873822e66,8.065817517094388e67,4.2748832840600255e69,2.308436973392414e71,1.2696403353658276e73,7.109985878048635e74,4.0526919504877214e76,2.3505613312828785e78,1.3868311854568984e80,8.32098711274139e81,5.075802138772248e83,3.146997326038794e85,1.98260831540444e87,1.2688693218588417e89,8.247650592082472e90,5.443449390774431e92,3.647111091818868e94,2.4800355424368305e96,1.711224524281413e98,1.1978571669969892e100,8.504785885678623e101,6.1234458376886085e103,4.4701154615126844e105,3.307885441519386e107,2.48091408113954e109,1.8854947016660504e111,1.4518309202828587e113,1.1324281178206297e115,8.946182130782976e116,7.156945704626381e118,5.797126020747368e120,4.753643337012842e122,3.945523969720659e124,3.314240134565353e126,2.81710411438055e128,2.4227095383672734e130,2.107757298379528e132,1.8548264225739844e134,1.650795516090846e136,1.4857159644817615e138,1.352001527678403e140,1.2438414054641308e142,1.1567725070816416e144,1.087366156656743e146,1.032997848823906e148,9.916779348709496e149,9.619275968248212e151,9.426890448883248e153,9.332621544394415e155,9.332621544394415e157,9.42594775983836e159,9.614466715035127e161,9.90290071648618e163,1.0299016745145628e166,1.081396758240291e168,1.1462805637347084e170,1.226520203196138e172,1.324641819451829e174,1.4438595832024937e176,1.588245541522743e178,1.7629525510902446e180,1.974506857221074e182,2.2311927486598138e184,2.5435597334721877e186,2.925093693493016e188,3.393108684451898e190,3.969937160808721e192,4.684525849754291e194,5.574585761207606e196,6.689502913449127e198,8.094298525273444e200,9.875044200833601e202,1.214630436702533e205,1.506141741511141e207,1.882677176888926e209,2.372173242880047e211,3.0126600184576594e213,3.856204823625804e215,4.974504222477287e217,6.466855489220474e219,8.47158069087882e221,1.1182486511960043e224,1.4872707060906857e226,1.9929427461615188e228,2.6904727073180504e230,3.659042881952549e232,5.012888748274992e234,6.917786472619489e236,9.615723196941089e238,1.3462012475717526e241,1.898143759076171e243,2.695364137888163e245,3.854370717180073e247,5.5502938327393044e249,8.047926057471992e251,1.1749972043909107e254,1.727245890454639e256,2.5563239178728654e258,3.80892263763057e260,5.713383956445855e262,8.62720977423324e264,1.3113358856834524e267,2.0063439050956823e269,3.0897696138473508e271,4.789142901463394e273,7.471062926282894e275,1.1729568794264145e278,1.853271869493735e280,2.9467022724950384e282,4.7147236359920616e284,7.590705053947219e286,1.2296942187394494e289,2.0044015765453026e291,3.287218585534296e293,5.423910666131589e295,9.003691705778438e297,1.503616514864999e300,2.5260757449731984e302,4.269068009004705e304,7.257415615307999e306];

// Lookup function:
function factorial(n) {
  return factorials[n] || (n > 170 ? Infinity : NaN);
}

// Test cases:
console.log(factorial(NaN));       // NaN
console.log(factorial(-Infinity)); // NaN
console.log(factorial(-1));        // NaN
console.log(factorial(0));         // 1
console.log(factorial(170));       // 7.257415615307999e+306 < Number.MAX_VALUE
console.log(factorial(171));       // Infinity > Number.MAX_VALUE
console.log(factorial(Infinity));  // Infinity

这与使用 Number 数据类型一样精确和快速。在 Javascript 中计算查找表 - 正如其他一些答案所建议的 - 当 n! 时会降低精度。 >数量。MAX_SAFE_INTEGER

通过 gzip 压缩运行时表可将其在磁盘上的大小从大约 3.6 KB 减少到 1.8 KB。

Exploiting the fact that Number.MAX_VALUE < 171!, we can simply use a complete lookup table consisting of just 171 compact array elements taking up less than 1.4 kilobytes of memory.

A fast lookup function with runtime complexity O(1) and minimal array access overhead would then look as follows:

// Lookup table for n! for 0 <= n <= 170:
const factorials = [1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800,87178291200,1307674368e3,20922789888e3,355687428096e3,6402373705728e3,121645100408832e3,243290200817664e4,5109094217170944e4,1.1240007277776077e21,2.585201673888498e22,6.204484017332394e23,1.5511210043330986e25,4.0329146112660565e26,1.0888869450418352e28,3.0488834461171387e29,8.841761993739702e30,2.6525285981219107e32,8.222838654177922e33,2.631308369336935e35,8.683317618811886e36,2.9523279903960416e38,1.0333147966386145e40,3.7199332678990125e41,1.3763753091226346e43,5.230226174666011e44,2.0397882081197444e46,8.159152832478977e47,3.345252661316381e49,1.40500611775288e51,6.041526306337383e52,2.658271574788449e54,1.1962222086548019e56,5.502622159812089e57,2.5862324151116818e59,1.2413915592536073e61,6.082818640342675e62,3.0414093201713376e64,1.5511187532873822e66,8.065817517094388e67,4.2748832840600255e69,2.308436973392414e71,1.2696403353658276e73,7.109985878048635e74,4.0526919504877214e76,2.3505613312828785e78,1.3868311854568984e80,8.32098711274139e81,5.075802138772248e83,3.146997326038794e85,1.98260831540444e87,1.2688693218588417e89,8.247650592082472e90,5.443449390774431e92,3.647111091818868e94,2.4800355424368305e96,1.711224524281413e98,1.1978571669969892e100,8.504785885678623e101,6.1234458376886085e103,4.4701154615126844e105,3.307885441519386e107,2.48091408113954e109,1.8854947016660504e111,1.4518309202828587e113,1.1324281178206297e115,8.946182130782976e116,7.156945704626381e118,5.797126020747368e120,4.753643337012842e122,3.945523969720659e124,3.314240134565353e126,2.81710411438055e128,2.4227095383672734e130,2.107757298379528e132,1.8548264225739844e134,1.650795516090846e136,1.4857159644817615e138,1.352001527678403e140,1.2438414054641308e142,1.1567725070816416e144,1.087366156656743e146,1.032997848823906e148,9.916779348709496e149,9.619275968248212e151,9.426890448883248e153,9.332621544394415e155,9.332621544394415e157,9.42594775983836e159,9.614466715035127e161,9.90290071648618e163,1.0299016745145628e166,1.081396758240291e168,1.1462805637347084e170,1.226520203196138e172,1.324641819451829e174,1.4438595832024937e176,1.588245541522743e178,1.7629525510902446e180,1.974506857221074e182,2.2311927486598138e184,2.5435597334721877e186,2.925093693493016e188,3.393108684451898e190,3.969937160808721e192,4.684525849754291e194,5.574585761207606e196,6.689502913449127e198,8.094298525273444e200,9.875044200833601e202,1.214630436702533e205,1.506141741511141e207,1.882677176888926e209,2.372173242880047e211,3.0126600184576594e213,3.856204823625804e215,4.974504222477287e217,6.466855489220474e219,8.47158069087882e221,1.1182486511960043e224,1.4872707060906857e226,1.9929427461615188e228,2.6904727073180504e230,3.659042881952549e232,5.012888748274992e234,6.917786472619489e236,9.615723196941089e238,1.3462012475717526e241,1.898143759076171e243,2.695364137888163e245,3.854370717180073e247,5.5502938327393044e249,8.047926057471992e251,1.1749972043909107e254,1.727245890454639e256,2.5563239178728654e258,3.80892263763057e260,5.713383956445855e262,8.62720977423324e264,1.3113358856834524e267,2.0063439050956823e269,3.0897696138473508e271,4.789142901463394e273,7.471062926282894e275,1.1729568794264145e278,1.853271869493735e280,2.9467022724950384e282,4.7147236359920616e284,7.590705053947219e286,1.2296942187394494e289,2.0044015765453026e291,3.287218585534296e293,5.423910666131589e295,9.003691705778438e297,1.503616514864999e300,2.5260757449731984e302,4.269068009004705e304,7.257415615307999e306];

// Lookup function:
function factorial(n) {
  return factorials[n] || (n > 170 ? Infinity : NaN);
}

// Test cases:
console.log(factorial(NaN));       // NaN
console.log(factorial(-Infinity)); // NaN
console.log(factorial(-1));        // NaN
console.log(factorial(0));         // 1
console.log(factorial(170));       // 7.257415615307999e+306 < Number.MAX_VALUE
console.log(factorial(171));       // Infinity > Number.MAX_VALUE
console.log(factorial(Infinity));  // Infinity

This is as precise and as fast as it gets using the Number datatype. Computing the lookup table in Javascript - as some other answers suggest - will reduce precision when n! > Number.MAX_SAFE_INTEGER.

Compressing the runtime table via gzip reduces its size on disk from about 3.6 to 1.8 kilobytes.

梦巷 2024-10-04 18:21:33

使用 ES6 你可以快速而简短地实现它:

const factorial = n => [...Array(n + 1).keys()].slice(1).reduce((acc, cur) => acc * cur, 1)

Using ES6 you can achieve it both fast and short:

const factorial = n => [...Array(n + 1).keys()].slice(1).reduce((acc, cur) => acc * cur, 1)
荭秂 2024-10-04 18:21:33

我偶然发现了这个帖子。受到这里所有贡献的启发,我想出了自己的版本,它有两个我以前没有讨论过的功能:
1) 检查以确保参数是非负整数
2) 从缓存中创建一个单元并使其成为一段自包含的代码。
为了好玩,我尝试使其尽可能紧凑。有些人可能会觉得它很优雅,而另一些人可能会认为它非常晦涩难懂。不管怎样,就是这样:

var fact;
(fact = function(n){
    if ((n = parseInt(n)) < 0 || isNaN(n)) throw "Must be non-negative number";
    var cache = fact.cache, i = cache.length - 1;
    while (i < n) cache.push(cache[i++] * i);
    return cache[n];
}).cache = [1];

您可以预先填充缓存,或者允许它在调用过程中填充。但是初始元素(对于fact(0) 必须存在,否则它将破坏。

享受吧:)

I came across this post. Inspired by all contributions here I came up with my own version, which has two features that I haven't seen discussed before:
1) A check to ensure the argument is a non-negative integer
2) Making a unit out of the cache and the function to make it one self contained bit of code.
For fun, I tried to make it as compact as possible. Some may find that elegant, others may think it terribly obscure. Anyway, here it is:

var fact;
(fact = function(n){
    if ((n = parseInt(n)) < 0 || isNaN(n)) throw "Must be non-negative number";
    var cache = fact.cache, i = cache.length - 1;
    while (i < n) cache.push(cache[i++] * i);
    return cache[n];
}).cache = [1];

You can either pre fill the cache, or allow it to be filled as the calls go by. But the initial element (for fact(0) must be present or it will break.

Enjoy :)

丶情人眼里出诗心の 2024-10-04 18:21:33

这是一种解决方案:

function factorial(number) {
  total = 1
  while (number > 0) {
    total *= number
    number = number - 1
  }
  return total
}

Here is one solution:

function factorial(number) {
  total = 1
  while (number > 0) {
    total *= number
    number = number - 1
  }
  return total
}
桃酥萝莉 2024-10-04 18:21:33

计算阶乘的代码取决于您的要求。

  1. 您担心溢出吗?
  2. 您将拥有什么范围的输入?
  3. 对您来说,减少规模和时间哪个更重要?
  4. 你打算用阶乘做什么?

关于第 1 点和第 4 点,使用一个函数来直接计算阶乘的 log 通常比使用一个函数来计算阶乘本身更有用。

这是一篇博客文章,讨论了这些问题。这里有一些用于计算对数阶乘的 C# 代码,移植到 JavaScript 很简单。但根据您对上述问题的回答,它可能并不适合您的需求。

The code to calculate factorial depends on your requirements.

  1. Are you concerned about overflow?
  2. What range of inputs will you have?
  3. Is it more important for you to minimize size or time?
  4. What are you going to do with the factorial?

Regarding points 1 and 4, it is often more useful to have a function to evaluate the log of the factorial directly rather than to have a function to evaluate factorial itself.

Here's a blog post that discusses these issues. Here is some C# code for computing log factorial that would be trivial to port to JavaScript. But it may not be best for your needs depending on your answers to the questions above.

绅士风度i 2024-10-04 18:21:33

这是一个紧凑的基于循环的版本

function factorial( _n )
{
    var _p = 1 ;
    while( _n > 0 ) { _p *= _n-- ; }
    return _p ;
}

或者您可以覆盖数学对象(递归版本):

Math.factorial = function( _x )  { return _x <= 1 ? 1 : _x * Math.factorial( --_x ) ; }

或者加入两种方法......

This is a compact loop-based version

function factorial( _n )
{
    var _p = 1 ;
    while( _n > 0 ) { _p *= _n-- ; }
    return _p ;
}

Or you might override Math object (recursive version):

Math.factorial = function( _x )  { return _x <= 1 ? 1 : _x * Math.factorial( --_x ) ; }

Or join both approaches ...

贱贱哒 2024-10-04 18:21:33

一行回答:

const factorial = (num, accumulator) => num <= 1 ? accumulator || 1 : factorial(--num, num * (accumulator || num + 1));

factorial(5); // 120
factorial(10); // 3628800
factorial(3); // 6
factorial(7); // 5040
// et cetera

One line answer:

const factorial = (num, accumulator) => num <= 1 ? accumulator || 1 : factorial(--num, num * (accumulator || num + 1));

factorial(5); // 120
factorial(10); // 3628800
factorial(3); // 6
factorial(7); // 5040
// et cetera

︶葆Ⅱㄣ 2024-10-04 18:21:33

使用 BigInt 进行迭代阶乘以确保安全

解决方案使用BigInt,ES 2018+/2019 功能。

这是使用 BigInt 的工作示例,因为这里的许多答案都逃脱了 Number (MDN) 几乎马上就可以了。它不是最快的,但它很简单,因此可以更清晰地适应其他优化(例如前 100 个数字的缓存)。

function factorial(n) {
   let p = BigInt(1)
   for (let i = BigInt(n); i > 0; i--) p *= i
   return p
}

用法示例

// 9.332621544394415e+157
Number(factorial(100))

// "933262154439441526816992388562667004907159682643816214685929638952175999
//  932299156089414639761565182862536979208272237582511852109168640000000000
//  00000000000000"
String(factorial(100))

// 9332621544394415268169923885626670049071596826438162146859296389521759999
// 3229915608941463976156518286253697920827223758251185210916864000000000000
// 000000000000n
factorial(100)
  • 诸如 1303n 之类的数字文字末尾的 n 表示它是 BigInt 类型。
  • 请记住,您不应将 BigIntNumber 混合使用,除非您明确强制它们,否则可能会导致准确性损失。

Iterative factorial with BigInt for safety

Solution uses BigInt, an ES 2018+/2019 feature.

This is working example uses BigInt, because many answers here all escape the safe boundary of Number (MDN) almost right away. It's not the fastest but it's simple and thus clearer for adapting other optimizations (like a cache of the first 100 numbers).

function factorial(n) {
   let p = BigInt(1)
   for (let i = BigInt(n); i > 0; i--) p *= i
   return p
}

Example Usage

// 9.332621544394415e+157
Number(factorial(100))

// "933262154439441526816992388562667004907159682643816214685929638952175999
//  932299156089414639761565182862536979208272237582511852109168640000000000
//  00000000000000"
String(factorial(100))

// 9332621544394415268169923885626670049071596826438162146859296389521759999
// 3229915608941463976156518286253697920827223758251185210916864000000000000
// 000000000000n
factorial(100)
  • The n at the end of a numeric literal like 1303n indicates it's a BigInt type.
  • Remember that you shouldn't mix BigInt with Number unless you explicitly coerce them, and that doing so could cause a loss in accuracy.
只怪假的太真实 2024-10-04 18:21:33

只是为了完整性,这里是一个递归版本,允许
尾调用优化。我不确定尾部调用优化是否在 JavaScript 中执行。

function rFact(n, acc)
{
    if (n == 0 || n == 1) return acc; 
    else return rFact(n-1, acc*n); 
}

调用它:

rFact(x, 1);

Just for completeness, here is a recursive version that would allow
tail call optimization. I'm not sure if tail call optimizations are performed in JavaScript though..

function rFact(n, acc)
{
    if (n == 0 || n == 1) return acc; 
    else return rFact(n-1, acc*n); 
}

To call it:

rFact(x, 1);
夜血缘 2024-10-04 18:21:33

这是一个迭代解决方案,使用更少的堆栈空间并以自记忆方式保存先前计算的值:

Math.factorial = function(n){
    if(this.factorials[n]){ // memoized
        return this.factorials[n];
    }
    var total=1;
    for(var i=n; i>0; i--){
        total*=i;
    }
    this.factorials[n] = total; // save
    return total;
};
Math.factorials={}; // store

另请注意,我将其添加到 Math 对象中,该对象是对象文字,因此没有原型。而只是将它们直接绑定到函数。

This is an iterative solution that uses less stack space and save previously computed values in a self-memoizing way:

Math.factorial = function(n){
    if(this.factorials[n]){ // memoized
        return this.factorials[n];
    }
    var total=1;
    for(var i=n; i>0; i--){
        total*=i;
    }
    this.factorials[n] = total; // save
    return total;
};
Math.factorials={}; // store

Also note that I am adding this to the Math object which is an object literal so there is no prototype. Rather just binding these to the function directly.

岁月打碎记忆 2024-10-04 18:21:33

我相信以下是上述评论中最可持续和最有效的代码。您可以在全局应用程序 js 架构中使用它......并且不用担心将其编写在多个命名空间中(因为它是一项可能不需要太多增强的任务)。我已经包含了 2 个方法名称(根据偏好),但这两个都可以使用,因为它们只是参考。

Math.factorial = Math.fact = function(n) {
    if (isNaN(n)||n<0) return undefined;
    var f = 1; while (n > 1) {
        f *= n--;
    } return f;
};

I believe the following is the most sustainable and efficient piece of code from the comments above. You can use this in your global application js architecture... and, not worry about writing it in multiple namespaces (since its a task which probably doesn't need much augmenting). I've included 2 method names (based on preference) but both can be used as they're just references.

Math.factorial = Math.fact = function(n) {
    if (isNaN(n)||n<0) return undefined;
    var f = 1; while (n > 1) {
        f *= n--;
    } return f;
};
染柒℉ 2024-10-04 18:21:33
// if you don't want to update the Math object, use `var factorial = ...`
Math.factorial = (function() {
    var f = function(n) {
        if (n < 1) {return 1;}  // no real error checking, could add type-check
        return (f[n] > 0) ? f[n] : f[n] = n * f(n -1);
    }
    for (i = 0; i < 101; i++) {f(i);} // precalculate some values
    return f;
}());

factorial(6); // 720, initially cached
factorial[6]; // 720, same thing, slightly faster access, 
              // but fails above current cache limit of 100
factorial(100); // 9.33262154439441e+157, called, but pulled from cache
factorial(142); // 2.6953641378881614e+245, called
factorial[141]; // 1.89814375907617e+243, now cached

这会动态缓存前 100 个值,并且不会将外部变量引入缓存范围,而是将这些值存储为函数对象本身的属性,这意味着如果您知道 Factorial(n) 已经计算出来了,你可以简单地把它称为​​factorial[n],这样效率稍微高一些。在现代浏览器中,运行前 100 个值将花费亚毫秒的时间。

// if you don't want to update the Math object, use `var factorial = ...`
Math.factorial = (function() {
    var f = function(n) {
        if (n < 1) {return 1;}  // no real error checking, could add type-check
        return (f[n] > 0) ? f[n] : f[n] = n * f(n -1);
    }
    for (i = 0; i < 101; i++) {f(i);} // precalculate some values
    return f;
}());

factorial(6); // 720, initially cached
factorial[6]; // 720, same thing, slightly faster access, 
              // but fails above current cache limit of 100
factorial(100); // 9.33262154439441e+157, called, but pulled from cache
factorial(142); // 2.6953641378881614e+245, called
factorial[141]; // 1.89814375907617e+243, now cached

This does the caching of the first 100 values on the fly, and does not introduce an external variable into scope for the cache, storing the values as properties of the function object itself, which means that if you know factorial(n) has already been calculated, you can simply refer to it as factorial[n], which is slightly more efficient. Running these first 100 values will take sub-millisecond time in modern browsers.

入怼 2024-10-04 18:21:33

这是计算正阶乘和负阶乘的实现。
它既快速又简单。

var factorial = function(n) {
  return n > 1
    ? n * factorial(n - 1)
    : n < 0
        ? n * factorial(n + 1)
        : 1;
}

Here is an implementation which calculates both positive and negative factorials.
It's fast and simple.

var factorial = function(n) {
  return n > 1
    ? n * factorial(n - 1)
    : n < 0
        ? n * factorial(n + 1)
        : 1;
}
一绘本一梦想 2024-10-04 18:21:33

这是我自己制作的,不要使用超过 170 或低于 2 的数字。

function factorial(x){
 if((!(isNaN(Number(x)))) && (Number(x)<=170) && (Number(x)>=2)){
  x=Number(x);for(i=x-(1);i>=1;--i){
   x*=i;
  }
 }return x;
}

Here's one I made myself, don't use numbers over 170 or under 2.

function factorial(x){
 if((!(isNaN(Number(x)))) && (Number(x)<=170) && (Number(x)>=2)){
  x=Number(x);for(i=x-(1);i>=1;--i){
   x*=i;
  }
 }return x;
}
尹雨沫 2024-10-04 18:21:33

这是我的代码

function factorial(num){
    var result = num;
    for(i=num;i>=2;i--){
        result = result * (i-1);
    }
    return result;
}

Here is my code

function factorial(num){
    var result = num;
    for(i=num;i>=2;i--){
        result = result * (i-1);
    }
    return result;
}
输什么也不输骨气 2024-10-04 18:21:33

缓存循环应该是最快的(至少在多次调用时)

var factorial = (function() {
  var x =[];

  return function (num) {
    if (x[num] >0) return x[num];
    var rval=1;
    for (var i = 2; i <= num; i++) {
        rval = rval * i;
        x[i] = rval;
    }
    return rval;
  }
})();

Cached loop should be fastest (at least when called multiple times)

var factorial = (function() {
  var x =[];

  return function (num) {
    if (x[num] >0) return x[num];
    var rval=1;
    for (var i = 2; i <= num; i++) {
        rval = rval * i;
        x[i] = rval;
    }
    return rval;
  }
})();
月竹挽风 2024-10-04 18:21:33
function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n)
}

http://javascript.info/tutorial/number-math 提供,作为一个简单的评估对象是否是适合计算的整数的方法。

var factorials=[[1,2,6],3];

一组简单的记忆阶乘需要冗余计算,可以通过“乘以1”进行处理,或者是一个不值得实时处理的简单方程的一位数字。

var factorial = (function(memo,n) {
    this.memomize = (function(n) {
        var ni=n-1;
        if(factorials[1]<n) {
            factorials[0][ni]=0;
            for(var factorial_index=factorials[1]-1;factorials[1]<n;factorial_index++) {
                factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);
                factorials[1]++;
            }
        }
    });
    this.factorialize = (function(n) {
        return (n<3)?n:(factorialize(n-1)*n);
    });
    if(isNumeric(n)) {
        if(memo===true) {
            this.memomize(n);
            return factorials[0][n-1];
        }
        return this.factorialize(n);
    }
    return factorials;
});

在审查了其他成员的输入(不包括日志建议,尽管我可能稍后会实现)后,我继续编写了一个相当简单的脚本。我从一个简单的 JavaScript OOP 示例开始,构建了一个小类来处理阶乘。然后我实现了上面建议的我的记忆化版本。我还实现了简写阶乘,但是我做了一个小的错误调整;我将“n<2”更改为“n<3”。 "n<2" 仍然会处理 n=2 这将是一种浪费,因为您将迭代 2*1=2;我认为这是一种浪费。我把它改成了“n<3”;因为如果 n 是 1 或 2,它将简单地返回 n,如果它是 3 或更大,它将正常评估。当然,根据规则的适用,我将函数按照假定执行的降序排列。我添加了 bool(true|false) 选项,以允许在备忘录执行和正常执行之间快速更改(您永远不知道何时想要在页面上交换而不需要更改“样式”)
正如我之前所说,记忆阶乘变量设置为 3 个起始位置,占用 4 个字符,并最大限度地减少浪费的计算。第三次迭代之后的所有内容都在处理两位数数学加。我想如果你对此有足够的坚持,你会在阶乘表上运行(已实现)。

这之后我有什么计划呢?
本地和会话存储允许根据具体情况缓存所需的迭代,本质上是处理上面提到的“表”问题。这也将大量节省数据库和服务器端空间。但是,如果您使用 localStorage,您实际上会占用用户计算机上的空间,只是为了存储数字列表并使他们的屏幕看起来更快,但是在很长一段时间内,如果有巨大的需求,这会很慢。我认为 sessionStorage (选项卡离开后清除)将是一个更好的路线。可能将其与自平衡服务器/本地依赖缓存结合起来?
用户 A 需要 X 次迭代。
用户 B 需要 Y 次迭代。
X+Y/2=本地缓存所需的数量。
然后,只需检测并调整每个用户的实时加载时间和执行时间基准,直到它自行调整以优化网站本身。
谢谢!

编辑3:

var f=[1,2,6];
var fc=3;
var factorial = (function(memo) {
    this.memomize = (function(n) {
        var ni=n-1;
        if(fc<n) {
            for(var fi=fc-1;fc<n;fi++) {
                f[fc]=f[fi]*(fc+1);
                fc++;
            }
        }
        return f[ni];
    });

    this.factorialize = (function(n) {
        return (n<3)?n:(factorialize(n-1)*n);
    });

    this.fractal = (function (functio) {
        return function(n) {
            if(isNumeric(n)) {
                return functio(n);
            }
            return NaN;
        }
    });

    if(memo===true) {
        return this.fractal(memomize);
    }
    return this.fractal(factorialize);
});

此编辑实现了另一个 Stack 建议,并允许我将该函数调用为 Factorial(true)(5),这是我设定的目标之一。 :3 我还删除了一些不必要的赋值,并简化了一些非公共变量名称。

function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n)
}

Provided by http://javascript.info/tutorial/number-math as a simple way to evaluate if an object is a proper integer for calculation.

var factorials=[[1,2,6],3];

A simple set of Memoized factorials that require redundant calculations, may be processed with "multiply by 1", or are one digit that is a simple equation not worth processing live.

var factorial = (function(memo,n) {
    this.memomize = (function(n) {
        var ni=n-1;
        if(factorials[1]<n) {
            factorials[0][ni]=0;
            for(var factorial_index=factorials[1]-1;factorials[1]<n;factorial_index++) {
                factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);
                factorials[1]++;
            }
        }
    });
    this.factorialize = (function(n) {
        return (n<3)?n:(factorialize(n-1)*n);
    });
    if(isNumeric(n)) {
        if(memo===true) {
            this.memomize(n);
            return factorials[0][n-1];
        }
        return this.factorialize(n);
    }
    return factorials;
});

After reviewing the input from other members (excluding the Log advice, although I may implement that later) I went ahead and threw together a script that is fairly simple. I started with a simple uneducated JavaScript OOP example and built a little class to handle factorials. I then implemented my version of the Memoization that was suggested above. I also implemented the shorthand Factorialization however I made a small error adjustment; I changed the "n<2" to "n<3". "n<2" would still process n=2 which would be a waste, because you would iterate for a 2*1=2; this is a waste in my opinion. I altered it to "n<3"; because if n is 1 or 2 it will simply return n, if it is 3 or more it will evaluate normally. Of course as rules apply, I placed my functions in descending order of assumed execution. I added in the bool(true|false) option to allow quick altering between memo'ed and normal execution (You just never know when you want to swap around on your page without needing to change the "style")
As I said before the memoized factorials variable is set with the 3 starting positions, taking 4 characters, and minimizing wasteful calculations. Everything past the third iteration you are handling double digit math plus. I figure if you where a stickler enough about it you would run on a factorial table (as implemented).

What have I planned after this?
local&|session storage to allow for a case by case cache of needed iterations, essentially handling the "table" issue spoken above. This would also massively save database and server side space. However, if you go with localStorage you would essentially be sucking up space on your users computer simply to store a list of numbers and make their screen LOOK faster, however over a long period of time with an immense need this would be slow. I am thinking sessionStorage (clearing after Tab leaves) would be a much better route. Possibly combine this with a self balancing server/local dependent cache?
User A needs X iterations.
User B need Y iterations.
X+Y/2=Amount needed locally cached.
Then just detect and fiddle with load-time and execute-time benchmarks live for every user until it adjusts itself to optimization for the site itself.
Thanks!

Edit 3:

var f=[1,2,6];
var fc=3;
var factorial = (function(memo) {
    this.memomize = (function(n) {
        var ni=n-1;
        if(fc<n) {
            for(var fi=fc-1;fc<n;fi++) {
                f[fc]=f[fi]*(fc+1);
                fc++;
            }
        }
        return f[ni];
    });

    this.factorialize = (function(n) {
        return (n<3)?n:(factorialize(n-1)*n);
    });

    this.fractal = (function (functio) {
        return function(n) {
            if(isNumeric(n)) {
                return functio(n);
            }
            return NaN;
        }
    });

    if(memo===true) {
        return this.fractal(memomize);
    }
    return this.fractal(factorialize);
});

This edit implements another Stack suggestion and allows me to call the function as factorial(true)(5), which was one of my goals setting out. :3 I also removed some needless assigning, and shorthanded some non-public variable names.

知你几分 2024-10-04 18:21:33

这是使用较新的 javascript 函数的一个 fill, 地图, < a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map" rel="nofollow noreferrer">减少 和 构造函数(和粗箭头语法):

Math.factorial = n => n === 0 ? 1 : Array(n).fill(null).map((e,i)=>i+1).reduce((p,c)=>p*c)

编辑:更新为处理n === 0

Here is one using newer javascript functions fill, map, reduce and constructor (and fat arrow syntax):

Math.factorial = n => n === 0 ? 1 : Array(n).fill(null).map((e,i)=>i+1).reduce((p,c)=>p*c)

Edit: updated to handle n === 0

秋凉 2024-10-04 18:21:33
function computeFactorialOfN(n) {
  var output=1;
  for(i=1; i<=n; i++){
    output*=i;
  } return output;
}
computeFactorialOfN(5);
function computeFactorialOfN(n) {
  var output=1;
  for(i=1; i<=n; i++){
    output*=i;
  } return output;
}
computeFactorialOfN(5);
蘸点软妹酱 2024-10-04 18:21:33

根据Wolfram MathWorld

阶乘n!是为正整数 n

n!=n(n-1)...2·1.

因此,可以使用下面的方法来获取一个数的阶乘:

const factorial = n => +!n || n * factorial(--n);

factorial(4) // 4! = 4 * 3 * 2 * 1 = 24

According to Wolfram MathWorld:

The factorial n! is defined for a positive integer n as

n!=n(n-1)...2·1.

Therefore, you can use the following method to obtain the factorial of a number:

const factorial = n => +!n || n * factorial(--n);

factorial(4) // 4! = 4 * 3 * 2 * 1 = 24
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文