106

JavaScriptでの階乗関数の非常に高速な実装を探しています。何か提案はありますか?

4

49 に答える 49

122

(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

それでも自分で値を計算したい場合は、メモ化を使用できます。

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

編集:2014年8月21日

解決策2

大きな数を使用してメモ化キャッシュを比較して正確な結果を得る、怠惰な 反復 階乗関数の実用的な例を追加すると便利だと思いました。

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

于 2010-10-18T12:48:11.203 に答える
108

ループを使用する必要があります。

これは、10.000回の100の階乗を計算することによってベンチマークされた2つのバージョンです。

再帰的

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ミリ秒。

于 2010-10-18T12:59:13.147 に答える
30

私はまだマーガスの答えが最良のものだと思います。ただし、0から1の範囲内の数値の階乗(つまり、ガンマ関数)も計算する場合は、ルックアップテーブルに無限の値が含まれている必要があるため、このアプローチを使用することはできません。

ただし、階乗の値を概算することはできます。これは、再帰的に呼び出したり、少なくともループしたりするよりも、かなり高速です(特に、値が大きくなり始めた場合)。

良い近似方法はランツォシュのものです

これが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)、精度が少しずれている可能性があります。結局のところ、これは結果の概算です。

于 2010-10-18T13:00:30.733 に答える
19

自然数を使用している場合は、ルックアップテーブルが最適な方法です。階乗をリアルタイムで計算するには、キャッシュを使用して階乗を高速化し、以前に計算した数値を保存します。何かのようなもの:

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

さらに高速化するために、いくつかの値を事前に計算することができます。

于 2010-10-18T13:34:50.143 に答える
18

これが私の解決策です:

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

これは私が見つけた最も簡単な方法(文字/行が少ない)であり、1つのコード行を持つ関数のみです。


編集:
本当にいくつかの文字を保存したい場合は、矢印関数 (21バイト)を使用できます:

f=n=>(n<2)?1:f(n-1)*n
于 2013-10-02T14:14:23.513 に答える
16

ES6でたった1行

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>

于 2016-07-24T20:50:15.567 に答える
12

短くて簡単な再帰関数(ループでも実行できますが、パフォーマンスに違いはないと思います):

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

nが非常に大きい場合は、スターリング近似を使用できますが、それでは近似値しか得られません。

編集:なぜ私がこれに反対票を投じているのかについてのコメントは良かったでしょう...

EDIT2 :これはループを使用した魂です(これはより良い選択です):

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

マーガスが述べたように、キャッシュされた値を使用し、より大きな値にはスターリング近似を使用するのが最善の解決策だと思います(本当に高速である必要があり、そのような大きな数値でそれほど正確である必要はないと仮定します)。

于 2010-10-18T12:47:08.723 に答える
9

最速の階乗関数

このループベースのバージョンは、最速の階乗関数かもしれないと思います。

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

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

そして、ここに私の推論があります:

  • 再帰関数は、メモ化を使用した場合でも、ループを使用するよりもパフォーマンスが低い関数呼び出し(基本的には関数をスタックにプッシュする)のオーバーヘッドがあります。
  • forループとwhileループのパフォーマンスは似ていますが、for初期化式と最終式のないループは奇妙に見えます。おそらく次のように書く方が良いでしょfor(; n > 0;)while(n > 0)
  • は2つのパラメーターのみが使用nrれるため、理論的にはパラメーターが少ないということは、メモリーの割り当てに費やされる時間が少ないことを意味します。
  • ゼロかどうかをチェックするデクリメントループを使用しますn-コンピューターは他の整数をチェックするよりも2進数(0と1)をチェックする方が優れているという理論を聞いたことがあります
于 2018-11-03T22:14:59.737 に答える
7

見よ、メモ化機能は、任意の単一引数関数を取り、それをメモ化します。短絡などを使用しているため、キャッシュのサイズの制限や関連するチェックなど、@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%高速です。

于 2012-04-05T15:40:03.170 に答える
6

ES6を使用すると非常に簡単です

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

こちらの例をご覧ください

于 2016-11-05T05:40:58.353 に答える
6

ES6を使用すると、高速かつ短時間でそれを実現できます。

const factorial = n => [...Array(n + 1).keys()].slice(1).reduce((acc, cur) => acc * cur, 1)
于 2018-02-17T06:03:42.070 に答える
5

