JavaScript에서 가장 빠른 계승 함수는 무엇입니까? [닫은]


94

팩토리얼 의 정말 빠른 구현을 찾고JavaScript에서 함수 있습니다. 어떤 제안이 있습니까?


8
가능한 인수 범위는 무엇입니까?
Nikita Rybak

5
계승을 미리 계산하고 값을 조회 테이블에 저장하는 것을 고려 했습니까?
Waleed Amjad

2
그러한 기능의 적용은 무엇입니까? 즉, 무엇을 위해 사용할 것입니까?
Pointy

@Nikita Rybak, 단 1 개의 agrument (n). If (n> 170) e = Infinity
Ken

@ Pointy, 또 다른 수학 계산기 서비스.

답변:


110

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

편집 : 21.08.2014

해결 방법 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


6402373705728000을 초과하는 값은 잘 리므로이 방법을 사용하려는 경우 앞서 언급 한 표를 사용하기 전에 지수로 변환해야합니다.
David Scott Kirby

1
@DavidScottKirby Javascript는 이러한 숫자를 가장 가까운 64 비트 부동 소수점 표현으로 자동 변환합니다. 코드에 완전한 정밀도 숫자가없는 경우의 진정한 이점은 파일 크기가 줄어든다는 것입니다.
le_m

두 번째 솔루션은 타사 라이브러리가 아닌 최신 내장 기능을 사용하는 내 대답function factorial (n) { for (var i = f.length; i <= n; i++) f.push(f[i - 1].multiply(i.toString())); return f[n]; } 도 볼 수 있도록 단순화 될 수 있습니다 . BigInt
Patrick Roberts

97

루프를 사용해야합니다.

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 밀리 초 ..


+1 좋은 답변! 더 큰 숫자에 대한 계승을 계산하기 위해 여러 호출이있을 때 메모 화가 합리적 일 수 있습니다.
Tadeck

@Tadeck, 감사합니다. 실제로 메모이 제이션이 경우에 매우 유용하며 그 이유 Margus의 대답은 올바른 :)으로 선택됩니다
가브리엘 Petrioli

재귀의 한 줄 버전 : function factorial (num) {return (num == 1)? num : num * arguments.callee (num-1); }
jbyrd

2
@HWTech, 당신은 결코 메소드를 호출하지 않습니다. 귀하의 테스트가 실행 걸릴 .. 시간이 아니라 두 가지 방법을 정의하는 속도를 비교 ...이 낫다 (15의 계승하려고) 테스트
가브리엘 Petrioli

3
대신 rval = rval * i;당신이 쓸 수rval *= i;
라이언

29

나는 여전히 Margus의 대답이 가장 좋은 것이라고 생각합니다. 그러나 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), 등과 같은 멋진 작업을 수행 할 수 있지만 정확도가 약간 떨어질 수 있습니다. 결국 결과의 근사치입니다.


매우 흥미로운 접근 방식입니다. 감사합니다.
Ken

시간을 많이 절약했습니다. 감사합니다. :)
nicolaskruchten

for 루프 아래 부분을 var d3d4 = Math.exp((z + 0.5) * Math.log(z + 5.5) - z - 5.5); return d1 * d2 * d3d4;. 이를 통해 최대 169 개의 ​​계승을 계산할 수 있습니다! 현재 140 개가 아닌!. 이것은 Number170! 인 데이터 유형을 사용하여 표현 가능한 최대 계승에 매우 가깝습니다 .
le_m

18

자연수로 작업하는 경우 조회 테이블을 사용하는 것이 분명합니다. 실시간으로 팩토리얼을 계산하려면 캐시를 사용하여 속도를 높여 이전에 계산 한 숫자를 저장할 수 있습니다. 다음과 같은 것 :

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

속도를 높이기 위해 일부 값을 미리 계산할 수 있습니다.


3
이 답변을 기반으로 특정 기능에 대한 자동 메모를 만들었습니다 (약간 더 빠릅니다 :)). 또한 캐시 크기에 대한 제한도 포함됩니다. stackoverflow.com/a/10031674/36537
Phil H

