Mencari implementasi yang sangat cepat dari fungsi faktorial dalam JavaScript. Ada saran?
Mencari implementasi yang sangat cepat dari fungsi faktorial dalam JavaScript. Ada saran?
Jawaban:
Anda dapat mencari (1 ... 100)! di Wolfram | Alpha untuk menghitung sebelumnya urutan faktorial.
100 angka pertama adalah:
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
Jika Anda masih ingin menghitung nilainya sendiri, Anda dapat menggunakan 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;
}
Saya pikir akan berguna untuk menambahkan contoh kerja fungsi faktorial iteratif malas yang menggunakan angka besar untuk mendapatkan hasil yang tepat dengan memoization dan cache sebagai perbandingan
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);
Saya berasumsi Anda akan menggunakan semacam closure untuk membatasi visibilitas nama variabel.
function factorial (n) { for (var i = f.length; i <= n; i++) f.push(f[i - 1].multiply(i.toString())); return f[n]; }
Juga lihat jawaban saya yang menggunakan bawaan yang BigInt
lebih baru daripada perpustakaan pihak ketiga.
Anda harus menggunakan loop.
Berikut adalah dua versi yang diukur dengan menghitung faktorial 100 untuk 10.000 kali.
Rekursif
function rFact(num)
{
if (num === 0)
{ return 1; }
else
{ return num * rFact( num - 1 ); }
}
Iteratif
function sFact(num)
{
var rval=1;
for (var i = 2; i <= num; i++)
rval = rval * i;
return rval;
}
Langsung di: http://jsfiddle.net/xMpTv/
Hasil saya menunjukkan:
- Rekursif ~ 150 milidetik
- Iteratif ~ 5 milidetik ..
rval = rval * i;
Anda bisa menulisrval *= i;
Saya masih berpikir jawaban Margus adalah yang terbaik. Namun jika Anda ingin menghitung faktorial angka dalam rentang 0 hingga 1 (yaitu fungsi gamma) juga, Anda tidak dapat menggunakan pendekatan itu karena tabel pemeta harus berisi nilai tak hingga.
Namun, Anda dapat memperkirakan nilai faktorial, dan ini cukup cepat, lebih cepat daripada memanggil dirinya sendiri secara rekursif atau setidaknya mengulanginya (terutama ketika nilai mulai menjadi lebih besar).
Metode perkiraan yang baik adalah metode Lanczos
Berikut adalah implementasi dalam JavaScript (porting dari kalkulator yang saya tulis bulan lalu):
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;
}
Anda sekarang dapat melakukan hal-hal keren seperti factorial(0.41)
, dll. Namun, akurasinya mungkin sedikit salah, bagaimanapun juga, ini adalah perkiraan hasilnya.
var d3d4 = Math.exp((z + 0.5) * Math.log(z + 5.5) - z - 5.5); return d1 * d2 * d3d4;
. Ini memungkinkan Anda untuk menghitung faktorial hingga 169! bukannya saat ini hanya 140 !. Ini cukup dekat dengan faktorial terwakili maksimum yang menggunakan Number
tipe data, yaitu 170 !.
Tabel pemeta adalah cara yang tepat untuk digunakan, jika Anda menggunakan bilangan asli. Untuk menghitung faktorial apa pun secara real-time, Anda dapat mempercepatnya dengan cache, menyimpan angka-angka yang telah Anda hitung sebelumnya. Sesuatu seperti:
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;
})();
Anda dapat menghitung sebelumnya beberapa nilai untuk lebih mempercepatnya.
Inilah solusi saya:
function fac(n){
return(n<2)?1:fac(n-1)*n;
}
Ini adalah cara paling sederhana (lebih sedikit karakter / baris) yang saya temukan, hanya fungsi dengan satu baris kode.
Sunting:
Jika Anda benar-benar ingin menyimpan beberapa karakter, Anda dapat menggunakan Fungsi Panah (21 byte) :
f=n=>(n<2)?1:f(n-1)*n
f=n=>n?f(n-1)*n:1
...
Hanya Satu baris dengan ES6
const factorial = n => !(n > 1) ? 1 : factorial(n - 1) * n;
factorial = n => n <= 1 ? 1 : factorial(n - 1) * n
fungsi rekursif yang singkat dan mudah (Anda juga dapat melakukannya dengan loop, tetapi menurut saya itu tidak akan membuat perbedaan dalam performa):
function factorial (n){
if (n==0 || n==1){
return 1;
}
return factorial(n-1)*n;
}
untuk n yang sangat besar, Anda dapat menggunakan perkiraan putaran - tetapi itu hanya akan memberi Anda nilai perkiraan.
EDIT: komentar tentang mengapa saya mendapatkan suara negatif untuk ini akan menyenangkan ...
EDIT2: ini akan menjadi solusi jiwa menggunakan loop (yang akan menjadi pilihan yang lebih baik):
function factorial (n){
j = 1;
for(i=1;i<=n;i++){
j = j*i;
}
return j;
}
Saya pikir solusi terbaik adalah dengan menggunakan nilai-nilai cache, sebagai Margus disebutkan dan menggunakan Stirlings pendekatan untuk nilai-nilai yang lebih besar (diasumsikan Anda harus benar-benar cepat dan tidak harus yang sebenarnya di nomor besar seperti).
Lihatlah, memoizer, yang mengambil fungsi argumen tunggal dan mem-memoasinya. Ternyata sedikit lebih cepat dari solusi @ xPheRe , termasuk batas ukuran cache dan pemeriksaan terkait, karena saya menggunakan shortcircuiting dan sebagainya.
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;
}());
Kira-kira 25x lebih cepat pada mesin saya di Chrome daripada versi rekursif, dan 10% lebih cepat dari xPheRe.
Menurut saya, versi berbasis loop ini mungkin merupakan fungsi faktorial tercepat.
function factorial(n, r = 1) {
while (n > 0) r *= n--;
return r;
}
// Default parameters `r = 1`,
// was introduced in ES6
Dan inilah alasan saya:
for
loop dan while
loop memiliki kinerja yang serupa, for
loop tanpa ekspresi inisialisasi dan ekspresi akhir terlihat aneh; mungkin lebih baik untuk menulis for(; n > 0;)
sebagaiwhile(n > 0)
n
dan r
digunakan, jadi dalam teori lebih sedikit parameter berarti lebih sedikit waktu yang dihabiskan untuk mengalokasikan memorin
nol - Saya pernah mendengar teori bahwa komputer lebih baik dalam memeriksa bilangan biner (0 dan 1) daripada memeriksa bilangan bulat lainnyaSaya menemukan posting ini. Terinspirasi oleh semua kontribusi di sini saya datang dengan versi saya sendiri, yang memiliki dua fitur yang belum pernah saya lihat sebelumnya: 1) Pemeriksaan untuk memastikan argumennya adalah bilangan bulat non-negatif 2) Membuat unit dari cache dan fungsi untuk membuatnya menjadi satu bit kode mandiri. Untuk bersenang-senang, saya mencoba membuatnya sekompak mungkin. Beberapa orang mungkin menganggapnya elegan, yang lain mungkin menganggapnya sangat tidak jelas. Bagaimanapun, ini dia:
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];
Anda dapat mengisi cache terlebih dahulu, atau membiarkannya diisi saat panggilan lewat. Tetapi elemen awal (untuk fakta (0) harus ada atau akan rusak.
Nikmati :)
Sangat sederhana menggunakan ES6
const factorial = n => n ? (n * factorial(n-1)) : 1;
Lihat contohnya di sini
Inilah salah satu solusinya:
function factorial(number) {
total = 1
while (number > 0) {
total *= number
number = number - 1
}
return total
}
Menggunakan ES6, Anda dapat mencapainya dengan cepat dan singkat:
const factorial = n => [...Array(n + 1).keys()].slice(1).reduce((acc, cur) => acc * cur, 1)
Kode untuk menghitung faktorial tergantung pada kebutuhan Anda.
Mengenai poin 1 dan 4, seringkali lebih berguna memiliki fungsi untuk mengevaluasi log faktorial secara langsung daripada memiliki fungsi untuk mengevaluasi faktorial itu sendiri.
Berikut adalah entri blog yang membahas masalah ini. Berikut adalah beberapa kode C # untuk menghitung faktorial log yang akan sepele untuk port ke JavaScript. Tetapi ini mungkin bukan yang terbaik untuk kebutuhan Anda tergantung pada jawaban Anda atas pertanyaan di atas.
Ini adalah versi berbasis loop kompak
function factorial( _n )
{
var _p = 1 ;
while( _n > 0 ) { _p *= _n-- ; }
return _p ;
}
Atau Anda mungkin menimpa objek Matematika (versi rekursif):
Math.factorial = function( _x ) { return _x <= 1 ? 1 : _x * Math.factorial( --_x ) ; }
Atau bergabunglah dengan kedua pendekatan ...
Memanfaatkan fakta bahwa Number.MAX_VALUE < 171!
, kita cukup menggunakan tabel pencarian lengkap yang hanya terdiri dari 171 elemen array ringkas yang memakan kurang dari 1,4 kilobyte memori.
Fungsi pencarian cepat dengan kompleksitas waktu proses O (1) dan overhead akses array minimal akan terlihat sebagai berikut:
// 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
Ini tepat dan secepat itu menggunakan Number
tipe data. Menghitung tabel pemeta dalam Javascript - seperti yang disarankan beberapa jawaban lain - akan mengurangi presisi saat n! > Number.MAX_SAFE_INTEGER
.
Mengompresi tabel runtime melalui gzip mengurangi ukurannya pada disk dari sekitar 3,6 menjadi 1,8 kilobyte.
Jawaban satu baris:
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
untuk keamananSolusi menggunakan
BigInt
, fitur ES 2018 + / 2019.
Ini adalah contoh penggunaan yang berfungsi BigInt
, karena banyak jawaban di sini semuanya lepas dari batas aman Number
(MDN) hampir seketika. Ini bukan yang tercepat tetapi sederhana dan dengan demikian lebih jelas untuk mengadaptasi pengoptimalan lain (seperti cache dari 100 angka pertama).
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
akhir literal numerik seperti 1303n
menunjukkan itu aBigInt
tipe.BigInt
dengan Number
kecuali Anda secara eksplisit memaksanya, dan hal itu dapat menyebabkan hilangnya akurasi.Menggunakan fitur ES6, dapat menulis kode pada SATU baris & tanpa rekursi :
var factorial=(n)=>Array.from({length: n},(v, k) => k+1).reduce((a, b) => a*b, 1)
Hanya untuk kelengkapan, berikut adalah versi rekursif yang akan memungkinkan pengoptimalan panggilan ekor. Saya tidak yakin apakah pengoptimalan panggilan ekor dilakukan dalam JavaScript ..
function rFact(n, acc)
{
if (n == 0 || n == 1) return acc;
else return rFact(n-1, acc*n);
}
Untuk menyebutnya:
rFact(x, 1);
Ini adalah solusi berulang yang menggunakan lebih sedikit ruang tumpukan dan menyimpan nilai yang dihitung sebelumnya dengan cara memo sendiri:
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
Juga perhatikan bahwa saya menambahkan ini ke objek Matematika yang merupakan literal objek sehingga tidak ada prototipe. Alih-alih hanya mengikat ini ke fungsi secara langsung.
Math.factorial(100); Math.factorial(500);
akan menghitung perkalian 1..100 dua kali.
Saya percaya berikut ini adalah bagian kode yang paling berkelanjutan dan efisien dari komentar di atas. Anda dapat menggunakan ini dalam arsitektur js aplikasi global Anda ... dan, tidak perlu khawatir tentang menulisnya di banyak ruang nama (karena ini adalah tugas yang mungkin tidak memerlukan banyak penambahan). Saya telah menyertakan 2 nama metode (berdasarkan preferensi) tetapi keduanya dapat digunakan karena mereka hanya referensi.
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
alih - alih sebaliknya, Anda kehilangan hingga 4 digit dengan presisi untuk 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
Ini melakukan caching dari 100 nilai pertama dengan cepat, dan tidak memasukkan variabel eksternal ke dalam ruang lingkup untuk cache, menyimpan nilai sebagai properti dari objek fungsi itu sendiri, yang berarti bahwa jika Anda tahu factorial(n)
telah dihitung, Anda dapat cukup menyebutnya sebagai factorial[n]
, yang sedikit lebih efisien. Menjalankan 100 nilai pertama ini akan membutuhkan waktu sub-milidetik di browser modern.
21! > Number.MAX_SAFE_INTEGER
, karenanya tidak dapat dengan aman direpresentasikan sebagai float 64-bit.
Berikut adalah implementasi yang menghitung faktorial positif dan negatif. Cepat dan sederhana.
var factorial = function(n) {
return n > 1
? n * factorial(n - 1)
: n < 0
? n * factorial(n + 1)
: 1;
}
Ini yang saya buat sendiri, jangan gunakan angka di atas 170 atau di bawah 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
dan melakukan terlalu banyak Number
konversi dan memberikan hasil yang salah untuk 0! (seperti yang Anda nyatakan, tapi mengapa?).
Ini kode saya
function factorial(num){
var result = num;
for(i=num;i>=2;i--){
result = result * (i-1);
}
return result;
}
factorial(0)
. Juga, dengan memulai perkalian Anda dengan n * (n-1) * (n-2) * ... * 1 alih-alih sebaliknya, Anda kehilangan hingga 4 digit dengan presisi untuk n >> 20. @prime: 170! > Number.MAX_VALUE
dan paling baik diwakili dengan Infinity
.
Loop yang di-cache harus tercepat (setidaknya ketika dipanggil beberapa kali)
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;
}
})();
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n)
}
Disediakan oleh http://javascript.info/tutorial/number-math sebagai cara sederhana untuk mengevaluasi apakah suatu objek adalah bilangan bulat yang tepat untuk kalkulasi.
var factorials=[[1,2,6],3];
Sekumpulan sederhana faktorial Memo yang memerlukan kalkulasi berlebihan, dapat diproses dengan "dikalikan dengan 1", atau merupakan satu digit yang merupakan persamaan sederhana yang tidak layak diproses secara langsung.
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;
});
Setelah meninjau masukan dari anggota lain (tidak termasuk saran Log, meskipun saya dapat menerapkannya nanti) saya melanjutkan dan membuat skrip yang cukup sederhana. Saya mulai dengan contoh JavaScript OOP sederhana yang tidak berpendidikan dan membuat kelas kecil untuk menangani faktorial. Saya kemudian menerapkan Memoisasi versi saya yang disarankan di atas. Saya juga menerapkan Factorialization steno namun saya membuat sedikit kesalahan penyesuaian; Saya mengubah "n <2" menjadi "n <3". "n <2" masih akan memproses n = 2 yang akan menjadi sia-sia, karena Anda akan mengulang untuk 2 * 1 = 2; ini sia-sia menurut saya. Saya mengubahnya menjadi "n <3"; karena jika n adalah 1 atau 2 itu hanya akan mengembalikan n, jika 3 atau lebih itu akan mengevaluasi secara normal. Tentu saja karena aturan berlaku, saya menempatkan fungsi saya dalam urutan menurun dari eksekusi yang diasumsikan. Saya menambahkan opsi bool (true | false) untuk memungkinkan perubahan cepat antara eksekusi memo'ed dan normal (Anda tidak pernah tahu kapan Anda ingin menukar halaman Anda tanpa perlu mengubah "gaya") Seperti yang saya katakan sebelumnya variabel faktorial memoized diatur dengan 3 posisi awal, mengambil 4 karakter, dan meminimalkan perhitungan yang sia-sia. Semua yang melewati iterasi ketiga, Anda menangani matematika dua digit plus. Saya pikir jika Anda di mana cukup ngotot tentang hal itu Anda akan menjalankan pada tabel faktorial (seperti yang diterapkan). mengambil 4 karakter, dan meminimalkan perhitungan yang boros. Semua yang melewati iterasi ketiga, Anda menangani matematika dua digit plus. Saya pikir jika Anda di mana cukup ngotot tentang hal itu Anda akan menjalankan pada tabel faktorial (seperti yang diterapkan). mengambil 4 karakter, dan meminimalkan perhitungan yang boros. Semua yang melewati iterasi ketiga, Anda menangani matematika dua digit plus. Saya pikir jika Anda di mana cukup ngotot tentang hal itu Anda akan menjalankan pada tabel faktorial (seperti yang diterapkan).
Apa yang telah saya rencanakan setelah ini? local & | session storage untuk memungkinkan cache kasus per kasus dari iterasi yang diperlukan, pada dasarnya menangani masalah "tabel" yang diucapkan di atas. Ini juga akan menghemat ruang database dan server secara besar-besaran. Namun, jika Anda menggunakan localStorage Anda pada dasarnya akan menghabiskan ruang di komputer pengguna Anda hanya untuk menyimpan daftar nomor dan membuat layar mereka TERLIHAT lebih cepat, namun dalam jangka waktu yang lama dengan kebutuhan yang sangat besar ini akan menjadi lambat. Saya berpikir sessionStorage (membersihkan setelah Tab pergi) akan menjadi rute yang jauh lebih baik. Mungkin menggabungkan ini dengan server self balancing / cache dependen lokal? Pengguna A membutuhkan pengulangan X. Pengguna B membutuhkan iterasi Y. X + Y / 2 = Jumlah yang dibutuhkan dalam cache lokal. Kemudian, cukup deteksi dan ubah dengan waktu muat dan waktu eksekusi langsung untuk setiap pengguna sampai menyesuaikan diri dengan pengoptimalan untuk situs itu sendiri. Terima kasih!
Edit 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);
});
Hasil edit ini menerapkan saran Tumpukan lainnya dan memungkinkan saya memanggil fungsi sebagai faktorial (benar) (5), yang merupakan salah satu tujuan saya yang ditetapkan. : 3 Saya juga menghapus beberapa penugasan yang tidak perlu, dan menyingkat beberapa nama variabel non-publik.
undefined
untuk 0 !. ES6 memungkinkan untuk diganti isNumeric
dengan Number.isInteger
. Garis seperti factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);
sama sekali tidak bisa dibaca.
Ini adalah salah satu yang menggunakan fungsi javascript yang lebih baru mengisi , memetakan , mengurangi dan konstruktor (dan sintaks panah lemak):
Math.factorial = n => n === 0 ? 1 : Array(n).fill(null).map((e,i)=>i+1).reduce((p,c)=>p*c)
Edit: diperbarui untuk menangani 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);