जावास्क्रिप्ट में सबसे तेज़ फैक्टरियल फ़ंक्शन क्या है? [बन्द है]


94

का एक बहुत तेजी से कार्यान्वयन के लिए खोज रहे भाज्य जावास्क्रिप्ट में कार्य करते हैं। कोई सुझाव?


8
तर्कों की संभावित सीमा क्या है?
निकिता रायबाक

5
क्या आपने पूर्व-गणना वाले तथ्यों को माना है और लुकअप टेबल में मानों को संचयित किया है?
वलद अमजद

2
ऐसे फ़ंक्शन का अनुप्रयोग क्या है? दूसरे शब्दों में, आप इसके लिए क्या उपयोग करने जा रहे हैं?
पोइंट्टी

@ निकिता रायबाक, केवल 1 एग्रीकल्चर (एन)। यदि (n> 170) ई = इन्फिनिटी
केन

@ इंगित, अभी तक एक और गणित कैलकुलेटर सेवा।
केन

जवाबों:


110

आप (1 ... 100) खोज सकते हैं! वुल्फरम पर | अल्फा तथ्य -क्रम की पूर्व-गणना करने के लिए।

पहले 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

समाधान २

मैंने सोचा कि यह आलसी पुनरावृत्ति संबंधी कार्य का एक उदाहरण जोड़ने के लिए उपयोगी होगा जो तुलना के रूप में संस्मरण और कैश के साथ सटीक परिणाम प्राप्त करने के लिए बड़ी संख्या का उपयोग करता है।

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

मुझे लगता है कि आप चर नाम दृश्यता को सीमित करने के लिए किसी तरह के बंद का उपयोग करेंगे ।

Ref : BigNumber सैंडबॉक्स : JsFiddle


यदि आप इस दृष्टिकोण का उपयोग करने जा रहे हैं तो पूर्व-निर्धारित तालिका का उपयोग करने से पहले घातांक में परिवर्तित करना सुनिश्चित करें।
डेविड स्कॉट किर्बी

1
@DavidScottKirby जावास्क्रिप्ट स्वचालित रूप से इन नंबरों को उनके निकटतम 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
पैट्रिक रॉबर्ट्स

96

आपको एक लूप का उपयोग करना चाहिए।

यहाँ दो संस्करणों को मानदंड की गणना करके 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 शानदार जवाब! यद्यपि संस्मरण उचित हो सकता है जब बड़ी संख्या के लिए भाज्य गणना करने के लिए कई कॉल होते हैं।
ताडेक

@ टैडेक, धन्यवाद। वास्तव में संस्मरण इस मामले में बहुत उपयोगी है और यही कारण है कि मार्गस का उत्तर सही एक के रूप में लिया गया है :)
गेब्रियल पेट्रीओली

पुनरावर्ती का 1-पंक्ति संस्करण: फ़ंक्शन फैक्टोरियल (संख्या) {वापसी (संख्या == 1)? संख्या: संख्या * तर्क। वर्ग (संख्या -1); }
jbyrd

2
@HWTech, आप तरीकों को कभी नहीं बुला रहे हैं। आपका परीक्षण दो तरीकों को परिभाषित करने की गति की तुलना करता है .. न कि उन्हें निष्पादित करने में लगने वाला समय .. यह एक बेहतर परीक्षा है (केवल 15 की
सच्चाई को आज़माते हुए

3
इसके बजाय rval = rval * i;आप लिख सकते हैंrval *= i;
रयान

29

मुझे अभी भी लगता है कि मार्गस का जवाब सबसे अच्छा है। हालाँकि, यदि आप 0 से 1 (यानी गामा फ़ंक्शन) के भीतर संख्याओं के भाज्य की गणना करना चाहते हैं, तो आप उस दृष्टिकोण का उपयोग नहीं कर सकते क्योंकि लुकअप तालिका में अनंत मान होंगे।

हालांकि, आप गुटों के मूल्यों को अनुमानित कर सकते हैं , और यह बहुत तेज़ है, तेज़ी से पुनरावर्ती रूप से खुद को कॉल करने या कम से कम लूप करने की तुलना में तेज़ है (विशेषकर जब मूल्य बड़े होने लगते हैं)।

एक अच्छा सन्निकटन विधि लैंकोज़ोस है

यहाँ जावास्क्रिप्ट में एक कार्यान्वयन है (एक कैलकुलेटर जिसे मैंने महीनों पहले लिखा था):

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), आदि। हालांकि सटीकता थोड़ी दूर हो सकती है, आखिरकार, यह परिणाम का एक अनुमान है।