16

내 해결책은 다음과 같습니다.

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

내가 찾은 가장 간단한 방법 (문자 / 줄 수가 적음) 이며 코드 줄이 하나 인 함수 만 있습니다.


편집 :
일부 문자를 저장하려면 화살표 기능 (21 바이트)을 사용할 수 있습니다 .

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

7
더으로 저장 f=n=>n?f(n-1)*n:1...
le_m

안타깝게도보기가 좋고 형식이 짧더라도 가장 느린 방법입니다.
Zibri

11

ES6로 단 한 줄

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


factorial = n => n <= 1 ? 1 : factorial(n - 1) * n
Naramsim

10

짧고 쉬운 재귀 함수 (루프로도 할 수 있지만 성능에 차이가 없다고 생각합니다) :

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

매우 큰 n의 경우 stirlings 근사치를 사용할 수 있지만 근사치 만 제공합니다.

편집 : 왜 내가 이것에 대해 반대표를 받고 있는지에 대한 의견은 좋았을 것입니다 ...

EDIT2 : 이것은 루프를 사용하는 soulution 일 것입니다 (더 나은 선택이 될 것입니다) :

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

Margus가 언급했듯이 캐시 된 값을 사용하고 더 큰 값에 대해 stirlings 근사값 을 사용하는 것이 가장 좋은 해결책이라고 생각 합니다 (당신이 정말 빨라야 하고 그렇게 큰 숫자에 대해 정확할 필요는 없다고 가정 ).


3
꼬리 호출 최적화가없는 언어 (즉, 가장 널리 사용되는 언어)에서는 방법이 있지만 쉽게 수행 할 수있는 비 재귀 구현을 사용하는 것이 좋습니다. paulbarry.com/articles/2009/08/30 / tail-call-optimization
Daniel Earwicker

구현 된 경우 TCO를 사용하지 않기 때문에 실제로 그렇게 빠르지는 않습니다. 그러나 그것은 간단하고 나는 그것을 반대 투표하지 않을 것입니다. 확실히 가장 빠른 것은 아닙니다.
haylem

재귀 호출이 꼬리 위치에 있지 않기 때문에이 함수에 대해서는 꼬리 호출 최적화조차 불가능합니다.
Fred Foo

3
@Josh, ( downvoter 아님) 가장 빠른 루프는 꽤 마진 ..
Gabriele Petrioli

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 % 빠릅니다.


6

가장 빠른 계승 함수

이 루프 기반 버전이 가장 빠른 계승 함수일 수 있다고 생각합니다.

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

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

그리고 여기에 내 추론이 있습니다.

  • 재귀 함수는 메모를 사용하더라도 루프를 사용하는 것보다 성능이 떨어지는 함수 호출 (기본적으로 스택에 함수 푸시)의 오버 헤드가 있습니다.
  • for루프와 while루프의 성능은 비슷 하지만 for초기화 표현식과 최종 표현식이없는 루프는 이상하게 보입니다. 아마도 다음 for(; n > 0;)과 같이 작성 하는 것이 좋습니다.while(n > 0)
  • 단지 두 개의 매개 변수 nr너무 이론 적은 매개 변수 수단의 사용은 적은 시간 메모리를 할당 보냈다
  • n0 인지 확인하는 감소 된 루프를 사용합니다. 컴퓨터가 다른 정수를 확인하는 것보다 이진수 (0과 1)를 확인하는 것이 더 좋다는 이론을 들었습니다.

5

이 게시물을 보았습니다. 여기에서 모든 기여에 영감을 받아 이전에 논의하지 않은 두 가지 기능이있는 자체 버전을 만들었습니다. 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)의 경우 존재해야하며 그렇지 않으면 중단됩니다.

즐겨 :)


4

ES6를 사용하면 매우 간단합니다.

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

여기 에서 예보기


4

다음은 한 가지 해결책입니다.

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

4

ES6를 사용하면 빠르고 짧게 달성 할 수 있습니다.

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

3

