Какова самая быстрая факториальная функция в JavaScript?

Ищете действительно быструю реализацию факториальной функции в JavaScript. Есть предложения?

Ответ 1

Вы можете искать (1... 100)! на WolframAlpha, чтобы предварительно вычислить факториальную последовательность.

Первые 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

Если вы все еще хотите сами рассчитать значения, вы можете использовать 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;
} ​

Изменить: 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

Ответ 2

Вы должны использовать цикл.

Вот две версии, которые оцениваются путем вычисления факториала 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;
}

Live at: http://jsfiddle.net/xMpTv/

Мои результаты показывают:
- Рекурсивный ~ 150 миллисекунд

- Итеративный ~ 5 миллисекунд..

Ответ 3

Я все еще думаю, что ответ Маргуса самый лучший. Однако, если вы хотите рассчитать факториалы чисел в диапазоне от 0 до 1 (т.е. Гамма-функцию), то вы не сможете использовать этот подход, потому что таблица поиска должна содержать бесконечные значения.

Однако вы можете аппроксимировать значения факториалов, и это довольно быстро, быстрее, чем рекурсивно вызывать себя или, по крайней мере, зацикливать (особенно когда значения начинают увеличиваться).

Хорошим методом приближения является Lanczos one

Вот реализация в 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) и т.д., однако точность может быть немного невысокой, в конце концов, это приближение результата.

Ответ 4

Таблица поиска - это очевидный путь, если вы работаете с натуральными числами. Чтобы вычислить любой факториал в режиме реального времени, вы можете ускорить его с помощью кеша, сохранив числа, которые вы рассчитали ранее. Что-то вроде:

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

Вы можете предварительно вычислить некоторые значения, чтобы ускорить его еще больше.

Ответ 5

Вот мое решение:

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

Это самый простой способ (меньше символов/строк), который я нашел, только функция с одной строкой кода.


Изменить:
Если вы действительно хотите сохранить несколько символов, вы можете воспользоваться функцией Arrow (21 байт):

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

Ответ 6

короткая и простая рекурсивная функция (вы тоже можете сделать это с помощью цикла, но я не думаю, что это повлияло бы на производительность):

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

для очень большого n, вы можете использовать аппликация завитушек - но это даст вам приблизительное значение.

РЕДАКТИРОВАТЬ: комментарий о том, почему я получаю downvote для этого, было бы хорошо...

EDIT2: это будет использование души, используя цикл (который будет лучшим выбором):

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

Я думаю, что лучшим решением было бы использовать кешированные значения, как упоминал Маргус, и использовать аппликацию завитушек для больших значений (предполагается, что у вас есть быть очень быстрыми и не обязательно быть такими точными на таких больших числах).

Ответ 7

Вот, memoizer, который принимает любую функцию с одним аргументом и запоминает ее. Оказывается, это будет немного быстрее, чем @xPheRe решение, включая ограничение на размер кеша и связанную проверку, потому что я использую shortcircuiting и т.д.

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

Примерно в 25 раз быстрее на моей машине в Chrome, чем в рекурсивной версии, и на 10% быстрее, чем у xPheRe.

Ответ 8

Только одна строка с ES6

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

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


function print(value) {
  document.querySelector('.result').innerHTML = value;
}
.result {
  margin-left: 10px;
}
<input onkeyup="print(factorial(this.value))" type="number"/>

<span class="result">......</span>

Ответ 9

Я столкнулся с этим сообщением. Вдохновленный всеми вкладами здесь, я придумал свою собственную версию, которая имеет две функции, о которых я не видел раньше: 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];

Вы можете либо предварительно заполнить кеш, либо разрешить его заполнение при прохождении вызовов. Но исходный элемент (для факта (0) должен присутствовать или он сломается.

Наслаждайтесь:)

Ответ 10

Это очень просто, используя ES6

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

Смотрите пример здесь

Ответ 11

Вот одно из решений:

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

Ответ 12

Используя ES6, вы можете добиться этого как быстро, так и за короткое время:

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

Ответ 13

Самая быстрая факториальная функция

Я думаю, что эта основанная на циклах версия может быть самой быстрой факториальной функцией.

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), чем они проверяют другие целые числа

Ответ 14

Код для расчета факториала зависит от ваших требований.

  • Вы обеспокоены переполнением?
  • Какой диапазон входных данных у вас будет?
  • Чем важнее для вас минимизировать размер или время?
  • Что вы собираетесь делать с факториалом?

Что касается точек 1 и 4, часто более полезно иметь функцию для оценки логарифма факториала напрямую, а не для того, чтобы иметь функцию для оценки самого факториала.