私はこの投稿に出くわしました。ここでのすべての貢献に触発されて、私は自分のバージョンを思いつきました。これには、これまでに説明したことのない2つの機能があります。1)引数が負でない整数であることを確認するチェック2)キャッシュからユニットを作成するそれを1つの自己完結型のコードにする関数。楽しみのために、できるだけコンパクトにしようとしました。エレガントだと思う人もいれば、ひどく曖昧だと思う人もいます。とにかく、ここにあります:

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)の場合は存在する必要があります。存在しない場合は壊れます。

楽しみ :)

于 2012-03-07T21:30:02.497 に答える
4

という事実を利用して、1.4キロバイト未満のメモリを使用する171個のコンパクトな配列要素で構成される完全なルックアップテーブルNumber.MAX_VALUE < 171!を簡単に使用できます。

実行時の複雑さが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! > Number.MAX_SAFE_INTEGERます。

gzipでランタイムテーブルを圧縮すると、ディスク上のサイズが約3.6キロバイトから1.8キロバイトに減少します。

于 2017-03-09T17:19:02.110 に答える
4

これが1つの解決策です:

function factorial(number) {
  total = 1
  while (number > 0) {
    total *= number
    number = number - 1
  }
  return total
}
于 2018-01-23T02:53:08.123 に答える
3

階乗を計算するコードは、要件によって異なります。

  1. オーバーフローが心配ですか?
  2. どの範囲の入力がありますか?
  3. サイズや時間を最小限に抑えることがより重要ですか?
  4. 階乗をどうするつもりですか?

ポイント1と4に関しては、階乗自体を評価する関数よりも、階乗の対数を直接評価する関数の方が便利なことがよくあります。

これらの問題について説明しているブログ投稿は次のとおりです。これは、JavaScriptに移植するのが簡単な対数階乗を計算するためのC#コードです。ただし、上記の質問に対する回答によっては、ニーズに最適ではない場合があります。

于 2010-10-18T13:12:39.783 に答える
3

これはコンパクトなループベースのバージョンです

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

または、Mathオブジェクト(再帰バージョン)をオーバーライドすることもできます。

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

または、両方のアプローチに参加してください...

于 2015-12-26T18:47:34.210 に答える
3

一行の答え:

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

于 2018-02-09T22:16:48.977 に答える
3

BigInt安全のための反復階乗

ソリューションはBigInt、ES 2018 +/2019機能を使用します。

BigIntここでの多くの回答はすべて(MDN)の安全な境界をほぼ即座に逃れるため、これは実際の使用例Numberです。これは最速ではありませんが、他の最適化(最初の100個の数値のキャッシュなど)を適応させるために単純であり、したがってより明確です。

function factorial(nat) {
   let p = BigInt(1)
   let i = BigInt(nat)

   while (1 < i--) p *= i

   return p
}

使用例

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

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

// 9332621544394415268169923885626670049071596826438162146859296389521759999
// 3229915608941463976156518286253697920827223758251185210916864000000000000
// 000000000000n
factorial(100)
  • nような数値リテラルの最後にあるは、1303nそれが型であることを示しますBigInt
  • 明示的に強制しない限り、混合BigIntしないでください。混合するNumberと、精度が低下する可能性があります。
于 2018-12-06T22:38:34.137 に答える
2

完全を期すために、末尾呼び出しの最適化を可能にする再帰バージョンを次に示します。ただし、末尾呼び出しの最適化がJavaScriptで実行されるかどうかはわかりません。

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

それを呼び出すには:

rFact(x, 1);
于 2010-11-19T06:32:33.930 に答える
2

これは、より少ないスタックスペースを使用し、以前に計算された値を自己メモ化する方法で保存する反復ソリューションです。

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オブジェクトに追加しているため、プロトタイプがないことにも注意してください。むしろ、これらを関数に直接バインドするだけです。

于 2012-03-05T19:02:39.927 に答える
2

上記のコメントから、以下が最も持続可能で効率的なコードだと思います。これは、グローバルアプリケーションの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;
};
于 2012-03-19T06:34:41.773 に答える
2
// 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個の値を実行するのにミリ秒未満の時間がかかります。

于 2012-03-23T13:43:52.887 に答える
2

これは、正と負の両方の階乗を計算する実装です。それは速くて簡単です。

var factorial = function(n) {
  return n > 1
    ? n * factorial(n - 1)
    : n < 0
        ? n * factorial(n + 1)
        : 1;
}
于 2012-07-31T03:22:23.600 に答える
2

これは私が自分で作ったものです。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;
}
于 2013-05-18T18:57:59.460 に答える
2

これが私のコードです

