Ищете действительно быструю реализацию функции факториала в JavaScript. Есть предложения?
Ищете действительно быструю реализацию функции факториала в JavaScript. Есть предложения?
Ответы:
Вы можете искать (1 ... 100)! на Wolfram | Alpha для предварительного вычисления факториальной последовательности.
Первые 100 чисел:
1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000, 51090942171709440000, 1124000727777607680000, 25852016738884976640000, 620448401733239439360000, 15511210043330985984000000, 403291461126605635584000000, 10888869450418352160768000000, 304888344611713860501504000000, 8841761993739701954543616000000, 265252859812191058636308480000000, 8222838654177922817725562880000000, 263130836933693530167218012160000000, 8683317618811886495518194401280000000, 295232799039604140847618609643520000000, 10333147966386144929666651337523200000000, 371993326789901217467999448150835200000000, 13763753091226345046315979581580902400000000, 523022617466601111760007224100074291200000000, 20397882081197443358640281739902897356800000000, 815915283247897734345611269596115894272000000000, 33452526613163807108170062053440751665152000000000, 1405006117752879898543142606244511569936384000000000, 60415263063373835637355132068513997507264512000000000, 2658271574788448768043625811014615890319638528000000000, 119622220865480194561963161495657715064383733760000000000, 5502622159812088949850305428800254892961651752960000000000, 258623241511168180642964355153611979969197632389120000000000, 12413915592536072670862289047373375038521486354677760000000000, 608281864034267560872252163321295376887552831379210240000000000, 30414093201713378043612608166064768844377641568960512000000000000, 1551118753287382280224243016469303211063259720016986112000000000000, 80658175170943878571660636856403766975289505440883277824000000000000, 4274883284060025564298013753389399649690343788366813724672000000000000, 230843697339241380472092742683027581083278564571807941132288000000000000, 12696403353658275925965100847566516959580321051449436762275840000000000000, 710998587804863451854045647463724949736497978881168458687447040000000000000, 40526919504877216755680601905432322134980384796226602145184481280000000000000, 2350561331282878571829474910515074683828862318181142924420699914240000000000000, 138683118545689835737939019720389406345902876772687432540821294940160000000000000, 8320987112741390144276341183223364380754172606361245952449277696409600000000000000, 507580213877224798800856812176625227226004528988036003099405939480985600000000000000, 31469973260387937525653122354950764088012280797258232192163168247821107200000000000000, 1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000, 126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000, 8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000, 544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000, 36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000, 2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000, 171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000, 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000, 850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000, 61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000, 4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000, 330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000, 24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000, 1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000, 145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000, 11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000, 894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000, 71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000, 5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000, 475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000, 39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000, 3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000, 281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000, 24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000, 2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000, 185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000, 16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000, 1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000, 135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000, 12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000, 1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000, 108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000, 10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000, 991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000, 96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000, 9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000, 933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Если вы все еще хотите вычислить значения самостоятельно, вы можете использовать мемоизацию :
var f = [];
function factorial (n) {
if (n == 0 || n == 1)
return 1;
if (f[n] > 0)
return f[n];
return f[n] = factorial(n-1) * n;
}
Я подумал, что было бы полезно добавить рабочий пример ленивой итеративной факториальной функции, которая использует большие числа для получения точного результата с мемоизацией и кешем для сравнения.
var f = [new BigNumber("1"), new BigNumber("1")];
var i = 2;
function factorial(n)
{
if (typeof f[n] != 'undefined')
return f[n];
var result = f[i-1];
for (; i <= n; i++)
f[i] = result = result.multiply(i.toString());
return result;
}
var cache = 100;
// Due to memoization, following line will cache first 100 elements.
factorial(cache);
Я предполагаю, что вы использовали бы какое-то закрытие, чтобы ограничить видимость имени переменной.
function factorial (n) { for (var i = f.length; i <= n; i++) f.push(f[i - 1].multiply(i.toString())); return f[n]; }
увидеть также мой ответ, в котором используется более поздняя встроенная, BigInt
а не сторонняя библиотека.
Вам следует использовать петлю.
Вот две версии, протестированные путем вычисления факториала 100 в 10.000 раз.
Рекурсивный
function rFact(num)
{
if (num === 0)
{ return 1; }
else
{ return num * rFact( num - 1 ); }
}
Итеративный
function sFact(num)
{
var rval=1;
for (var i = 2; i <= num; i++)
rval = rval * i;
return rval;
}
Жить в : http://jsfiddle.net/xMpTv/
Мои результаты показывают:
- Рекурсивный ~ 150 миллисекунд
- Итеративный ~ 5 миллисекунд ..
rval = rval * i;
вас можно было написатьrval *= i;
Я по-прежнему считаю, что ответ Маргуса лучший. Однако, если вы хотите вычислить факториалы чисел в диапазоне от 0 до 1 (т.е. гамма-функцию), вы не можете использовать этот подход, потому что таблица поиска должна содержать бесконечные значения.
Однако вы можете аппроксимировать значения факториалов, и это довольно быстро, быстрее, чем рекурсивный вызов самого себя или, по крайней мере, цикл (особенно, когда значения начинают увеличиваться).
Хороший метод приближения - метод Ланцоша.
Вот реализация на JavaScript (перенесенная с калькулятора, который я написал несколько месяцев назад):
function factorial(op) {
// Lanczos Approximation of the Gamma Function
// As described in Numerical Recipes in C (2nd ed. Cambridge University Press, 1992)
var z = op + 1;
var p = [1.000000000190015, 76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 1.208650973866179E-3, -5.395239384953E-6];
var d1 = Math.sqrt(2 * Math.PI) / z;
var d2 = p[0];
for (var i = 1; i <= 6; ++i)
d2 += p[i] / (z + i);
var d3 = Math.pow((z + 5.5), (z + 0.5));
var d4 = Math.exp(-(z + 5.5));
d = d1 * d2 * d3 * d4;
return d;
}
Теперь вы можете делать такие крутые вещи, как factorial(0.41)
и т. Д., Но точность может быть немного неточной, в конце концов, это приблизительное значение результата.
var d3d4 = Math.exp((z + 0.5) * Math.log(z + 5.5) - z - 5.5); return d1 * d2 * d3d4;
. Это позволяет вам вычислять факториалы до 169! вместо нынешних всего 140 !. Это довольно близко к максимально представимому факториалу с использованием Number
типа данных, который равен 170 !.
Таблица поиска - очевидный путь, если вы работаете с натуральными числами. Чтобы вычислить любой факториал в реальном времени, вы можете ускорить его с помощью кеша, сохранив числа, которые вы вычисляли ранее. Что-то типа:
factorial = (function() {
var cache = {},
fn = function(n) {
if (n === 0) {
return 1;
} else if (cache[n]) {
return cache[n];
}
return cache[n] = n * fn(n -1);
};
return fn;
})();
Вы можете предварительно рассчитать некоторые значения, чтобы ускорить его еще больше.
Вот мое решение:
function fac(n){
return(n<2)?1:fac(n-1)*n;
}
Это самый простой способ (меньше символов / строк), который я нашел, только функция с одной строкой кода.
Изменить:
если вы действительно хотите сохранить несколько символов, вы можете использовать стрелки (21 байт) :
f=n=>(n<2)?1:f(n-1)*n
f=n=>n?f(n-1)*n:1
...
Всего одна линия с ES6
const factorial = n => !(n > 1) ? 1 : factorial(n - 1) * n;
factorial = n => n <= 1 ? 1 : factorial(n - 1) * n
короткая и простая рекурсивная функция (вы тоже можете сделать это с помощью цикла, но я не думаю, что это повлияет на производительность):
function factorial (n){
if (n==0 || n==1){
return 1;
}
return factorial(n-1)*n;
}
для очень больших n вы можете использовать приближение Стиллингса, но это даст вам только приблизительное значение.
РЕДАКТИРОВАТЬ: комментарий о том, почему я получаю отрицательный голос за это, было бы неплохо ...
РЕДАКТИРОВАТЬ2: это было бы сутью с использованием цикла (что было бы лучшим выбором):
function factorial (n){
j = 1;
for(i=1;i<=n;i++){
j = j*i;
}
return j;
}
Я думаю , что лучшим решением было бы использовать кэшированные значения, как уже упоминалось Маргус и использовать приближение stirlings для больших значений (предполагается , что вы должны быть действительно быстро и не должны быть , что точно на таких больших чисел).
Взгляните на мемоизатор, который принимает любую функцию с одним аргументом и запоминает ее. Оказывается, он немного быстрее, чем решение @ xPheRe , включая ограничение на размер кеша и связанную проверку, потому что я использую сокращение и так далее.
function memoize(func, max) {
max = max || 5000;
return (function() {
var cache = {};
var remaining = max;
function fn(n) {
return (cache[n] || (remaining-- >0 ? (cache[n]=func(n)) : func(n)));
}
return fn;
}());
}
function fact(n) {
return n<2 ? 1: n*fact(n-1);
}
// construct memoized version
var memfact = memoize(fact,170);
// xPheRe's solution
var factorial = (function() {
var cache = {},
fn = function(n) {
if (n === 0) {
return 1;
} else if (cache[n]) {
return cache[n];
}
return cache[n] = n * fn(n -1);
};
return fn;
}());
Примерно в 25 раз быстрее на моей машине в Chrome, чем рекурсивная версия, и на 10% быстрее, чем у xPheRe.
Я думаю, что эта версия на основе цикла может быть самой быстрой факториальной функцией.
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), чем другие целые числа.Я наткнулся на этот пост. Вдохновленный всеми представленными здесь материалами, я придумал свою собственную версию, в которой есть две функции, которые я раньше не видел: 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) должен присутствовать, иначе он сломается.
Наслаждаться :)
Вот одно из решений:
function factorial(number) {
total = 1
while (number > 0) {
total *= number
number = number - 1
}
return total
}
Используя ES6, вы можете добиться этого быстро и быстро:
const factorial = n => [...Array(n + 1).keys()].slice(1).reduce((acc, cur) => acc * cur, 1)
Код для вычисления факториала зависит от ваших требований.
Что касается пунктов 1 и 4, часто бывает более полезно иметь функцию для оценки журнала факториала напрямую, чем иметь функцию для оценки самого факториала.
Вот сообщение в блоге, в котором обсуждаются эти проблемы. Вот некоторый код C # для вычисления лог-факториала, который было бы тривиально перенести на JavaScript. Но это может не подходить для ваших нужд в зависимости от ваших ответов на вопросы выше.
Это компактная версия на основе петель
function factorial( _n )
{
var _p = 1 ;
while( _n > 0 ) { _p *= _n-- ; }
return _p ;
}
Или вы можете переопределить объект Math (рекурсивная версия):
Math.factorial = function( _x ) { return _x <= 1 ? 1 : _x * Math.factorial( --_x ) ; }
Или присоединитесь к обоим подходам ...
Воспользовавшись тем фактом, что Number.MAX_VALUE < 171!
мы можем просто использовать полную таблицу поиска, состоящую всего из 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
Это так же точно и быстро, как и при использовании Number
типа данных. Вычисление таблицы поиска в Javascript - как предлагают некоторые другие ответы - снизит точность, когда n! > Number.MAX_SAFE_INTEGER
.
Сжатие таблицы времени выполнения с помощью gzip уменьшает ее размер на диске примерно с 3,6 до 1,8 килобайт.
Однострочный ответ:
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
для безопасностиРешение использует
BigInt
функцию ES 2018 + / 2019.
Это рабочий пример использования BigInt
, потому что многие ответы здесь почти сразу выходят за безопасную границу Number
(MDN). Это не самый быстрый, но простой и, следовательно, более понятный способ адаптации других оптимизаций (например, кеш первых 100 чисел).
function factorial(nat) {
let p = BigInt(1)
let i = BigInt(nat)
while (1 < i--) p *= i
return p
}
// 9.332621544394415e+157
Number(factorial(100))
// "933262154439441526816992388562667004907159682643816214685929638952175999
// 932299156089414639761565182862536979208272237582511852109168640000000000
// 00000000000000"
String(factorial(100))
// 9332621544394415268169923885626670049071596826438162146859296389521759999
// 3229915608941463976156518286253697920827223758251185210916864000000000000
// 000000000000n
factorial(100)
n
в конце числового литерала как 1303n
указывает на BigInt
тип.BigInt
с, Number
если вы явно не принуждаете их, и это может привести к потере точности.Используя функции ES6, можно писать код в ОДНОЙ строке и без рекурсии :
var factorial=(n)=>Array.from({length: n},(v, k) => k+1).reduce((a, b) => a*b, 1)
Просто для полноты, вот рекурсивная версия, которая позволяет оптимизировать хвостовой вызов. Я не уверен, что оптимизация хвостовых вызовов выполняется в JavaScript ...
function rFact(n, acc)
{
if (n == 0 || n == 1) return acc;
else return rFact(n-1, acc*n);
}
Чтобы назвать это:
rFact(x, 1);
Это итеративное решение, использующее меньше места в стеке и сохраняющее ранее вычисленные значения с возможностью самопоминания:
Math.factorial = function(n){
if(this.factorials[n]){ // memoized
return this.factorials[n];
}
var total=1;
for(var i=n; i>0; i--){
total*=i;
}
this.factorials[n] = total; // save
return total;
};
Math.factorials={}; // store
Также обратите внимание, что я добавляю это к объекту Math, который является литералом объекта, поэтому прототипа нет. Скорее просто привязывайте их к функции напрямую.
Math.factorial(100); Math.factorial(500);
дважды вычисляет умножение 1..100.
Я считаю, что следующий фрагмент кода является наиболее устойчивым и эффективным из приведенных выше комментариев. Вы можете использовать это в своей глобальной архитектуре js приложения ... и не беспокойтесь о том, чтобы писать его в нескольких пространствах имен (поскольку это задача, которая, вероятно, не требует значительного дополнения). Я включил два имени метода (в зависимости от предпочтений), но оба могут использоваться, поскольку они просто ссылки.
Math.factorial = Math.fact = function(n) {
if (isNaN(n)||n<0) return undefined;
var f = 1; while (n > 1) {
f *= n--;
} return f;
};
n * (n-1) * (n-2) * ... * 1
вместо наоборот, вы потеряете до 4 цифр в точности для n >> 20.
// 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! > Number.MAX_SAFE_INTEGER
, что , таким образом, его нельзя безопасно представить как 64-битное число с плавающей запятой.
Вот реализация, которая вычисляет как положительные, так и отрицательные факториалы. Это быстро и просто.
var factorial = function(n) {
return n > 1
? n * factorial(n - 1)
: n < 0
? n * factorial(n + 1)
: 1;
}
Вот один, который я сделал сам, не используйте числа больше 170 или меньше 2.
function factorial(x){
if((!(isNaN(Number(x)))) && (Number(x)<=170) && (Number(x)>=2)){
x=Number(x);for(i=x-(1);i>=1;--i){
x*=i;
}
}return x;
}
i
и выполняет слишком много Number
преобразований и дает неверные результаты для 0! (как вы сказали, но почему?).
Вот мой код
function factorial(num){
var result = num;
for(i=num;i>=2;i--){
result = result * (i-1);
}
return result;
}
factorial(0)
. Кроме того, начав умножение с n * (n-1) * (n-2) * ... * 1, а не наоборот, вы потеряете до 4 цифр в точности для n >> 20. @prime: 170! > Number.MAX_VALUE
и лучше всего представлен с помощью Infinity
.
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n)
}
Предоставляется http://javascript.info/tutorial/number-math как простой способ оценить, является ли объект правильным целым числом для расчета.
var factorials=[[1,2,6],3];
Простой набор мемоизированных факториалов, которые требуют избыточных вычислений, могут быть обработаны с помощью "умножения на 1" или представляют собой одну цифру, которая представляет собой простое уравнение, не стоящее обработки вживую.
var factorial = (function(memo,n) {
this.memomize = (function(n) {
var ni=n-1;
if(factorials[1]<n) {
factorials[0][ni]=0;
for(var factorial_index=factorials[1]-1;factorials[1]<n;factorial_index++) {
factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);
factorials[1]++;
}
}
});
this.factorialize = (function(n) {
return (n<3)?n:(factorialize(n-1)*n);
});
if(isNumeric(n)) {
if(memo===true) {
this.memomize(n);
return factorials[0][n-1];
}
return this.factorialize(n);
}
return factorials;
});
Изучив ввод от других участников (за исключением рекомендаций журнала, хотя я могу реализовать это позже), я пошел дальше и составил довольно простой сценарий. Я начал с простого необразованного примера ООП на JavaScript и построил небольшой класс для обработки факториалов. Затем я реализовал свою версию мемоизации, предложенную выше. Я также реализовал сокращенную факториализацию, но сделал небольшую корректировку ошибок; Я изменил «n <2» на «n <3». «n <2» по-прежнему будет обрабатывать n = 2, что было бы пустой тратой, потому что вы бы выполняли итерацию для 2 * 1 = 2; на мой взгляд, это бесполезная трата. Я изменил его на «n <3»; потому что, если n равно 1 или 2, он просто вернет n, если он равен 3 или более, он будет оцениваться нормально. Конечно, поскольку применяются правила, я разместил свои функции в порядке убывания предполагаемого выполнения. Я добавил опцию bool (true | false), чтобы разрешить быстрое переключение между memo'ed и нормальным выполнением (вы просто никогда не знаете, когда вы захотите поменять местами на своей странице, не изменяя «стиль»). Как я уже говорил перед Переменная memoized factorials задается с 3 начальными позициями, принимает 4 символа и сводит к минимуму бесполезные вычисления. После третьей итерации вы обрабатываете двузначный математический плюс. Я полагаю, если вы достаточно привержены этому, вы бы использовали факториальную таблицу (как реализовано). взяв 4 символа и минимизируя бесполезные вычисления. После третьей итерации вы обрабатываете двузначный математический плюс. Я полагаю, если вы достаточно привержены этому, вы бы использовали факториальную таблицу (как реализовано). взяв 4 символа и минимизируя бесполезные вычисления. После третьей итерации вы обрабатываете двузначный математический плюс. Я полагаю, если вы достаточно привержены этому, вы бы использовали факториальную таблицу (как реализовано).
Что я планировал после этого? локальное & | хранилище сеансов, чтобы обеспечить возможность кэширования необходимых итераций в каждом конкретном случае, по существу решая проблему "таблицы", о которой говорилось выше. Это также значительно сэкономит место на стороне базы данных и сервера. Однако, если вы выберете localStorage, вы, по сути, будете занимать место на своем компьютере пользователя, просто чтобы сохранить список чисел и заставить их экран СМОТРЕТЬ быстрее, однако в течение длительного периода времени с огромной потребностью это будет медленным. Я думаю, что sessionStorage (очистка после выхода вкладки) будет намного лучшим способом. Возможно ли совместить это с самобалансирующимся сервером / локальным зависимым кешем? Пользователю A нужно X итераций. Пользователю B нужно Y итераций. X + Y / 2 = сумма, необходимая для локального кеширования. Затем просто обнаруживайте и играйте с тестами времени загрузки и выполнения в реальном времени для каждого пользователя, пока он не настроится на оптимизацию для самого сайта. Благодарность!
Изменить 3:
var f=[1,2,6];
var fc=3;
var factorial = (function(memo) {
this.memomize = (function(n) {
var ni=n-1;
if(fc<n) {
for(var fi=fc-1;fc<n;fi++) {
f[fc]=f[fi]*(fc+1);
fc++;
}
}
return f[ni];
});
this.factorialize = (function(n) {
return (n<3)?n:(factorialize(n-1)*n);
});
this.fractal = (function (functio) {
return function(n) {
if(isNumeric(n)) {
return functio(n);
}
return NaN;
}
});
if(memo===true) {
return this.fractal(memomize);
}
return this.fractal(factorialize);
});
Это редактирование реализует другое предложение стека и позволяет мне вызывать функцию как factorial (true) (5), что было одной из моих целей. : 3 Я также удалил некоторые ненужные присвоения и сократил некоторые закрытые имена переменных.
undefined
за 0 !. ES6 позволяет заменить isNumeric
на Number.isInteger
. Строки вроде factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);
совершенно нечитаемы.
Вот один, использующий новые функции javascript fill , map , reduce и конструктор (и синтаксис жирной стрелки):
Math.factorial = n => n === 0 ? 1 : Array(n).fill(null).map((e,i)=>i+1).reduce((p,c)=>p*c)
Изменить: обновлено для обработки n === 0
n === 0
? Math.factorial = n => Array.from({ length: n }).reduce((product, _, i) => product * (i + 1), 1)
function computeFactorialOfN(n) {
var output=1;
for(i=1; i<=n; i++){
output*=i;
} return output;
}
computeFactorialOfN(5);