팩토리얼 의 정말 빠른 구현을 찾고JavaScript에서 함수 있습니다. 어떤 제안이 있습니까?
팩토리얼 의 정말 빠른 구현을 찾고JavaScript에서 함수 있습니다. 어떤 제안이 있습니까?
답변:
(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;
}
큰 숫자 를 사용 하여 메모 와 캐시 를 비교 하여 정확한 결과 를 얻는 지연 반복 팩토리얼 함수 의 작업 예제를 추가하는 것이 유용 할 것이라고 생각했습니다.
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);
나는 당신이 어떤 종류의 클로저를 사용할 것이라고 가정합니다.변수 이름 가시성을 제한하기 위해 를 .
function factorial (n) { for (var i = f.length; i <= n; i++) f.push(f[i - 1].multiply(i.toString())); return f[n]; }
도 볼 수 있도록 단순화 될 수 있습니다 . BigInt
루프를 사용해야합니다.
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 밀리 초 ..
rval = rval * i;
당신이 쓸 수rval *= i;
나는 여전히 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)
, 등과 같은 멋진 작업을 수행 할 수 있지만 정확도가 약간 떨어질 수 있습니다. 결국 결과의 근사치입니다.
var d3d4 = Math.exp((z + 0.5) * Math.log(z + 5.5) - z - 5.5); return d1 * d2 * d3d4;
. 이를 통해 최대 169 개의 계승을 계산할 수 있습니다! 현재 140 개가 아닌!. 이것은 Number
170! 인 데이터 유형을 사용하여 표현 가능한 최대 계승에 매우 가깝습니다 .
자연수로 작업하는 경우 조회 테이블을 사용하는 것이 분명합니다. 실시간으로 팩토리얼을 계산하려면 캐시를 사용하여 속도를 높여 이전에 계산 한 숫자를 저장할 수 있습니다. 다음과 같은 것 :
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;
})();
속도를 높이기 위해 일부 값을 미리 계산할 수 있습니다.
짧고 쉬운 재귀 함수 (루프로도 할 수 있지만 성능에 차이가 없다고 생각합니다) :
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 근사값 을 사용하는 것이 가장 좋은 해결책이라고 생각 합니다 (당신이 정말 빨라야 하고 그렇게 큰 숫자에 대해 정확할 필요는 없다고 가정 ).
단일 인수 함수를 가져 와서 메모하는 메모 자입니다. 단락 등을 사용하기 때문에 캐시 크기 및 관련 검사에 대한 제한을 포함하여 @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 % 빠릅니다.
이 루프 기반 버전이 가장 빠른 계승 함수일 수 있다고 생각합니다.
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)
n
와 r
너무 이론 적은 매개 변수 수단의 사용은 적은 시간 메모리를 할당 보냈다n
0 인지 확인하는 감소 된 루프를 사용합니다. 컴퓨터가 다른 정수를 확인하는 것보다 이진수 (0과 1)를 확인하는 것이 더 좋다는 이론을 들었습니다.이 게시물을 보았습니다. 여기에서 모든 기여에 영감을 받아 이전에 논의하지 않은 두 가지 기능이있는 자체 버전을 만들었습니다. 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)의 경우 존재해야하며 그렇지 않으면 중단됩니다.
즐겨 :)
계승을 계산하는 코드는 요구 사항에 따라 다릅니다.
점 1과 4와 관련하여 요인 자체를 평가하는 함수를 갖는 것보다 요인 의 로그 를 직접 평가하는 함수를 갖는 것이 종종 더 유용 합니다.
다음 은 이러한 문제를 논의 하는 블로그 게시물 입니다. 다음은 JavaScript로 이식하기 쉬운 로그 팩토리얼을 계산하기위한 C # 코드입니다 . 그러나 위 질문에 대한 귀하의 답변에 따라 귀하의 요구에 가장 적합하지 않을 수 있습니다.
이것은 컴팩트 루프 기반 버전입니다.
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 ) ; }
또는 두 가지 접근 방식을 모두 결합하십시오 ...
라는 사실을 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로 줄어 듭니다.
BigInt
안전 을 위한 반복 팩토리얼솔루션은
BigInt
ES 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
유형입니다.BigInt
에 Number
명시 적으로 강요하지 않는 한, 그리고 이렇게하면 정확도의 손실이 발생할 수있다.ES6 기능 사용에 코드를 작성할 수 있습니다 ONE 라인 및 재귀없이 :
var factorial=(n)=>Array.from({length: n},(v, k) => k+1).reduce((a, b) => a*b, 1)
이것은 스택 공간을 덜 사용하고 이전에 계산 된 값을 자체 메모리 방식으로 저장하는 반복적 인 솔루션입니다.
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 곱셈을 두 번 계산합니다.
나는 다음이 위의 주석에서 가장 지속 가능하고 효율적인 코드라고 생각합니다. 이를 글로벌 애플리케이션 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
// 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! > Number.MAX_SAFE_INTEGER
, 따라서 64 비트 부동 소수점으로 안전하게 표현할 수 없기 때문 입니다.
다음은 양의 계승과 음의 계승을 모두 계산하는 구현입니다. 빠르고 간단합니다.
var factorial = function(n) {
return n > 1
? n * factorial(n - 1)
: n < 0
? n * factorial(n + 1)
: 1;
}
여기 제가 직접 만든 것이 있습니다. 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;
}
i
이고 너무 많은 Number
변환을 수행 하고 0에 대해 잘못된 결과를 제공합니다! (당신이 말했듯이, 그러나 왜?).
내 코드는 다음과 같습니다.
function factorial(num){
var result = num;
for(i=num;i>=2;i--){
result = result * (i-1);
}
return result;
}
factorial(0)
. 또한 곱셈을 n * (n-1) * (n-2) * ... * 1로 시작하면 n >> 20에 대한 정밀도가 최대 4 자리까지 풀립니다. @prime : 170! > Number.MAX_VALUE
로 가장 잘 표현됩니다 Infinity
.
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 또한 불필요한 할당을 제거하고 일부 비공개 변수 이름을 단축했습니다.
undefined
0!을 반환 합니다. ES6 대체 할 수 있습니다 isNumeric
로 Number.isInteger
. 같은 줄 factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);
은 완전히 읽을 수 없습니다.
다음은 최신 자바 스크립트 함수 fill , map , reduce 및 constructor (및 뚱뚱한 화살표 구문)를 사용하는 것입니다.
Math.factorial = n => n === 0 ? 1 : Array(n).fill(null).map((e,i)=>i+1).reduce((p,c)=>p*c)
편집 : n === 0을 처리하도록 업데이트 됨
n === 0
어떻습니까? Math.factorial = n => Array.from({ length: n }).reduce((product, _, i) => product * (i + 1), 1)
function computeFactorialOfN(n) {
var output=1;
for(i=1; i<=n; i++){
output*=i;
} return output;
}
computeFactorialOfN(5);