function factorial(num){
    var result = num;
    for(i=num;i>=2;i--){
        result = result * (i-1);
    }
    return result;
}
于 2014-01-03T16:50:38.437 に答える
2

キャッシュされたループは最速である必要があります(少なくとも複数回呼び出された場合)

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;
  }
})();
于 2014-03-20T14:14:48.013 に答える
2

これは、新しいjavascript関数fillmapreduceコンストラクター (および太い矢印の構文)を使用したものです。

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

編集:n===0を処理するように更新

于 2016-01-04T22:36:03.720 に答える
2
function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n)
}

オブジェクトが計算に適切な整数であるかどうかを評価する簡単な方法として、http://javascript.info/tutorial/number-mathによって提供されます。

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

冗長な計算を必要とするメモ化された階乗の単純なセットは、「1を掛ける」で処理されるか、ライブで処理する価値のない単純な方程式である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;
});

他のメンバーからの入力を確認した後(後で実装する可能性がありますが、ログのアドバイスを除く)、先に進んで、かなり単純なスクリプトをまとめました。単純な教育を受けていないJavaScriptOOPの例から始めて、階乗を処理するための小さなクラスを作成しました。次に、上記で提案したメモ化のバージョンを実装しました。省略形のFactorializationも実装しましたが、小さなエラー調整を行いました。「n<2」を「n<3」に変更しました。「n<2」はn=2を処理しますが、これは2 * 1 = 2を繰り返すため、無駄になります。これは私の意見では無駄です。「n<3」に変更しました。nが1または2の場合は単にnを返すため、3以上の場合は正常に評価されます。もちろん、ルールが適用されるので、想定される実行の降順で関数を配置しました。bool(true | false)オプションを追加して、メモ化された実行と通常の実行をすばやく変更できるようにしました(「スタイル」を変更せずに、ページをいつ入れ替えたいかはわかりません)。メモ化された階乗変数は、3つの開始位置で設定され、4文字を使用し、無駄な計算を最小限に抑えます。3回目の反復を過ぎると、2桁の数学プラスを処理します。それについて十分なsticklerが(実装されたように)階乗テーブルで実行されるかどうかを私は考えます。4文字を取り、無駄な計算を最小限に抑えます。3回目の反復を過ぎると、2桁の数学プラスを処理します。それについて十分なsticklerが(実装されたように)階乗テーブルで実行されるかどうかを私は考えます。4文字を取り、無駄な計算を最小限に抑えます。3回目の反復を過ぎると、2桁の数学プラスを処理します。それについて十分なsticklerが(実装されたように)階乗テーブルで実行されるかどうかを私は考えます。

この後、私は何を計画しましたか?ローカル&|セッションストレージ。必要な反復のケースバイケースのキャッシュを可能にし、基本的に上記の「テーブル」の問題を処理します。これにより、データベースとサーバー側のスペースも大幅に節約されます。ただし、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);
});

この編集により、別のスタック提案が実装され、関数をfactorial(true)(5)として呼び出すことができます。これは、私の目標の1つです。:3また、いくつかの不必要な割り当てを削除し、いくつかの非公開変数名を省略しました。

于 2016-05-10T23:18:19.350 に答える
2

ES6機能を使用して、再帰なしで1行にコードを記述できます 。

var factorial=(n)=>Array.from({length: n},(v, k) => k+1).reduce((a, b) => a*b, 1)

var factorial=(n)=>Array.from(
       {length: n}, (v, k) => k+1)   /*Generate Array [1, 2, .., n -1, n]*/
     .reduce(
       (a, b) => a*b, 1 /*Multiply all aarray items; one with the next*/
     ); 
     

var n = prompt('Give us "n", we will calculate "n!" ?');

if (n) {
  alert(`${n}! = ${factorial(n)}`)
}

于 2016-07-24T21:15:29.957 に答える
2
function computeFactorialOfN(n) {
  var output=1;
  for(i=1; i<=n; i++){
    output*=i;
  } return output;
}
computeFactorialOfN(5);
于 2017-08-29T10:55:09.833 に答える
2

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
于 2018-11-01T21:09:33.470 に答える
2

これはまだ提供されていないアプローチです。メモ化を使用するBigIntと、正確な結果を取得し、すでに計算された値の計算をスキップできます。

// using let and const, block scope can be used instead of IIFE for closure
{
  const lut = [1n, 1n];
  
  // returns factorial as BigInt instead of Number
  function factorial (n) {
    for (let i = lut.length; i <= n; i++) {
      lut.push(BigInt(i) * lut[i - 1]);
    }

    return lut[n];
  }
}

