क्या जावास्क्रिप्ट में यादृच्छिक संख्या जनरेटर (Math.random) को बीज करना संभव है?
क्या जावास्क्रिप्ट में यादृच्छिक संख्या जनरेटर (Math.random) को बीज करना संभव है?
जवाबों:
नहीं, यह नहीं है, लेकिन अपने स्वयं के जनरेटर को लिखना काफी आसान है, या बेहतर अभी तक एक मौजूदा का उपयोग करना है। बाहर की जाँच करें: यह संबंधित प्रश्न ।
इसके अलावा, सीडिंग के बारे में अधिक जानकारी के लिए डेविड बाउ के ब्लॉग को देखें ।
नोट: बावजूद (या यों कहें कि) सुसाइड और स्पष्ट लालित्य के कारण, यह एल्गोरिथ्म किसी भी तरह से यादृच्छिकता के मामले में उच्च गुणवत्ता वाला नहीं है। बेहतर परिणाम के लिए इस उत्तर में सूचीबद्ध उदाहरण के लिए देखें ।
(मूल रूप से एक टिप्पणी में प्रस्तुत एक चतुर विचार से दूसरे उत्तर के लिए अनुकूलित।)
var seed = 1;
function random() {
var x = Math.sin(seed++) * 10000;
return x - Math.floor(x);
}
आप seed
किसी भी संख्या के लिए सेट कर सकते हैं , बस शून्य (या Math.PI के किसी भी एकाधिक) से बचें।
इस समाधान की भव्यता, मेरी राय में, किसी भी "जादू" संख्या की कमी से आती है (10000 के अलावा, जो अंकों की न्यूनतम राशि के बारे में दर्शाता है जो आपको अजीब पैटर्न से बचने के लिए फेंकना चाहिए - 10 , 100 , 1000 मानों के साथ परिणाम देखें )। ब्रेविटी भी अच्छी है।
यह Math.random () या 2 या 3 के एक कारक से थोड़ा धीमा है, लेकिन मेरा मानना है कि यह जावास्क्रिप्ट में लिखे गए किसी भी अन्य समाधान के रूप में तेजी से है।
मैंने सादे जावास्क्रिप्ट में कई अच्छे, छोटे और तेज Pseudorandom नंबर जनरेटर (PRNG) कार्यों को लागू किया है। उन सभी को सीड किया जा सकता है और अच्छी गुणवत्ता वाले नंबर प्रदान किए जा सकते हैं।
सबसे पहले, अपने PRNGs को ठीक से इनिशियलाइज़ करने का ध्यान रखें। नीचे दिए गए अधिकांश जनरेटर में बिल्ट-इन सीड जनरेट करने की प्रक्रिया (सरलता के लिए) नहीं है, लेकिन PRNG की प्रारंभिक अवस्था के रूप में एक या अधिक 32-बिट मानों को स्वीकार करते हैं । इसी तरह के बीज (जैसे 1 और 2 का एक साधारण बीज) कमजोर PRNGs में सहसंबंध पैदा कर सकता है, जिसके परिणामस्वरूप आउटपुट में समान गुण होते हैं (जैसे यादृच्छिक रूप से उत्पन्न स्तर समान)। इससे बचने के लिए, PRNGs को अच्छी तरह से वितरित बीज के साथ शुरू करना सबसे अच्छा अभ्यास है।
शुक्र है कि PRNG के लिए शॉर्ट स्ट्रिंग्स से बीज उत्पन्न करने में हैश फ़ंक्शन बहुत अच्छे हैं। एक अच्छा हैश फ़ंक्शन दो स्ट्रिंग्स समान होने पर भी बहुत भिन्न परिणाम उत्पन्न करेगा। यहाँ एक उदाहरण मुरमुरैश 3 के मिक्सिंग फंक्शन पर आधारित है:
function xmur3(str) {
for(var i = 0, h = 1779033703 ^ str.length; i < str.length; i++)
h = Math.imul(h ^ str.charCodeAt(i), 3432918353),
h = h << 13 | h >>> 19;
return function() {
h = Math.imul(h ^ h >>> 16, 2246822507);
h = Math.imul(h ^ h >>> 13, 3266489909);
return (h ^= h >>> 16) >>> 0;
}
}
के बाद के प्रत्येक कॉल वापसी समारोह का xmur3
एक नया "यादृच्छिक" 32-बिट हैश एक PRNG में एक बीज के रूप में प्रयोग की जाने वाली मूल्य पैदा करता है। यहां बताया गया है कि आप इसका उपयोग कैसे कर सकते हैं:
// Create xmur3 state:
var seed = xmur3("apples");
// Output four 32-bit hashes to provide the seed for sfc32.
var rand = sfc32(seed(), seed(), seed(), seed());
// Output one 32-bit hash to provide the seed for mulberry32.
var rand = mulberry32(seed());
// Obtain sequential random numbers like so:
rand();
rand();
वैकल्पिक रूप से, बस बीज को पैड करने के लिए कुछ डमी डेटा चुनें, और प्रारंभिक अवस्था को अच्छी तरह से मिलाने के लिए जनरेटर को कुछ बार (12-20 पुनरावृत्तियों) अग्रिम करें। यह अक्सर PRNGs के संदर्भ कार्यान्वयन में देखा जाता है, लेकिन यह प्रारंभिक राज्यों की संख्या को सीमित करता है।
var seed = 1337 ^ 0xDEADBEEF; // 32-bit seed with optional XOR value
// Pad seed with Phi, Pi and E.
// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
var rand = sfc32(0x9E3779B9, 0x243F6A88, 0xB7E15162, seed);
for (var i = 0; i < 15; i++) rand();
इन PRNG फ़ंक्शंस का आउटपुट एक सकारात्मक 32-बिट संख्या (0 से 2 32 -1) का उत्पादन करता है, जिसे बाद में 0-1 (0 समावेशी, 1 अनन्य) के बीच एक फ्लोटिंग-पॉइंट नंबर में बदल दिया जाता है Math.random()
, यदि आप यादृच्छिक संख्या चाहते हैं किसी विशिष्ट श्रेणी का, MDN पर यह लेख पढ़ें । यदि आप केवल कच्चे बिट्स चाहते हैं, तो बस अंतिम विभाजन ऑपरेशन को हटा दें।
ध्यान देने योग्य एक और बात जेएस की सीमाएं हैं। नंबर केवल 53-बिट रिज़ॉल्यूशन तक पूरे पूर्णांक का प्रतिनिधित्व कर सकते हैं। और बिटवाइज़ ऑपरेशन का उपयोग करते समय, यह 32 तक कम हो जाता है। इससे C या C ++ में लिखे एल्गोरिदम को लागू करना मुश्किल हो जाता है, जो कि 64-बिट संख्या का उपयोग करते हैं। 64-बिट कोड को पोर्ट करने के लिए शिम की आवश्यकता होती है जो प्रदर्शन को काफी कम कर सकता है । तो सादगी और दक्षता के लिए, मैंने केवल एल्गोरिदम पर विचार किया है जो 32-बिट गणित का उपयोग करता है, क्योंकि यह सीधे जेएस के साथ संगत है।
अब, जनरेटर के लिए आगे। (मैं यहां संदर्भ के साथ पूरी सूची बनाए रखता हूं )
sfc32 प्रैक्ट्रैंड रैंडम नंबर टेस्टिंग सूट का हिस्सा है (जो यह पाठ्यक्रम से गुजरता है)। sfc32 में 128-बिट स्थिति है और JS में बहुत तेज़ है।
function sfc32(a, b, c, d) {
return function() {
a >>>= 0; b >>>= 0; c >>>= 0; d >>>= 0;
var t = (a + b) | 0;
a = b ^ b >>> 9;
b = c + (c << 3) | 0;
c = (c << 21 | c >>> 11);
d = d + 1 | 0;
t = t + d | 0;
c = c + t | 0;
return (t >>> 0) / 4294967296;
}
}
शहतूत32 एक 32-बिट राज्य के साथ एक सरल जनरेटर है, लेकिन बहुत तेज़ है और इसमें अच्छी गुणवत्ता है (लेखक बताता है कि यह gjrand परीक्षण सूट के सभी परीक्षण पास करता है और इसमें पूर्ण 2 32 अवधि है, लेकिन मैंने सत्यापित नहीं किया है)।
function mulberry32(a) {
return function() {
var t = a += 0x6D2B79F5;
t = Math.imul(t ^ t >>> 15, t | 1);
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
return ((t ^ t >>> 14) >>> 0) / 4294967296;
}
}
यदि आप सिर्फ एक सरल लेकिन सभ्य PRNG की जरूरत है और मैं यादृच्छिक संख्या ( जन्मदिन की समस्या देखें ) के अरबों की जरूरत नहीं है, तो मैं यह सिफारिश करेंगे ।
मई 2018 तक, जोशी / ब्लैकमैन (जिन्होंने क्रोम में उपयोग किया जाता है, जो कि Xoroshiro भी लिखा है) द्वारा , Xoshiro128 ** Xorshift परिवार का नया सदस्य है । यह सबसे तेज़ जनरेटर है जो 128-बिट राज्य प्रदान करता है।
function xoshiro128ss(a, b, c, d) {
return function() {
var t = b << 9, r = a * 5; r = (r << 7 | r >>> 25) * 9;
c ^= a; d ^= b;
b ^= c; a ^= d; c ^= t;
d = d << 11 | d >>> 21;
return (r >>> 0) / 4294967296;
}
}
लेखकों का दावा है कि यह यादृच्छिकता परीक्षणों को अच्छी तरह से पास करता है ( यद्यपि कैविटीज़ के साथ )। अन्य शोधकर्ताओं ने बताया है कि टेस्टयू 01 (विशेष रूप से लिनियरकॉम और बाइनरीरैंक) में कुछ परीक्षण विफल हो जाते हैं। व्यवहार में, जब फ्लोट्स का उपयोग किया जाता है (जैसे कि ये कार्यान्वयन), तो यह मुद्दों का कारण नहीं होना चाहिए, लेकिन कच्चे बिट पर निर्भर होने पर मुद्दों का कारण हो सकता है।
यह जेस जेनकिंस (2007) द्वारा JSF या 'स्मॉलप्रेंज' है, जो उस व्यक्ति ने बनाया है जिसे ISAAC और SpookyHash बनाया गया है । यह प्रैक्ट्रैंड परीक्षण पास करता है और यह काफी तेज़ होना चाहिए, हालांकि एसएफसी जितना तेज़ नहीं।
function jsf32(a, b, c, d) {
return function() {
a |= 0; b |= 0; c |= 0; d |= 0;
var t = a - (b << 27 | b >>> 5) | 0;
a = b ^ (c << 17 | c >>> 15);
b = c + d | 0;
c = d + t | 0;
d = a + t | 0;
return (d >>> 0) / 4294967296;
}
}
एलसीजी बेहद तेज और सरल है, लेकिन इसकी यादृच्छिकता की गुणवत्ता इतनी कम है, कि अनुचित उपयोग वास्तव में आपके कार्यक्रम में कीड़े पैदा कर सकता है! बहरहाल, यह कुछ जवाबों का उपयोग करने के सुझाव से काफी बेहतर है Math.sin
या Math.PI
! यह हालांकि वन-लाइनर है, जो अच्छा है :)।
var LCG=s=>()=>(2**31-1&(s=Math.imul(48271,s)))/2**31;
इस कार्यान्वयन को न्यूनतम मानक RNG कहा जाता है, जैसा कि 1988 और 1993 में पार्क-मिलर द्वारा प्रस्तावित और C ++ 11 में लागू किया गया था minstd_rand
। ध्यान रखें कि राज्य 31-बिट है (31 बिट्स 2 बिलियन संभव राज्य देते हैं, 32 बिट्स दोगुना देते हैं)। यह PRNG का बहुत ही प्रकार है जिसे अन्य बदलने का प्रयास कर रहे हैं!
यह काम करेगा, लेकिन मैं इसका उपयोग नहीं करूंगा जब तक कि आपको वास्तव में गति की आवश्यकता न हो और यादृच्छिकता गुणवत्ता (वैसे भी यादृच्छिक क्या है?) के बारे में परवाह नहीं है। एक खेल जाम या एक डेमो या कुछ के लिए महान। एलसीजी बीज सहसंबंधों से ग्रस्त हैं, इसलिए एलसीजी के पहले परिणाम को त्यागना सबसे अच्छा है । और यदि आप एलसीजी का उपयोग करने पर जोर देते हैं, तो एक वेतन वृद्धि मूल्य जोड़ने से परिणामों में सुधार हो सकता है, लेकिन यह संभवत: निरर्थकता में एक व्यायाम है जब बहुत बेहतर विकल्प मौजूद हैं।
32-बिट राज्य (राज्य-स्थान में वृद्धि) की पेशकश करने वाले अन्य गुणक प्रतीत होते हैं:
var LCG=s=>()=>(s=Math.imul(741103597,s)>>>0)/2**32;
var LCG=s=>()=>(s=Math.imul(1597334677,s)>>>0)/2**32;
ये LCG मान इस प्रकार हैं: P. L.Ecuyer: Linear Congruential Generators of विभिन्न आकारों और अच्छी जाली संरचना की एक तालिका, 30 अप्रैल 1997।
seed = (seed * 185852 + 1) % 34359738337
:।
Math.imul
यह के रूप में जब 32-बिट पूर्णांकों पर सी में गुणन का उपयोग यह होगा अतिप्रवाह कर सकते हैं। आप जो सुझाव दे रहे हैं वह जेएस के पूर्णांक स्थान की पूरी श्रृंखला का उपयोग करने वाला एक एलसीजी है, जो निश्चित रूप से एक दिलचस्प क्षेत्र है। :)
नहीं, लेकिन यहां एक साधारण छद्म आयामी जनरेटर है, जिसे मैं बहु विकिपीडिया से अनुकूलित किया गया है ( जिसे तब से हटा दिया गया है) का कार्यान्वयन
var m_w = 123456789;
var m_z = 987654321;
var mask = 0xffffffff;
// Takes any integer
function seed(i) {
m_w = (123456789 + i) & mask;
m_z = (987654321 - i) & mask;
}
// Returns number between 0 (inclusive) and 1.0 (exclusive),
// just like Math.random().
function random()
{
m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask;
m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask;
var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
result /= 4294967296;
return result;
}
EDIT: फिक्स्ड सीड फंक्शन इसे रीसेट करके m_z
EDIT2: गंभीर कार्यान्वयन दोषों को ठीक कर दिया गया है
seed
समारोह, यादृच्छिक जनरेटर रीसेट नहीं है क्योंकि mz_z
चर जब बदल जाता है random()
कहा जाता है। इसलिए सेट करें mz_z = 987654321
(या कोई अन्य मूल्य)seed
m_w
, नहीं m_z
। 2) दोनों m_w
और m_z
कर रहे हैं परिवर्तन उनके पिछले मूल्यों पर आधारित है, इसलिए यह परिणाम को संशोधित करता है।
एंट्टी साइकिरी का एल्गोरिदम अच्छा और छोटा है। जब मैंने Math.seed (s) को कॉल किया तो मैंने शुरू में एक बदलाव किया, जिसने जावास्क्रिप्ट के Math.random को बदल दिया, लेकिन तब जेसन ने टिप्पणी की कि फ़ंक्शन को वापस करना बेहतर होगा:
Math.seed = function(s) {
return function() {
s = Math.sin(s) * 10000; return s - Math.floor(s);
};
};
// usage:
var random1 = Math.seed(42);
var random2 = Math.seed(random1());
Math.random = Math.seed(random2());
यह आपको एक और कार्यक्षमता देता है जो जावास्क्रिप्ट में नहीं है: कई स्वतंत्र यादृच्छिक जनरेटर। यह विशेष रूप से महत्वपूर्ण है यदि आप एक ही समय में कई बार दोहराए जाने वाले अनुकरण करना चाहते हैं।
Math.random
आपको कई स्वतंत्र जनरेटर बनाने की अनुमति देगा, है ना?
Math.seed(42);
इसे करते हैं, तो यह फ़ंक्शन को रीसेट करता है, इसलिए यदि आप करते var random = Math.seed(42); random(); random();
हैं 0.70...
, तो 0.38...
। यदि आप इसे var random = Math.seed(42);
फिर से कॉल करके रीसेट करते हैं , तो अगली बार जब आप कॉल random()
करेंगे तो आप 0.70...
फिर से मिलेंगे, और अगली बार जब आप दोबारा कॉल करेंगे 0.38...
।
random
एक देशी जावास्क्रिप्ट फ़ंक्शन को अधिलेखित करने के बजाय एक स्थानीय चर का उपयोग करने के लिए समय निकालें। ओवरराइटिंग Math.random
Jist संकलक अपने सभी कोड unoptimize हो सकती है।
कृपया पियरे L'Ecuyer का काम 1980 के दशक के अंत में और 1990 के दशक की शुरुआत में देखें। वहां अन्य लोग भी हैं। यदि आप विशेषज्ञ नहीं हैं, तो अपने दम पर एक यादृच्छिक संख्या में जनरेटर (छद्म) का निर्माण करना बहुत खतरनाक है, क्योंकि या तो परिणामों की एक उच्च संभावना है कि परिणाम सांख्यिकीय रूप से यादृच्छिक नहीं हैं या एक छोटी अवधि होने में हैं। पियरे (और अन्य) ने कुछ अच्छे (छद्म) यादृच्छिक संख्या जनरेटर को एक साथ रखा है जिन्हें लागू करना आसान है। मैं उनके LFSR जनरेटर में से एक का उपयोग करता हूं।
https://www.iro.umontreal.ca/~lecuyer/myftp/papers/handstat.pdf
फिल ट्रॉय
पिछले उत्तरों में से कुछ को मिलाकर, यह आपके लिए खोजे जा सकने योग्य यादृच्छिक कार्य है:
Math.seed = function(s) {
var mask = 0xffffffff;
var m_w = (123456789 + s) & mask;
var m_z = (987654321 - s) & mask;
return function() {
m_z = (36969 * (m_z & 65535) + (m_z >>> 16)) & mask;
m_w = (18000 * (m_w & 65535) + (m_w >>> 16)) & mask;
var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
result /= 4294967296;
return result;
}
}
var myRandomFunction = Math.seed(1234);
var randomNumber = myRandomFunction();
Math.seed(0)()
रिटर्न 0.2322845458984375
, और Math.seed(1)()
रिटर्न 0.23228873685002327
। बीज के अनुसार m_w
और परिवर्तन दोनों में m_z
मदद मिलती है। var m_w = 987654321 + s; var m_z = 123456789 - s;
विभिन्न बीजों के साथ पहले मूल्यों का अच्छा वितरण करता है।
अपने खुद के छद्म यादृच्छिक जनरेटर लिखने के लिए काफी सरल है।
डेव स्कॉटीज़ का सुझाव उपयोगी है, लेकिन जैसा कि दूसरों द्वारा बताया गया है, यह काफी समान रूप से वितरित नहीं है।
हालाँकि, यह पाप के पूर्णांक तर्कों के कारण नहीं है। यह केवल पाप की सीमा के कारण है, जो एक वृत्त का एक आयामी प्रक्षेपण होता है। यदि आप इसके बजाय वृत्त का कोण लेंगे तो यह एक समान होगा।
इसलिए पाप (x) के बजाय arg (exp (i * x)) / (2 * PI) का उपयोग करें।
यदि आपको रेखीय क्रम पसंद नहीं है, तो इसे थोड़ा सा एक्सोर के साथ मिलाएं। वास्तविक कारक उतना मायने नहीं रखता है।
N छद्म यादृच्छिक संख्या उत्पन्न करने के लिए कोई कोड का उपयोग कर सकता है:
function psora(k, n) {
var r = Math.PI * (k ^ n)
return r - Math.floor(r)
}
n = 42; for(k = 0; k < n; k++) console.log(psora(k, n))
कृपया ध्यान दें कि असली एंट्रॉपी की आवश्यकता होने पर आप छद्म यादृच्छिक अनुक्रमों का उपयोग नहीं कर सकते हैं।
कई लोग जिन्हें इन दिनों जावास्क्रिप्ट में एक बीज-रहित यादृच्छिक-संख्या जनरेटर की आवश्यकता होती है, वे डेविड बाऊ के बीजगणित मॉड्यूल का उपयोग कर रहे हैं ।
Math.random
नहीं, लेकिन भागा पुस्तकालय इसे हल करता है। इसमें लगभग सभी वितरण हैं जिनकी आप कल्पना कर सकते हैं और वरीयता प्राप्त यादृच्छिक संख्या का समर्थन कर सकते हैं। उदाहरण:
ran.core.seed(0)
myDist = new ran.Dist.Uniform(0, 1)
samples = myDist.sample(1000)
मैंने एक फ़ंक्शन लिखा है जो एक बीजयुक्त यादृच्छिक संख्या देता है, यह Math.sin का उपयोग एक लंबे यादृच्छिक संख्या में करता है और उस से संख्या लेने के लिए बीज का उपयोग करता है।
उपयोग :
seedRandom("k9]:2@", 15)
यह आपके वरीयता प्राप्त नंबर को वापस करेगा पहला पैरामीटर किसी भी स्ट्रिंग मान है; आपका बीज। दूसरा पैरामीटर है कि कितने अंक वापस आएंगे।
function seedRandom(inputSeed, lengthOfNumber){
var output = "";
var seed = inputSeed.toString();
var newSeed = 0;
var characterArray = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','y','x','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','U','R','S','T','U','V','W','X','Y','Z','!','@','#','$','%','^','&','*','(',')',' ','[','{',']','}','|',';',':',"'",',','<','.','>','/','?','`','~','-','_','=','+'];
var longNum = "";
var counter = 0;
var accumulator = 0;
for(var i = 0; i < seed.length; i++){
var a = seed.length - (i+1);
for(var x = 0; x < characterArray.length; x++){
var tempX = x.toString();
var lastDigit = tempX.charAt(tempX.length-1);
var xOutput = parseInt(lastDigit);
addToSeed(characterArray[x], xOutput, a, i);
}
}
function addToSeed(character, value, a, i){
if(seed.charAt(i) === character){newSeed = newSeed + value * Math.pow(10, a)}
}
newSeed = newSeed.toString();
var copy = newSeed;
for(var i=0; i<lengthOfNumber*9; i++){
newSeed = newSeed + copy;
var x = Math.sin(20982+(i)) * 10000;
var y = Math.floor((x - Math.floor(x))*10);
longNum = longNum + y.toString()
}
for(var i=0; i<lengthOfNumber; i++){
output = output + longNum.charAt(accumulator);
counter++;
accumulator = accumulator + parseInt(newSeed.charAt(counter));
}
return(output)
}
निश्चित बीज के लिए एक सरल तरीका:
function fixedrandom(p){
const seed = 43758.5453123;
return (Math.abs(Math.sin(p)) * seed)%1;
}
0 और 100 के बीच की संख्या के लिए।
Number.parseInt(Math.floor(Math.random() * 100))
Math.random
तरह के बीजारोपण के बारे में सवाल यह है कि जब भी Math.random
एक ही बीज के साथ बीज डाला जाता है, तो यह क्रमिक संख्याओं की क्रमिक श्रृंखला का उत्पादन करेगा। यह प्रश्न, प्रति कहना, वास्तविक उपयोग / प्रदर्शन के बारे में नहीं है Math.random
।