काफी दिलचस्प दृष्टिकोण, धन्यवाद।
केन

बस मुझे एक टन बचा लिया, बहुत बहुत धन्यवाद :)
nicolaskruchten

मैं फॉर-लूप के नीचे के हिस्से को बदलने की सलाह देता हूं var d3d4 = Math.exp((z + 0.5) * Math.log(z + 5.5) - z - 5.5); return d1 * d2 * d3d4;। यह आपको 169 तक फैक्टरियल की गणना करने की अनुमति देता है! के बजाय वर्तमान में केवल 140 !. यह Numberडेटाटाइप का उपयोग करके अधिकतम प्रतिनिधित्व करने योग्य तथ्य के करीब है , जो कि 170 है!
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
फिल एच

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

दुर्भाग्य से, भले ही यह देखने में अच्छा हो और संक्षिप्त रूप में, यह इसे करने का सबसे धीमा तरीका है।
जिबरी

11

ES6 के साथ सिर्फ एक लाइन

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


factorial = n => n <= 1 ? 1 : factorial(n - 1) * n
नरसिम्ह

10

लघु और आसान पुनरावर्ती कार्य (आप इसे लूप के साथ भी कर सकते हैं, लेकिन मुझे नहीं लगता कि प्रदर्शन में कोई अंतर होगा):

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

मुझे लगता है कि सबसे अच्छा समाधान कैश्ड मूल्यों का उपयोग करना होगा, जैसा कि मार्गस ने उल्लेख किया है और बड़े मूल्यों के लिए स्टर्लिंग के सन्निकटन का उपयोग किया है (माना कि आपको वास्तव में तेजी से होना है और ऐसी बड़ी संख्याओं पर सटीक होना जरूरी नहीं है )।


3
टेल कॉल ऑप्टिमाइज़ेशन के बिना भाषाओं में (अर्थात सबसे अधिक उपयोग की जाने वाली भाषाएँ) गैर-पुनरावर्ती कार्यान्वयन का उपयोग करना बेहतर होता है जहाँ ऐसा करना आसान होता है, हालाँकि इसके आस-पास तरीके भी हैं: paulbarry.com/articles/2009/08/30 / टेल-कॉल-ऑप्टिमाइज़ेशन
डैनियल ईयरविकर

यह वास्तव में निश्चित रूप से सबसे तेज़ नहीं है, क्योंकि यह TCO का उपयोग नहीं करेगा, यदि इसे लागू किया गया था। लेकिन यह आसान है और मैं इसे कम नहीं करूंगा। यह सुनिश्चित करने के लिए सबसे तेज़ नहीं है।
haylem

इस फ़ंक्शन के लिए टेल कॉल ऑप्टिमाइज़ेशन भी संभव नहीं है, क्योंकि पुनरावर्ती कॉल पूंछ की स्थिति में नहीं है।
फ्रेड फू

3
@ जोश, (
डाउनवॉटर

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 में पुनरावर्ती संस्करण की तुलना में मेरी मशीन पर लगभग 25x तेज़ और 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)
  • केवल दो मापदंडों nऔरr उपयोग किया जाता है, इसलिए सिद्धांत रूप में कम मापदंडों का मतलब स्मृति को आवंटित करने में कम समय खर्च करना है
  • एक डीरेक्टेड लूप का उपयोग करता है जो चेक करता है कि nक्या शून्य है - मैंने उन सिद्धांतों को सुना है जो बाइनरी संख्या (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];