console.log('starting');
// first time will require computation
console.log(factorial(10000).toString());
// second time will return result from cache
console.log(factorial(10000).toString());
div.as-console-wrapper { overflow-x: scroll; }

于 2019-08-22T16:01:56.153 に答える
1

これにより、nの階乗が返されます

function f(n) {
    var e = n;
    if (e == 1 | e == 0) return 1;
    while (n--) {
        if (n < 1)
            break;
        e *= n;
    }
    return e
}
于 2014-01-13T16:48:04.250 に答える
1
var factorial = (function() {
    var cache = [1];
    return function(value) {
        for (var index = cache.length; index <= value; index++) {
            cache[index] = index * cache[index - 1]
        }
        return cache[value];
    }
})();

私はこれが同じ場合に役立つと思います:

function factorialDivision(n, d) {
    var value = 1;
    for (d++ < n) {
        value *= d;
    }
    return value;
}
于 2014-01-14T15:48:53.837 に答える
1

階乗は、与えられた数から1までの単純な縮退乗算であるため、乗算をループする方が実際に簡単です。

Math.factorial = function(n) {

  if (n === 0||n === 1) {

    return 1;

  } else {

    for(var i = n; i > 0; --i) { //always make sure to decrement the value BEFORE it's tacked onto the original as a product
      n *= i;
    }

    return n;

  }

}
于 2014-01-27T05:05:43.273 に答える
1
 used closure  for this with the helper (getFact) , I think this approach is neat hope this helps  


    factorial of n : using closures*/

    function getFact(num) {

        if (num > 1)
            return num * getFact(num - 1);
        else
            return 1;

    }


    function makeFact(fn) {
        return function(num) {
            return fn(num);
        }


    }

   makeFact(getFact)(5) //120
于 2014-11-08T09:11:42.303 に答える
1
var factorial = function(numToBeFactored)
    {
        if (numToBeFactored == 0)
                return 1;
            var numLength = 0;
            var numBeingFactored = 1;
        /*goes through the loop numToBeFactored times and each time multiplies numBeingFactored by one less than the last loop*/
            for (numLength = 0; numLength < numToBeFactored; numLength++)
            {
                numBeingFactored *= (numToBeFactored - numLength);
            }
            return numBeingFactored;
    };
于 2015-02-09T14:57:08.697 に答える
1

最初はおそらく非常に単純であり、おそらくこの短いコードから、ニーズに応じてより適切に設定できます。

<body>

    <button  onclick="fact()">Open the Prompt</button>
    <h2 id="output"></h2>

    <script>

    function fact(){ 
        var enter=prompt("Enter You Factorial Number Bellow :","");
        var Num_enter=Number(enter);

        for (var i=1,FactNumber=1;i<=Num_enter;i++){

        FactNumber=FactNumber*i;
        }

        if(Num_enter){ 
           document.getElementById("output").textContent="the factorial of "+ Num_enter + " is: "+Num_enter+"!= "+ FactNumber;
        }


     }

   </script>


 </body>
于 2015-06-09T07:35:00.183 に答える
1
    function factorial(num){    
        var num=Number(num);
        if (num < 0){
            return "this is not a positive number";
        }
        else{

        for (i=2 , f=1 ; i<=num;i++){

        f=f*i;

        }

    return f;
    }
    }
    // the function assumes that a number < 0 is null and factorial of any word is considerate as factorial of 0 //

    console.log("-5! ="+factorial(-1));
    console.log("something ="+factorial("something"));
    console.log("15! ="+factorial(15));
    console.log("20! ="+factorial(20));
于 2015-06-12T00:21:22.820 に答える
1
var factorial = function() {
    var memo = [1];
    var facto = function (n) {
        var result = memo[n];
    if (typeof result !== 'number'){
        result = facto(n-1)*n;
    }
        return result;
    };
    return facto;
}();

メモ化を使用して数値の階乗を計算するには、を使用して呼び出しますfactorial(n)

于 2015-09-10T09:39:03.917 に答える
1

上記のものはどれも良いのですが、どれも長すぎるように思えるので、自分で作りました。

function factorial(n) {              //"n" is the number used in the factorial

    var ans = 1,                     //define the base variables
        neg = false,
        n = Math.round(n);

    if (n<0 || !n) neg = true;       //check if the number is negative or if the number doesn't exist

    for (var i=1;i<=n;i++) ans *= i; //the actual repeating code, won't run if the number is less than or equal to 0

    return neg ? NaN : ans;          //return the answer if the original was positive

}