계승을 계산하는 코드는 요구 사항에 따라 다릅니다.

  1. 오버플로가 걱정 되십니까?
  2. 어떤 범위의 입력이 있습니까?
  3. 크기 나 시간을 최소화하는 것이 더 중요합니까?
  4. 계승으로 무엇을 할 건가요?

점 1과 4와 관련하여 요인 자체를 평가하는 함수를 갖는 것보다 요인 의 로그 를 직접 평가하는 함수를 갖는 것이 종종 더 유용 합니다.

다음 은 이러한 문제를 논의 하는 블로그 게시물 입니다. 다음은 JavaScript로 이식하기 쉬운 로그 팩토리얼을 계산하기위한 C # 코드입니다 . 그러나 위 질문에 대한 귀하의 답변에 따라 귀하의 요구에 가장 적합하지 않을 수 있습니다.


번호가 매겨진 목록은 아마도 주석에 있어야합니다. 남은 것은 두 개의 링크 뿐이며 링크 전용 답변은 권장하지 않습니다.
Barett 2015-08-24

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

또는 두 가지 접근 방식을 모두 결합하십시오 ...


1
위의 코드에서 수정했습니다. 감사합니다!
산드로 로사

3

라는 사실을 Number.MAX_VALUE < 171!활용하여 1.4KB 미만의 메모리를 차지하는 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.6KB에서 1.8KB로 줄어 듭니다.


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


3

BigInt안전 을 위한 반복 팩토리얼

솔루션은 BigIntES 2018 + / 2019 기능인을 사용합니다.

BigInt여기에서 많은 답변이 모두 Number거의 즉시 (MDN) 의 안전 경계를 벗어나기 때문에 이것은 작업 예제 입니다. 가장 빠르지는 않지만 간단하고 (처음 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 유형입니다.
  • 당신이 혼합되지 않도록 기억 BigIntNumber명시 적으로 강요하지 않는 한, 그리고 이렇게하면 정확도의 손실이 발생할 수있다.

3

ES6 기능 사용에 코드를 작성할 수 있습니다 ONE 라인재귀없이 :

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


2

완전성을 위해 다음은 테일 호출 최적화를 허용하는 재귀 버전입니다. 테일 호출 최적화가 JavaScript에서 수행되는지 확실하지 않습니다.

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

그것을 부르려면 :

rFact(x, 1);

ES6는 TCO를 지원하지만이 기능은 아직 어떤 주요 엔진에서도 기본적으로 활성화되지 않습니다
le_m

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 객체에 이것을 추가하고 있으므로 프로토 타입이 없습니다. 오히려 이것을 함수에 직접 바인딩하십시오.


예를 들어, Math.factorial(100); Math.factorial(500);1..100 곱셈을 두 번 계산합니다.
Barett 2015-08-24

2

나는 다음이 위의 주석에서 가장 지속 가능하고 효율적인 코드라고 생각합니다. 이를 글로벌 애플리케이션 js 아키텍처에서 사용할 수 있습니다. 그리고 여러 네임 스페이스에 작성하는 것에 대해 걱정할 필요가 없습니다 (아마도 많은 보강이 필요하지 않은 작업이기 때문입니다). 두 가지 메서드 이름 (기본 설정에 따라)을 포함했지만 둘 다 참조 일 뿐이므로 사용할 수 있습니다.

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

n * (n-1) * (n-2) * ... * 1
반대로

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 개의 값을 실행하면 최신 브라우저에서 1 밀리 초 미만의 시간이 걸립니다.


21 년 이후에 알아 냈어요! 숫자는 신뢰할 수 없습니다.
AutoSponge 2012 년

@AutoSponge 그 이유는 21! > Number.MAX_SAFE_INTEGER, 따라서 64 비트 부동 소수점으로 안전하게 표현할 수 없기 때문 입니다.
le_m


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

반대로 n * (n-1) * (n-2) * ... * 1로 곱셈을 시작하면 n >> 20에 대해 최대 4 자리의 정밀도를 잃게됩니다. 또한 원치 않는 전역 변수 i이고 너무 많은 Number변환을 수행 하고 0에 대해 잘못된 결과를 제공합니다! (당신이 말했듯이, 그러나 왜?).
le_m

2

내 코드는 다음과 같습니다.

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

1
If (n> 170) e = Infinity. 그리고 코드는 엄청난 수를 생성합니다. 오버플로가 없을까요?
프라임

에 대한 잘못된 결과입니다 factorial(0). 또한 곱셈을 n * (n-1) * (n-2) * ... * 1로 시작하면 n >> 20에 대한 정밀도가 최대 4 자리까지 풀립니다. @prime : 170! > Number.MAX_VALUE로 가장 잘 표현됩니다 Infinity.
le_m

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

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

다른 회원의 의견을 검토 한 후 (나중에 구현할 수도 있지만 Log 조언은 제외) 계속해서 매우 간단한 스크립트를 작성했습니다. 저는 교육을받지 못한 간단한 JavaScript OOP 예제로 시작하여 팩토리얼을 처리하기위한 작은 클래스를 만들었습니다. 그런 다음 위에서 제안한 Memoization 버전을 구현했습니다. 또한 속기 Factorialization을 구현했지만 약간의 오류를 조정했습니다. "n <2"를 "n <3"으로 변경했습니다. "n <2"는 2 * 1 = 2에 대해 반복하기 때문에 낭비 인 n = 2를 계속 처리합니다. 제 생각에는 이것은 낭비입니다. 나는 그것을 "n <3"으로 변경했다; n이 1 또는 2이면 단순히 n을 반환하기 때문에 3 이상이면 정상적으로 평가됩니다. 물론 규칙이 적용되면 내 함수를 가정 된 실행의 내림차순으로 배치했습니다. bool (true | false) 옵션을 추가하여 메모 된 실행과 일반 실행 사이에서 빠르게 변경할 수 있습니다. memoized factorials 변수는 3 개의 시작 위치로 설정되며 4 개의 문자를 취하고 낭비되는 계산을 최소화합니다. 세 번째 반복 이후의 모든 것은 두 자리 수학 플러스를 처리합니다. 나는 당신이 그것에 대해 충분히 고집하는 곳이라면 (구현 된대로) 팩토리얼 테이블에서 실행할 것이라고 생각합니다. 4 개의 문자를 취하고 낭비되는 계산을 최소화합니다. 세 번째 반복 이후의 모든 것은 두 자리 수학 플러스를 처리합니다. 나는 당신이 그것에 대해 충분히 고집하는 곳이라면 (구현 된대로) 팩토리얼 테이블에서 실행할 것이라고 생각합니다. 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);
});