Здесь сообщение в блоге, в котором обсуждаются эти проблемы. Вот несколько код С# для вычисления факториала журнала, который был бы тривиальным для переноса на JavaScript. Но это может быть не лучшим для ваших нужд, в зависимости от ваших ответов на вопросы выше.

Ответ 15

Это компактная версия на основе цикла

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

Или присоедините оба подхода...

Ответ 16

Используя тот факт, что Number.MAX_VALUE < 171!, мы можем просто использовать полную таблицу поиска, состоящую всего из 171 компактных элементов массива, занимающих менее 1,4 килобайта памяти.

Быстрая функция поиска со сложностью выполнения 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

Ответ 17

Один ответ:

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

Ответ 18

Итерационный BigInt с BigInt для безопасности

Решение использует BigInt, ES 2018+/2019.

Этот рабочий пример использует BigInt, потому что многие ответы здесь полностью 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 если вы явно не принуждаете их, и это может привести к потере точности.

Ответ 19

Просто для полноты, вот рекурсивная версия, которая позволила бы оптимизация хвостовых вызовов. Я не уверен, что оптимизация хвостового вызова выполняется в JavaScript, хотя...

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

Чтобы вызвать его:

rFact(x, 1);

Ответ 20

Это итеративное решение, которое использует меньше пространства стека и сохраняет ранее вычисленные значения самопомощи:

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, который является литералом объекта, поэтому прототипа нет. Скорее просто привязывая их к функции напрямую.

Ответ 21

Я считаю, что следующая наиболее устойчивая и эффективная часть кода из комментариев выше. Вы можете использовать это в своей глобальной архитектуре 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;
};

Ответ 22

// 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 значений в современных браузерах займет субмиллисекундное время.

Ответ 23

Вот реализация, которая вычисляет как положительные, так и отрицательные факториалы. Это быстро и просто.

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

Ответ 24

Здесь я сделал сам, не пользуюсь цифрами более 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;
}

Ответ 25

Вот мой код

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

Ответ 26

Кэшированный цикл должен быть самым быстрым (по крайней мере, когда вызывается несколько раз)

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

Ответ 27

Вот один из них, в котором используются более новые функции javascript fill, map, уменьшить и конструктор (и синтаксис толстой стрелки):

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

Изменить: обновлено для обработки n === 0

Ответ 28

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, хотя я могу это реализовать позже), я пошел вперед и бросил вместе script, что довольно просто. Я начал с простого необразованного примера JavaScript OOP и построил небольшой класс для обработки факториалов. Затем я внедрил мою версию Memoization, которая была предложена выше. Я также реализовал сокращенную факториализацию, однако я сделал небольшую корректировку ошибок; Я изменил "n < 2" на "n < 3". "n < 2" все равно будет обрабатывать n = 2, что будет представлять собой отходы, потому что вы будете перебирать 2 * 1 = 2; на мой взгляд, это пустая трата. Я изменил его на "n < 3"; потому что если n равно 1 или 2, оно просто вернет n, если оно равно 3 или более, оно будет нормально оцениваться. Конечно, по мере применения правил я поместил свои функции в порядке убывания предполагаемого исполнения. Я добавил параметр bool (true | false), чтобы разрешить быстрое изменение между записью и нормальным исполнением (вы просто не знаете, когда вы хотите обмениваться на своей странице, не меняя "стиль" ) Как я уже говорил, переменная memoized factorials устанавливается с 3 начальными позициями, взяв 4 символа и минимизируя расточительные вычисления. Все, что прошло после третьей итерации, вы используете для вычисления двузначной математики плюс. Я полагаю, если вы, где достаточно пристально, расскажете об этом на факториальной таблице (как реализовано).

Что я запланировал после этого? local & | session storage, чтобы обеспечить кэш-память нужных итераций в каждом конкретном случае, в основном обрабатывая проблему "таблицы", упомянутую выше. Это также будет значительно экономить пространство базы данных и сервера. Однако, если вы идете с localStorage, вы, по сути, будете всасывать пространство на вашем компьютере пользователя, просто чтобы сохранить список номеров и сделать их экран более быстрым, однако в течение длительного периода времени с огромной потребностью это было бы медленным. Я думаю, что sessionStorage (очистка после вкладок Tab) будет намного лучшим маршрутом. Возможно, это сочетается с автономным балансирующим сервером/локальным кэшем? Пользователь A нуждается в итерациях X. Пользователь B нуждается в итерациях. 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);
});

Это редактирование реализует другое предложение Stack и позволяет мне вызвать функцию как factorial (true) (5), что было одной из моих целей.: 3 Я также удалил ненужное назначение и сократил некоторые имена непубличных переменных.

Ответ 29

Используя функции ES6, вы можете написать код в ОДНОЙ строке & без рекурсии :

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

Ответ 30

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