JavaScript'te faktöriyel işlevin gerçekten hızlı bir uygulamasını arıyorsunuz . Herhangi bir önerin var mı?
JavaScript'te faktöriyel işlevin gerçekten hızlı bir uygulamasını arıyorsunuz . Herhangi bir önerin var mı?
Yanıtlar:
(1 ... 100) için arama yapabilirsiniz ! Faktöriyel sırayı önceden hesaplamak için Wolfram | Alpha üzerine tıklayın .
İlk 100 numara:
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
Hala Degerler kendini hesaplamak istiyorsanız, kullanabileceğiniz 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;
}
Bunun bir çalışma örnek eklemek kullanışlı olacağını düşündük tembel iteratif faktöriyel fonksiyonunun kullandığı bu büyük sayılar elde etmek tam ile sonuca memoization ve cache karşılaştırma
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);
Değişken isim görünürlüğünü sınırlamak için bir tür kapatma kullanacağınızı varsayıyorum .
function factorial (n) { for (var i = f.length; i <= n; i++) f.push(f[i - 1].multiply(i.toString())); return f[n]; }
da görmek için basitleştirilebilir . BigInt
Bir döngü kullanmalısınız.
İşte 100 faktöriyelini 10.000 kez hesaplayarak karşılaştırılan iki versiyon.
Özyinelemeli
function rFact(num)
{
if (num === 0)
{ return 1; }
else
{ return num * rFact( num - 1 ); }
}
Yinelemeli
function sFact(num)
{
var rval=1;
for (var i = 2; i <= num; i++)
rval = rval * i;
return rval;
}
Canlı: http://jsfiddle.net/xMpTv/
Sonuçlarım şunu gösteriyor:
- Yinelemeli ~ 150 milisaniye
- Yinelemeli ~ 5 milisaniye ..
rval = rval * i;
Senin yerine yazabilirsinrval *= i;
Hala Margus'un cevabının en iyisi olduğunu düşünüyorum. Bununla birlikte, 0 ile 1 aralığındaki sayıların faktöriyellerini de (yani gama işlevi) hesaplamak istiyorsanız, bu yaklaşımı kullanamazsınız çünkü arama tablosunun sonsuz değerler içermesi gerekecektir.
Bununla birlikte, faktöriyellerin değerlerini yaklaşık olarak tahmin edebilirsiniz ve oldukça hızlıdır, kendini yinelemeli olarak çağırmaktan veya en azından döngüye sokmaktan daha hızlıdır (özellikle değerler büyümeye başladığında).
İyi bir yaklaşım yöntemi Lanczos'unkidir
İşte JavaScript'te bir uygulama (aylar önce yazdığım bir hesap makinesinden alınmıştır):
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;
}
Artık factorial(0.41)
, vb. Gibi harika şeyler yapabilirsiniz , ancak doğruluk biraz düşük olabilir, sonuçta bu, sonucun bir tahminidir.
var d3d4 = Math.exp((z + 0.5) * Math.log(z + 5.5) - z - 5.5); return d1 * d2 * d3d4;
. Bu, 169'a kadar faktöriyelleri hesaplamanıza olanak tanır! şu anda sadece 140 yerine !. Bu, Number
170 olan veri türünü kullanan maksimum temsil edilebilir faktöryel değere oldukça yakındır .
Doğal sayılarla çalışıyorsanız, arama tablosu en bariz yoldur. Herhangi bir faktöriyel gerçek zamanlı olarak hesaplamak için, daha önce hesapladığınız sayıları kaydederek bir önbellekle hızlandırabilirsiniz. Gibi bir şey:
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;
})();
Daha da hızlandırmak için bazı değerleri önceden hesaplayabilirsiniz.
İşte benim çözümüm:
function fac(n){
return(n<2)?1:fac(n-1)*n;
}
Bulduğum en basit yol (daha az karakter / satır) , yalnızca bir kod satırına sahip bir işlev.
Düzenleme:
Bazı karakterleri gerçekten kaydetmek istiyorsanız, bir Ok Fonksiyonu (21 bayt) ile gidebilirsiniz :
f=n=>(n<2)?1:f(n-1)*n
f=n=>n?f(n-1)*n:1
ES6 ile sadece bir satır
const factorial = n => !(n > 1) ? 1 : factorial(n - 1) * n;
factorial = n => n <= 1 ? 1 : factorial(n - 1) * n
kısa ve kolay özyinelemeli işlev (bunu bir döngü ile de yapabilirsiniz, ancak bunun performansta herhangi bir fark yaratacağını düşünmüyorum):
function factorial (n){
if (n==0 || n==1){
return 1;
}
return factorial(n-1)*n;
}
çok büyük bir n için, stirlings yaklaşımını kullanabilirsiniz - ancak bu size yalnızca yaklaşık bir değer verecektir.
DÜZENLEME: Bunun için neden olumsuz oy aldığıma dair bir yorum güzel olurdu ...
DÜZENLEME2: Bu, bir döngü kullanan özüm olacaktır (bu daha iyi bir seçim olacaktır):
function factorial (n){
j = 1;
for(i=1;i<=n;i++){
j = j*i;
}
return j;
}
Bence en iyi çözüm, Margus'un bahsettiği gibi önbelleğe alınmış değerleri kullanmak ve daha büyük değerler için stirlings yaklaşımını kullanmak olacaktır ( gerçekten hızlı olmanız ve böylesine büyük sayılarda bu kadar kesin olmanız gerekmediğini varsayıyoruz ).
Bakın, herhangi bir tek argüman işlevini alan ve onu ezberleyen memoizer. Önbellek boyutu sınırı ve ilgili denetim de dahil olmak üzere @ xPheRe'nin çözümünden marjinal olarak daha hızlı olduğu ortaya çıkıyor , çünkü kısa devreyi kullanıyorum vb.
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'daki makinemde yinelemeli sürümden yaklaşık 25 kat daha hızlı ve xPheRe'den% 10 daha hızlı.
Bu döngü tabanlı sürümün en hızlı faktöriyel işlev olabileceğini düşünüyorum.
function factorial(n, r = 1) {
while (n > 0) r *= n--;
return r;
}
// Default parameters `r = 1`,
// was introduced in ES6
Ve işte benim gerekçem:
for
Döngüler ve while
döngüler benzer performansa sahipken , for
başlatma ifadesi ve son ifade olmayan bir döngü tuhaf görünür; muhtemelen daha iyi yazmaya for(; n > 0;)
olarakwhile(n > 0)
n
ver
böylece teori daha az parametreler yardımıyla kullanılır, daha az zaman bellek tahsis geçirdin
Sıfır olup olmadığını kontrol eden azaltılmış bir döngü kullanır - Bilgisayarların ikili sayıları (0 ve 1) kontrol etmede diğer tam sayıları kontrol etmekten daha iyi olduğuna dair teoriler duydumBu yazıya rastladım. Buradaki tüm katkılardan esinlenerek, daha önce tartışmadığım iki özelliğe sahip kendi sürümümü oluşturdum: 1) Argümanın negatif olmayan bir tamsayı olduğundan emin olmak için bir kontrol 2) Önbellekten bir birim yapmak ve kendi içinde bir kod biti yapma işlevi. Eğlenmek için olabildiğince kompakt yapmaya çalıştım. Bazıları bunu zarif bulabilir, bazıları ise son derece belirsiz olduğunu düşünebilir. Her neyse, işte burada:
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];
Önbelleği önceden doldurabilir veya aramalar geçtikçe doldurulmasına izin verebilirsiniz. Ancak ilk öğe (gerçekte (0) mevcut olmalı yoksa kırılacaktır.
Zevk almak :)
İşte bir çözüm:
function factorial(number) {
total = 1
while (number > 0) {
total *= number
number = number - 1
}
return total
}
ES6 kullanarak bunu hem hızlı hem de kısa sürede gerçekleştirebilirsiniz:
const factorial = n => [...Array(n + 1).keys()].slice(1).reduce((acc, cur) => acc * cur, 1)
Faktöriyel hesaplama kodu gereksinimlerinize bağlıdır.
1. ve 4. noktalarla ilgili olarak, faktöriyelin kendisini değerlendirmek için bir fonksiyona sahip olmaktansa, faktöriyelin günlüğünü doğrudan değerlendirecek bir fonksiyona sahip olmak genellikle daha faydalıdır .
İşte bu sorunları tartışan bir blog yazısı . İşte JavaScript'e taşımak için önemsiz olan günlük faktöryel hesaplama için bazı C # kodu . Ancak yukarıdaki sorulara verdiğiniz cevaplara bağlı olarak ihtiyaçlarınız için en iyisi olmayabilir.
Bu kompakt döngü tabanlı bir versiyondur
function factorial( _n )
{
var _p = 1 ;
while( _n > 0 ) { _p *= _n-- ; }
return _p ;
}
Veya Math nesnesini geçersiz kılabilirsiniz (özyinelemeli sürüm):
Math.factorial = function( _x ) { return _x <= 1 ? 1 : _x * Math.factorial( --_x ) ; }
Veya her iki yaklaşıma da katılın ...
Tam bir arama tablosuNumber.MAX_VALUE < 171!
kullanabileceğimiz gerçeğinden yararlanarak bellek 1.4 kilobayt daha az kaplıyor sadece 171 kompakt dizi öğelerinin oluşan.
Çalışma zamanı karmaşıklığı O (1) ve minimum dizi erişimi ek yüküne sahip hızlı bir arama işlevi daha sonra aşağıdaki gibi görünecektir:
// 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
Bu, Number
veri türünü kullanırken aldığı kadar kesin ve hızlıdır . Arama tablosunu Javascript'te hesaplamak - diğer bazı yanıtların önerdiği gibi - ne zaman hassasiyeti azaltacaktır n! > Number.MAX_SAFE_INTEGER
.
Çalışma zamanı tablosunu gzip aracılığıyla sıkıştırmak, diskteki boyutunu yaklaşık 3.6'dan 1.8 kilobayt'a düşürür.
Tek satır cevap:
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
BigInt
Güvenlik için yinelemeli faktöryelÇözüm
BigInt
, ES 2018 + / 2019 özelliğini kullanır.
Bu, çalışan örnek kullanımlarıdır BigInt
, çünkü buradaki birçok yanıtın tümü Number
(MDN) güvenli sınırından neredeyse hemen kaçar. En hızlı değil, ancak basit ve dolayısıyla diğer optimizasyonları uyarlamak için daha net (ilk 100 sayının önbelleği gibi).
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
Bir sayısal hazır benzerlerinin ucunda 1303n
bir olduğunu belirmektedir BigInt
türü.BigInt
ile Number
bunları açıkça zorlamak sürece ve bunu yaparken doğruluğunda kaybına neden olabilir.ES6 özelliklerini kullanarak, TEK satıra ve özyineleme olmadan kod yazabilir :
var factorial=(n)=>Array.from({length: n},(v, k) => k+1).reduce((a, b) => a*b, 1)
Tamlık için, işte kuyruk arama optimizasyonuna izin verecek özyinelemeli bir sürüm. Yine de kuyruk arama optimizasyonlarının JavaScript'te yapılıp yapılmadığından emin değilim ..
function rFact(n, acc)
{
if (n == 0 || n == 1) return acc;
else return rFact(n-1, acc*n);
}
Onu aramak için:
rFact(x, 1);
Bu, daha az yığın alanı kullanan ve önceden hesaplanmış değerleri kendi kendine ezberleyerek kaydeden yinelemeli bir çözümdür:
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
Ayrıca bunu bir nesne değişmezi olan Math nesnesine eklediğime dikkat edin, böylece prototip yoktur. Aksine, bunları doğrudan işleve bağlamak.
Math.factorial(100); Math.factorial(500);
için hafızaya alma işleminden tam olarak yararlanmıyor - örneğin, 1..100 çarpımını iki kez hesaplayacak.
Aşağıdakilerin, yukarıdaki yorumlardan elde edilen en sürdürülebilir ve verimli kod parçası olduğuna inanıyorum. Bunu küresel uygulama js mimarinizde kullanabilirsiniz ... ve birden çok ad alanında yazma konusunda endişelenmeyin (çünkü bu, muhtemelen çok fazla artırmaya ihtiyaç duymayan bir görevdir). 2 yöntem adı ekledim (tercihe göre), ancak her ikisi de sadece referans oldukları için kullanılabilir.
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
Bu, ilk 100 değerin anında önbelleğe alınmasını sağlar ve önbellek kapsamına harici bir değişken getirmez, değerleri işlev nesnesinin kendisinin özellikleri olarak saklar, yani factorial(n)
zaten hesaplanmış olduğunu biliyorsanız , basitçe factorial[n]
, biraz daha verimli olan olarak adlandırın . Bu ilk 100 değeri çalıştırmak, modern tarayıcılarda bir milisaniyenin altında bir zaman alacaktır.
21! > Number.MAX_SAFE_INTEGER
, 64 bitlik kayan nokta olarak güvenli bir şekilde temsil edilememesidir.
İşte hem olumlu hem de olumsuz faktörleri hesaplayan bir uygulama. Hızlı ve basit.
var factorial = function(n) {
return n > 1
? n * factorial(n - 1)
: n < 0
? n * factorial(n + 1)
: 1;
}
İşte kendim yaptığım bir tane, 170'in üzerinde veya 2'nin altındaki sayıları kullanma.
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
ve çok fazla Number
dönüşüm gerçekleştiriyor ve 0 için yanlış sonuçlar veriyor! (belirttiğiniz gibi, ama neden?).
İşte kodum
function factorial(num){
var result = num;
for(i=num;i>=2;i--){
result = result * (i-1);
}
return result;
}
factorial(0)
. Ayrıca, çarpmaya n * (n-1) * (n-2) * ... * 1 ile başladığınızda, n >> 20 için hassasiyette 4 haneye kadar kaybedersiniz. @Prime: 170! > Number.MAX_VALUE
ve en iyi şekilde temsil edilir Infinity
.
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n)
}
Tarafından sunulmuştur http://javascript.info/tutorial/number-math bir amacı hesaplanması için uygun bir tamsayıdır olmadığını değerlendirmek için basit bir yöntemdir.
var factorials=[[1,2,6],3];
Gereksiz hesaplamalar gerektiren, "1 ile çarp" ile işlenebilir veya canlı olarak işlemeye değmeyen basit bir denklem olan tek basamaklı bir basit Ezberlenmiş faktöriye seti.
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;
});
Diğer üyelerden gelen girdileri inceledikten sonra (Günlük tavsiyesi hariç, ancak bunu daha sonra uygulayabilirim) devam ettim ve oldukça basit bir senaryoyu bir araya getirdim. Basit bir eğitimsiz JavaScript OOP örneğiyle başladım ve faktöriyelleri işlemek için küçük bir sınıf oluşturdum. Daha sonra yukarıda önerilen Memoization sürümümü uyguladım. Ayrıca kısaltmayı uyguladım, ancak küçük bir hata düzeltmesi yaptım; "N <2" yi "n <3" olarak değiştirdim. "n <2" yine de israf olan n = 2'yi işler, çünkü 2 * 1 = 2 için yineleme yapardınız; bu bence bir israf. "N <3" olarak değiştirdim; çünkü n 1 veya 2 ise, basitçe n döndürür, 3 veya daha fazla ise normal olarak değerlendirilir. Elbette kurallar uygulandığında, işlevlerimi azalan varsayılan yürütme sırasına yerleştirdim. Memo'lu ve normal yürütme arasında hızlı değişiklik yapılmasına izin vermek için bool (true | false) seçeneğini ekledim (Sayfanızda "stili" değiştirmeye gerek kalmadan ne zaman geçiş yapmak istediğinizi asla bilemezsiniz) Daha önce de söylediğim gibi Memoized factorials değişkeni, 3 başlangıç konumu ile ayarlanır, 4 karakter alır ve israflı hesaplamaları en aza indirir. Üçüncü yinelemeyi geçen her şey, çift basamaklı matematik artı ile uğraşıyorsunuz. Bu konuda yeterince titizseniz, faktöriyel bir tabloda (uygulandığı gibi) koşarsınız. 4 karakter alarak gereksiz hesaplamaları en aza indirir. Üçüncü yinelemeyi geçen her şey, çift basamaklı matematik artı ile uğraşıyorsunuz. Bu konuda yeterince titizseniz, faktöriyel bir tabloda (uygulandığı gibi) koşarsınız. 4 karakter alarak boşa giden hesaplamaları en aza indirir. Üçüncü yinelemeyi geçen her şey, çift basamaklı matematik artı ile uğraşıyorsunuz. Bu konuda yeterince titizseniz, faktöriyel bir tabloda (uygulandığı gibi) koşarsınız.
Bundan sonra ne planladım? Yerel ve | oturum depolaması, temelde yukarıda bahsedilen "tablo" sorununu ele alarak, gerekli yinelemelerin vaka bazında önbelleğe alınmasına izin verir. Bu aynı zamanda veritabanı ve sunucu tarafı alanından da büyük ölçüde tasarruf sağlayacaktır. Bununla birlikte, localStorage ile giderseniz, basitçe bir sayı listesi depolamak ve ekranlarının daha hızlı GÖRÜNMESİNİ sağlamak için, temelde kullanıcılarınızın bilgisayarındaki alanı emiyor olacaksınız, ancak çok büyük bir ihtiyaç olduğunda uzun bir süre sonra bu yavaş olacaktır. Bence sessionStorage (Sekme ayrıldıktan sonra temizleme) çok daha iyi bir yol olacaktır. Muhtemelen bunu kendi kendini dengeleyen bir sunucu / yerel bağımlı önbellek ile birleştirmek? A kullanıcısının X yinelemeye ihtiyacı var. B kullanıcısının Y yinelemesine ihtiyacı var. X + Y / 2 = Yerel olarak önbelleğe alınması gereken miktar. Ardından, sitenin optimizasyonuna kendini ayarlayana kadar her kullanıcı için yükleme süresi ve yürütme zamanı karşılaştırmaları canlı olarak tespit edin ve oynayın. Teşekkürler!
Düzenleme 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);
});
Bu düzenleme, başka bir Yığın önerisi uygular ve işlevi faktöriyel (doğru) (5) olarak adlandırmama izin verir, ki bu da hedeflerimden biridir. : 3 Ayrıca bazı gereksiz atamaları kaldırdım ve bazı genel olmayan değişken isimlerini kısalttım.
undefined
0 !. ES6 değiştirmesini sağlar isNumeric
ile Number.isInteger
. Gibi satırlar factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);
tamamen okunamaz.
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);