आप या तो कैश को प्री-भर सकते हैं, या कॉल के चलते इसे भरने की अनुमति दे सकते हैं। लेकिन प्रारंभिक तत्व (तथ्य के लिए) मौजूद होना चाहिए या यह टूट जाएगा।

का आनंद लें :)


4

ईएस 6 का उपयोग करना बहुत सरल है

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

एक उदाहरण यहाँ देखें



4

ES6 का उपयोग करके आप इसे तेज और संक्षिप्त दोनों प्राप्त कर सकते हैं:

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

3

तथ्यात्मक गणना करने के लिए कोड आपकी आवश्यकताओं पर निर्भर करता है।

  1. क्या आप अतिप्रवाह के बारे में चिंतित हैं?
  2. आपके पास इनपुट की कितनी सीमा होगी?
  3. क्या आपके लिए आकार या समय को कम करना अधिक महत्वपूर्ण है?
  4. आप इस तथ्य के साथ क्या करने जा रहे हैं?

अंक 1 और 4 के संबंध में, लॉग का मूल्यांकन करने के लिए कार्य करना अक्सर अधिक उपयोगी होता है फैक्टरियल का न कि स्वयं फैक्टरियल का मूल्यांकन करने के लिए फ़ंक्शन के बजाय।

यहाँ एक ब्लॉग पोस्ट है जो इन मुद्दों पर चर्चा करता है। यहाँ लॉग फैक्टर की गणना के लिए कुछ C # कोड है जो जावास्क्रिप्ट में पोर्ट के लिए तुच्छ होगा। लेकिन यह ऊपर दिए गए प्रश्नों के आपके उत्तरों के आधार पर आपकी आवश्यकताओं के लिए सर्वोत्तम नहीं हो सकता है।


क्रमांकित सूची शायद टिप्पणियों में होनी चाहिए। जो कुछ बचा है वह दो लिंक हैं, और लिंक-केवल उत्तर हतोत्साहित हैं।
बरेट

3

यह एक कॉम्पैक्ट लूप-आधारित संस्करण है

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

या आप मैथ ऑब्जेक्ट (पुनरावर्ती संस्करण) को ओवरराइड कर सकते हैं:

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

या दोनों दृष्टिकोणों से जुड़ें ...


1
मैंने इसे उपरोक्त कोड के अंदर तय किया। धन्यवाद!
सांड्रो रोजा

3

इस तथ्य को उजागर करते हुए कि Number.MAX_VALUE < 171!, हम केवल एक पूर्ण लुकअप तालिका का उपयोग कर सकते हैं, जिसमें केवल 171 कॉम्पैक्ट सरणी तत्वों से मिलकर 1.4 किलोबाइट से कम मेमोरी ली जा सकती है।