이 편집은 또 다른 스택 제안을 구현하고 내 목표 설정 중 하나였던 factorial (true) (5)로 함수를 호출 할 수있게합니다. : 3 또한 불필요한 할당을 제거하고 일부 비공개 변수 이름을 단축했습니다.


undefined0!을 반환 합니다. ES6 대체 할 수 있습니다 isNumericNumber.isInteger. 같은 줄 factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);은 완전히 읽을 수 없습니다.
le_m

2

다음은 최신 자바 스크립트 함수 fill , map , reduceconstructor (및 뚱뚱한 화살표 구문)를 사용하는 것입니다.

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

편집 : n === 0을 처리하도록 업데이트 됨


2
이것은 매우 추하고 읽을 수없는 코드 줄입니다.
jungledev

1
그것은 깔끔한 아이디어입니다. 길이를 두 번 횡단하는 대신 모든 로직을 reduce 함수로 변환하고 초기 값을 사용하여 에지 케이스를 처리하는 것이 n === 0어떻습니까? Math.factorial = n => Array.from({ length: n }).reduce((product, _, i) => product * (i + 1), 1)
AlexSashaRegan

2
function computeFactorialOfN(n) {
  var output=1;
  for(i=1; i<=n; i++){
    output*=i;
  } return output;
}
computeFactorialOfN(5);

2
StackOverflow에 오신 것을 환영하며 도움을 주셔서 감사합니다. 설명을 추가하여 더 나은 답을 만들고 싶을 수 있습니다.
Elias MP
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.