ループが機能する方法は、for1未満の数値に対しては自動的に何もしません。したがって、基本的に「(数値)が。以下の場合は0、を返し1ます。

if (n<0 || !n) neg = true;return neg ? NaN : ans;連携して、「数値が負の場合は、NaN(数値ではない)を返します」と言います。これらはまた、番号が存在するかどうかを確認しNaN、番号が存在しない場合は(番号ではない)を返します。

ノート

少なくともChromev50.0.2661.86(64ビット)では、最大170です。したがって、この関数を170より大きい数値(たとえば171)で実行すると、が返されinfinityます。

于 2016-04-25T17:01:10.830 に答える
1

これは、階乗関数を作成するために私が知っている最も簡単な方法です

function factorial(num) {

    var result = 1;
    for(var i = 2; i<= num; i++) {
        result *= i;
    }
    return result;
}
于 2017-01-20T17:32:12.990 に答える
1

使用できます

function factorial(n) {
    return [...Array(n+1).keys()].slice(1).reduce( (a,b) => a * b, 1 );
}
于 2017-04-28T19:48:00.760 に答える
1

さて、この質問には十分な答えがありますが、階乗と逆階乗の読みやすく、速くて短い解決策を投稿するだけです。

{
    const cache = [1, 1];
    let i = 2;

    function factorial(n) {
        if (!isFinite(n = parseInt(n)) || n < 0)
            throw new Error('argument for factorial has to be a positive finite integer but was ' + n);

        for (; i <= n; i++)
            cache[i] = cache[i - 1] * i;

        return cache[n];
    }

    function reverseFactorial(n) {
        if (!isFinite(n = parseFloat(n)) || n < 0)
            throw new Error('argument for reverseFactorial has to be a positive finite floatingpoint number but was ' + n);

        let f = 1;

        while (true)
            if (factorial(++f) >= n)
                return f - 1; // lower bound (f! which will fit in the given n, for upper bound just return f)

    }
}

reverseFactorial指定されたnに適合するk最大のanを返します。k!

両方の関数は、によって構築されたキャッシュの利益をもたらしfactorialます。

少しテストしたい場合:

for (let i = 0; i < 10; i++) {
    let random = Math.random() * 100;
    random = factorial(random) * Math.random() * random;

    const reverse = reverseFactorial(random);
    const resultOfReverse = factorial(reverse);

    function expo(x) {
        return x.toExponential(2);
    }

    console.log('%s fits %d! which is %s (upper bound %d! is %s)', expo(random), reverse, expo(resultOfReverse), reverse + 1, expo(factorial(reverse + 1)));
}
于 2018-06-10T20:34:46.660 に答える
1

反復および再帰オプションの1行ソリューション。

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

const sf = n => {for (var i = n, c = 1; i > 1; i --) c *= i; return c;}
于 2018-09-10T11:39:37.140 に答える
0

反復:

Math.factorial=n=>{for(var o=n;n>1;)o*=--n;return o};

再帰的:

Math.factorial=n=>n>1?n--*Math.fac(n):1;

事前計算:

(_=>{let f=[],i=0;for(;i<171;i++)f[i]=(n=>{for(var o=n;n>1;)o*=--n;return o})(i);Math.factorial=n=>{n=Math.round(n);return n<171?f[n]:Infinity}})();

https://code.sololearn.com/Wj4rlA27C9fD。ここで私はより多くの解決策を投稿するかもしれません。

于 2017-11-03T14:12:22.803 に答える
0

彼女はIIFy関数と再帰を使用した私のソリューションです。

console.log((function factorial(n){return (n>1)?n*factorial(n-1):1;})(10))

これは、1行のコードで階乗の出力を取得するための最適なソリューションです。

于 2019-08-22T15:09:29.030 に答える
-1

古い質問ですが、このアプローチは非常に読みやすく簡単です。

function factorialize(num) {
  var arr = [];
  var result;
  if ( num === 0 || num === 1 ) {
    return 1;
  } else {
    for (var i = num; i > 0; i--) {
      arr.push(i);
      result = arr.reduce(function(previousVal, nextVal){
                return previousVal * nextVal;
              });
    }
    return result;
  }
}
于 2017-01-15T19:32:40.687 に答える
-2
    var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    numbers.reduce(function factorial(previous, current) {
      return previous * current;
      });

   console.log(numbers);
于 2017-01-04T11:58:39.320 に答える