रनटाइम कॉम्प्लेक्सिटी ओ (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डेटाटाइप का उपयोग करते हुए जितना सटीक और उतना ही तेज़ है । जावास्क्रिप्ट में लुकअप टेबल की गणना - जैसा कि कुछ अन्य उत्तर बताते हैं - जब सटीकता कम हो जाएगी n! > Number.MAX_SAFE_INTEGER

Gzip के माध्यम से रनटाइम टेबल को कंप्रेस करने से डिस्क पर इसका आकार लगभग 3.6 से 1.8 किलोबाइट तक कम हो जाता है।


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सुरक्षा के लिए निष्क्रिय तथ्य

समाधान का उपयोग करता है BigInt, एक ईएस 2018 + / 2019 सुविधा।

यह काम कर रहे उदाहरण का उपयोग करता है BigInt, क्योंकि यहां कई जवाब सभी 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जब तक आप स्पष्ट रूप से उन्हें मजबूर, और ऐसा करने सटीकता में कमी का कारण बनेगा।

3

ES6 सुविधाओं का उपयोग करते हुए, एक पंक्ति और पुनरावृत्ति के बिना कोड लिख सकते हैं :

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


2

पूर्णता के लिए, यहां एक पुनरावर्ती संस्करण है जो पूंछ कॉल अनुकूलन की अनुमति देगा। मुझे यकीन नहीं है अगर पूंछ कॉल अनुकूलन अनुकूलन जावास्क्रिप्ट में किया जाता है, हालांकि ..

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.factorial(100); Math.factorial(500);में उपप्रकारों के लिए संस्मरण का पूर्ण लाभ नहीं उठाता है - उदाहरण के लिए, दो बार 1..100 गुणा की गणना करेगा।
बरेट

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

n * (n-1) * (n-2) * ... * 1दूसरे तरीके के बजाय अपने गुणन को शुरू करने से, आप n> 20 के लिए परिशुद्धता में 4 अंकों तक ढीले हो जाते हैं।
le_m

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 मानों को चलाने से आधुनिक ब्राउज़रों में उप-मिलीसेकंड समय लगेगा।


मुझे लगा कि 21 के बाद! संख्या विश्वसनीय नहीं है।
ऑटोस्पेन्ज

@ ऑटो इसलिए 21! > Number.MAX_SAFE_INTEGER, क्योंकि इस प्रकार सुरक्षित रूप से 64-बिट फ्लोट के रूप में प्रतिनिधित्व नहीं किया जा सकता है।
le_m

2

यहां एक कार्यान्वयन है जो सकारात्मक और नकारात्मक दोनों प्रकार के तथ्य की गणना करता है। यह तेज और सरल है।

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

आमतौर पर, एन! n <0 के लिए परिभाषित नहीं किया गया है। देखें mathoverflow.net/questions/10124/the-factorial-of-1-2-3
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
अगर (n> 170) e = इन्फिनिटी। और आपका कोड एक बड़ी संख्या उत्पन्न करेगा। वहाँ कोई अतिप्रवाह नहीं होगा?
प्राइम

के लिए गलत परिणाम 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;
});

अन्य सदस्यों से इनपुट की समीक्षा करने के बाद (लॉग सलाह को छोड़कर, हालांकि मैं इसे बाद में लागू कर सकता हूं) मैं आगे बढ़ा और एक स्क्रिप्ट को फेंक दिया जो काफी सरल है। मैंने एक साधारण अशिक्षित जावास्क्रिप्ट OOP उदाहरण के साथ शुरुआत की और factorials को संभालने के लिए एक छोटा वर्ग बनाया। फिर मैंने ऊपर दिए गए मेमोइज़ेशन के अपने संस्करण को लागू किया। मैंने शॉर्टहैंड फैक्ट्रीलाइज़ेशन भी लागू किया, हालांकि मैंने एक छोटी सी त्रुटि समायोजन की; मैंने "n <2" को "n <3" में बदल दिया। "n <2" अभी भी n = 2 को संसाधित करेगा जो एक बेकार होगा, क्योंकि आप 2 * 1 = 2 के लिए पुनरावृति करेंगे; यह मेरी राय में एक बेकार है। मैंने इसे "n <3" में बदल दिया; क्योंकि यदि n 1 या 2 है तो यह केवल n पर वापस आ जाएगा, यदि यह 3 या अधिक है तो यह सामान्य रूप से मूल्यांकन करेगा। बेशक, नियम लागू होने के बाद, मैंने अपने कार्यों को ग्रहण किए गए क्रियान्वयन के अवरोही क्रम में रखा। मैंने मेम (ईडी) और सामान्य निष्पादन के बीच त्वरित फेरबदल की अनुमति देने के लिए बूल (सच | गलत) विकल्प में जोड़ा (आप "शैली को बदलने की आवश्यकता के बिना अपने पेज पर जब आप स्वैप करना चाहते हैं, तो आप कभी नहीं जान सकते) जैसा कि मैंने पहले कहा था। ज्ञापन वाले भाज्य चर को 3 प्रारंभिक स्थितियों के साथ सेट किया जाता है, 4 वर्णों को लिया जाता है, और व्यर्थ गणनाओं को न्यूनतम किया जाता है। तीसरी पुनरावृत्ति के पूर्व का सब कुछ आप दोहरे अंकों के गणित से जोड़ रहे हैं। यदि आप इसके बारे में पर्याप्त रूप से एक स्टैक्लर लगाते हैं, तो आप यह जानेंगे कि आप एक तथ्यात्मक तालिका (जैसा लागू हो) पर चलेंगे। 4 वर्ण लेना, और व्यर्थ गणना को कम करना। तीसरी पुनरावृत्ति के पूर्व का सब कुछ आप दोहरे अंकों के गणित से जोड़ रहे हैं। यदि आप इसके बारे में पर्याप्त रूप से एक स्टैक्लर लगाते हैं, तो आप यह जानेंगे कि आप एक तथ्यात्मक तालिका (जैसा लागू हो) पर चलेंगे। 4 वर्ण लेना, और व्यर्थ गणना को कम करना। तीसरी पुनरावृत्ति के पूर्व का सब कुछ आप दोहरे अंकों के गणित से जोड़ रहे हैं। यदि आप इसके बारे में पर्याप्त रूप से एक स्टैक्लर लगाते हैं, तो आप यह जानेंगे कि आप एक तथ्यात्मक तालिका (जैसा लागू हो) पर चलेंगे।

मैंने इसके बाद क्या योजना बनाई है? स्थानीय और सत्र भंडारण, आवश्यक पुनरावृत्तियों के मामले कैश द्वारा एक मामले के लिए अनुमति देने के लिए, आवश्यक रूप से ऊपर "तालिका" समस्या को संभाल रहा है। यह बड़े पैमाने पर डेटाबेस और सर्वर साइड स्पेस को भी बचाएगा। हालाँकि, यदि आप लोकलस्टोरेज के साथ जाते हैं, तो आप अनिवार्य रूप से अपने यूजर्स के कंप्यूटर पर जगह की संख्या की एक सूची को स्टोर करने के लिए और उनके स्क्रीन को तेजी से बनाने के लिए स्पेस चूस रहे होंगे, हालांकि एक लंबे समय से अधिक समय तक इसकी जरूरत धीमी रहेगी। मुझे लगता है कि सेशनस्टोरेज (टैब पत्तियों के बाद समाशोधन) एक बेहतर मार्ग होगा। संभवतः इसे एक आत्म संतुलन सर्वर / स्थानीय निर्भर कैश के साथ संयोजित करें? उपयोगकर्ता 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);
});

यह एक और स्टैक सुझाव को कार्यान्वित करता है और मुझे फंक्शन को तथ्यात्मक (सत्य) (5) के रूप में कॉल करने की अनुमति देता है, जो कि मेरे लक्ष्यों में से एक था। : 3 मैंने कुछ अनावश्यक असाइनमेंट भी निकाले, और कुछ गैर-सार्वजनिक चर नामों को शॉर्टहैंड किया।


undefined0 के लिए रिटर्न !. ES6 के isNumericसाथ बदलने की अनुमति देता है Number.isInteger। जैसी लाइनें factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);पूरी तरह से अपठनीय हैं।
le_m

2

यहाँ एक नया जावास्क्रिप्ट फंक्शन फिल , मैप , कम और कंस्ट्रक्टर (और फैट एरो सिंटैक्स) का उपयोग किया जाता है:

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

संपादित करें: n === 0 को संभालने के लिए अद्यतन किया गया


2
यह कोड की गंभीर रूप से बदसूरत अपठनीय रेखा है।
जंगलबेदेव

1
यह एक साफ विचार है। लंबाई को दो बार ट्रेस करने के बजाय, सभी लॉजिक को कम फंक्शन में क्यों न कन्वर्ट करें और एज केस को हैंडल करने के लिए इसका शुरुआती मूल्य इस्तेमाल करें n === 0? Math.factorial = n => Array.from({ length: n }).reduce((product, _, i) => product * (i + 1), 1)
एलेक्सशैरेगन

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

2
StackOverflow में आपका स्वागत है और आपकी मदद के लिए धन्यवाद। आप कुछ स्पष्टीकरण जोड़कर अपने उत्तर को और बेहतर बनाना चाहते हैं।
एलियास एमपी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.