कई प्रोग्राम को असली दुनिया की घटनाओं का अनुकरण करने के लिए (दिखने में) रैंडम वैल्यू की ज़रूरत होती है।
आम और परिचित उदाहरणों में शामिल हैं:
('H', 'T') में से एक रैंडम वैल्यू।कंप्यूटर से वास्तव में रैंडम वैल्यू बनाना आश्चर्यजनक रूप से कठिन तकनीकी चुनौती है, इसलिए हो सकता है कि आप इन नतीजों को "स्यूडोरैंडम" कहते हुए देखें।
ज़रूरी: यह कॉन्सेप्ट क्रिप्टोग्राफिक रूप से सुरक्षित रैंडम संख्याओं को शामिल नहीं करता, जो कहीं ज़्यादा कठिन चुनौती हैं।
लेकिन Julia की स्टैंडर्ड लाइब्रेरी के Random मॉड्यूल जैसी अच्छी तरह बनी लाइब्रेरी तेज़ और लचीली होती हैं, और ये मॉडलिंग, अनुकरण तथा गेम्स के ज़्यादातर कामों के लिए काफ़ी अच्छे नतीजे देती हैं।
Julia रैंडम कार्यक्षमता को कई जगहों पर बाँटता है:
Base में बस कुछ बुनियादी लेकिन बहुत काम के फंक्शन, जो हमेशा उपलब्ध रहते हैं।Random मॉड्यूल में और भी ज़्यादा विकल्प।Random स्टैंडर्ड लाइब्रेरी का हिस्सा है और ज़्यादा संभावना है कि यह पहले से इंस्टॉल हो, लेकिन इसकी सामग्री को नेमस्पेस में लाने के लिए आपको अपने प्रोग्राम के ऊपर using Random जोड़ना होगा।
rand() फंक्शनयह फंक्शन क्या करता है, यह इस पर निर्भर करता है कि आप इसे कौन से आर्गुमेंट देते हैं। इसमें बहुत सारे विकल्प हैं।
बिना किसी आर्गुमेंट के, यह 0 (सम्मिलित) से 1 के बीच एक दशमलव संख्या बनाता है।
यह एक uniform डिस्ट्रिब्यूशन है जिसमें सभी वैल्यू की संभावना बराबर होती है, जैसा कि नीचे "डिस्ट्रिब्यूशन के साथ काम करना" वाले हिस्से में बताया गया है।
सिर्फ एक पूर्णांक आर्गुमेंट उसी लंबाई का एक वेक्टर बनाता है।
julia> rand()
0.10261774967264703
julia> rand(5)
5-element Vector{Float64}:
0.24134501977563894
0.5664193284851202
0.9804412082089355
0.6229551330613335
0.47589221741904664
किसी और रेंज के लिए, बस नतीजे को ठीक से खिसकाइए और स्केल कीजिए।
नीचे दिया गया उदाहरण घटाव के लिए ब्रॉडकास्टिंग का इस्तेमाल करता है, जिसके बारे में वेक्टर ऑपरेशंस कॉन्सेप्ट में बताया गया है।
.- इस गणित को बस वेक्टर के हर एलिमेंट पर लागू करता है।
# numbers between -1.0 and +1.0
julia> (rand(5) .- 0.5) * 2
5-element Vector{Float64}:
-0.5303906759076336
0.9635682226775855
-0.048823697086981754
0.465842804648374
0.9880834344780736
अगर आर्गुमेंट के तौर पर सिर्फ एक टाइप दिया जाए, तो rand सीमा के रूप में typemin और typemax का इस्तेमाल करेगा।
शायद आप यह नहीं चाहते!
रैंडम पूर्णांकों के लिए, हम एक रेंज दे सकते हैं, और चाहें तो यह भी कि कितनी वैल्यू बनानी हैं।
julia> rand(Int64)
-9159538335234594326 # not very useful
julia> rand(1:10, 5)
5-element Vector{Int64}:
1
1
1
4
7
ऊपर दिए गए rand(1:10, 5) उदाहरण में ध्यान दीजिए कि (संयोग से) वैल्यू दोहराई जा रही हैं, क्योंकि हर चुनाव स्वतंत्र है।
इसे "रीप्लेसमेंट के साथ सैंपलिंग" कहते हैं, जिस पर नीचे और विस्तार से बात की गई है।
रेंज में दशमलव वैल्यू के लिए, आमतौर पर आपको स्टेप साइज़ बताना होगा। वरना स्टेप डिफ़ॉल्ट रूप से 1.0 हो जाएगा, जो शायद ही कभी काम आता है।
julia> rand(2.4:0.01:3.2, 4)
4-element Vector{Float64}:
3.19
2.53
3.14
3.13
या फिर, एक ऐरे या टपल दीजिए, और rand एक रैंडम एंट्री लौटाएगा:
julia> rand([4, 9, 16, 25])
16
# coin flip
julia> rand(['H', 'T'])
'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase)
# mixed types in tuple
julia> rand( (1, 3.2, "name"), 2 )
2-element Vector{Any}:
1
"name"
सोचिए कि हमारे पास एक थैला है जिसमें 3 लाल गेंदें और 4 हरी गेंदें हैं, और हम थैले से रैंडम रूप से एक गेंद निकालते हैं। दूसरी गेंद निकालने के लिए दो तरीके हैं:
पहली स्थिति रीप्लेसमेंट के साथ है, दूसरी उसके बिना, और दोनों अलग-अलग नतीजे देती हैं।
Julia में रीप्लेसमेंट के बिना सैंपलिंग का अनुकरण करने के लिए कुछ विकल्प हैं।
सबसे आसान (और Exercism के अंदर इकलौता) तरीका यह है कि Random.shuffle() का इस्तेमाल करके एंट्रियों को रैंडम क्रम में रखिए, फिर पहले n एलिमेंट ले लीजिए।
यह छोटी समस्याओं के लिए तो ठीक है, लेकिन बड़े संग्रहों पर शायद अच्छी तरह काम न करे: shuffle को पूरा ऐरे बनाना पड़ता है, भले ही आप उसका सिर्फ एक छोटा हिस्सा चाहते हों।
रीप्लेसमेंट के साथ सैंपलिंग "ठीक से" करने के लिए, StatsBase.jl पैकेज इंस्टॉल कीजिए।
यह पूरे विकल्पों के साथ sample() फंक्शन देता है।
हम उचित रूप से उम्मीद कर सकते हैं कि आने वाले किसी रिलीज़ में ऐसी ही कार्यक्षमता Random में जोड़ दी जाएगी, ताकि यह स्टैंडर्ड लाइब्रेरी का हिस्सा बन जाए (इस दस्तावेज़ के कोड नमूने Julia 1.11 के साथ जाँचे गए थे)।
अब तक हमने उन मामलों पर ध्यान दिया है जिनमें सभी परिणामों की संभावना बराबर होती है।
उदाहरण के लिए, rand(1:100) 1 से 100 तक के किसी भी पूर्णांक को बराबर संभावना से देता है।
असली दुनिया की कई स्थितियाँ इससे कहीं कम आसान होती हैं।
इसीलिए सांख्यिकीविदों ने "असली दुनिया" के नतीजों को गणितीय ढंग से बताने के लिए कई तरह के distributions बनाए हैं।
ऊपर बताया गया rand() फंक्शन तब इस्तेमाल होता है जब सभी संभावनाएँ बराबर हों।
इसे uniform डिस्ट्रिब्यूशन कहते हैं।
इसे "नॉर्मल" डिस्ट्रिब्यूशन या "घंटी के आकार की" वक्र भी कहते हैं, और यह मापी गई वैल्यू में आने वाली अशुद्धि बताने का बहुत आम तरीका है।
उदाहरण के लिए, मान लीजिए कि जिस कारखाने में आप काम करते हैं, उसने अभी-अभी 10,000 बोल्ट खरीदे हैं, जो एक जैसे होने चाहिए।
आप कारखाने के रोबोट को इन्हें संभालने के लिए तैयार करना चाहते हैं, तो आप 100 बोल्ट का एक नमूना तौलते हैं और पाते हैं कि उनका औसत (या mean) वज़न 4.731g है।
इसका यह मतलब होना बेहद कम संभव है कि इन सबका वज़न ठीक 4.731g हो।
हो सकता है कि आप पाएँ कि वैल्यू 4.627 से 4.794g तक फैली हैं, लेकिन 4.731g के आसपास केंद्रित हैं।
यह Gaussian distribution है, जिसमें संभावनाएँ औसत पर सबसे ज़्यादा होती हैं और दोनों तरफ सममित रूप से घटती जाती हैं (इसीलिए "घंटी के आकार की")।
इसका सॉफ्टवेयर में अनुकरण करने के लिए, हमें वक्र की चौड़ाई बताने का कोई तरीका चाहिए (आमतौर पर, महँगे बोल्ट सस्ते बोल्टों के मुकाबले औसत के आसपास ज़्यादा कसकर केंद्रित होंगे!).
परंपरा से, यह standard deviation से किया जाता है: तेज़ और संकरे वक्र के लिए छोटी वैल्यू, और नीचे और चौड़े वक्र के लिए बड़ी।
गणितज्ञों को ग्रीक अक्षर पसंद हैं, इसलिए हम औसत दिखाने के लिए μ (म्यू) और स्टैंडर्ड डेविएशन दिखाने के लिए σ (सिग्मा) इस्तेमाल करते हैं।
इसलिए, अगर आप पढ़ें कि "95% वैल्यू μ के 2σ के अंदर हैं" या "हिग्स बोसॉन 5-सिग्मा विश्वास के साथ पाया गया है", तो ऐसी बातों का संबंध स्टैंडर्ड डेविएशन से होता है।
इस बारे में और बातें Statistics कॉन्सेप्ट में होंगी।
randn() फंक्शन"random normal" का छोटा रूप, यह rand() के दशमलव वाले रूप जैसा ही है, बस फर्क यह है कि वैल्यू 0 औसत और 1 स्टैंडर्ड डेविएशन वाले गॉसियन के रूप में बँटी होती हैं।
फिर से, आप शायद randn के मूल आउटपुट को स्टैंडर्ड डेविएशन के लिए स्केल करना चाहें, और औसत के लिए उसे खिसकाना चाहें।
नीचे दिया गया उदाहरण इसे 30 औसत और 5 स्टैंडर्ड डेविएशन में बदलता है।
julia> raw = randn(5)
5-element Vector{Float64}:
3.0762588867281475
1.5101100620253902
-0.5914858221637778
0.684175554069735
-0.8416433926114673
julia> raw * 5 .+ 30
5-element Vector{Float64}:
45.38129443364074
37.55055031012695
27.04257088918111
33.420877770348675
25.791783036942665
आउटपुट को देखकर यह बताना मुश्किल है कि मूल आउटपुट यूनिफॉर्म डिस्ट्रिब्यूशन की तुलना में शून्य के ज़्यादा करीब केंद्रित होता है। अगर आपको इसमें शक है, तो 1000 या उससे ज़्यादा बनाइए और उन्हें प्लॉट करके इसे और स्पष्ट कर दीजिए।
Random मॉड्यूलइस मॉड्यूल में अगले स्तर की कार्यक्षमता है, जिसे Julia की डिफॉल्ट कॉन्फिगरेशन का आकार कम रखने के लिए Base से बाहर रखा गया है।
Random, Base के rand और randn में उनके बदलाव करने वाले रूप rand! और randn! भी जोड़ता है।
एक काम की चीज़ randstring है, जो दी गई लंबाई की एक स्ट्रिंग बनाता है।
डिफॉल्ट रूप से यह बड़े और छोटे अक्षरों के साथ 0 से 9 तक के अंक इस्तेमाल करता है, लेकिन और विकल्प भी बताए जा सकते हैं।
julia> using Random
julia> randstring(20)
"BoJnIxrS33pJiWggXZQV"
इसके अलावा, दी गई लंबाई का रैंडम BitArray बनाने के लिए एक bitrand फंक्शन है।
julia> bitrand(5)
julia> bitrand(5)
5-element BitVector:
1
1
0
0
1
किसी Vector की एंट्रियों को रैंडम रूप से शफल करने के लिए हमारे पास shuffle है; और इनपुट वेक्टर को उसी जगह बदलने के लिए shuffle! भी।
julia> v = ['A', '1', '2', 'J', 'Q', 'K'];
julia> shuffle(v)
6-element Vector{Char}:
'K': ASCII/Unicode U+004B (category Lu: Letter, uppercase)
'1': ASCII/Unicode U+0031 (category Nd: Number, decimal digit)
'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)
'J': ASCII/Unicode U+004A (category Lu: Letter, uppercase)
'2': ASCII/Unicode U+0032 (category Nd: Number, decimal digit)
'Q': ASCII/Unicode U+0051 (category Lu: Letter, uppercase)
# shuffles are random:
julia> shuffle(v)
6-element Vector{Char}:
'2': ASCII/Unicode U+0032 (category Nd: Number, decimal digit)
'K': ASCII/Unicode U+004B (category Lu: Letter, uppercase)
'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)
'Q': ASCII/Unicode U+0051 (category Lu: Letter, uppercase)
'J': ASCII/Unicode U+004A (category Lu: Letter, uppercase)
'1': ASCII/Unicode U+0031 (category Nd: Number, decimal digit)
कभी-कभी शफल किए गए इंडेक्स रखना ज़्यादा काम आता है।
इसके लिए randperm(n) इस्तेमाल कीजिए, जहाँ n अनुक्रम की लंबाई है।
julia> randperm(6)
6-element Vector{Int64}:
6
2
4
1
3
5
वास्तव में, ऊपर दिया गया उदाहरण shuffle(1:6) जैसे ही नतीजे देता है।
मैरी टीवी सीरीज़ Star Trek: The Next Generation की बड़ी प्रशंसक है। वह अक्सर कागज़-कलम वाले रोल-प्लेइंग गेम खेलती है, जिनमें वह और उसके दोस्त Starship Enterprise के क्रू का किरदार निभाते हैं। मैरी का किरदार कैप्टन पिकार्ड है, इसका मतलब है कि उसे कैप्टन का लॉग रखना पड़ता है। उसे खेल का रचनात्मक हिस्सा बहुत पसंद है, लेकिन मौके पर रैंडम डेटा बनाना उसे पसंद नहीं है।
कैप्टन के लॉग में आम तौर पर दिखने वाले डेटा के लिए रैंडम जनरेटर बनाकर मैरी की मदद कीजिए।
Starship Enterprise को अपनी यात्राओं में कई ग्रह मिलते हैं। Star Trek की दुनिया में ग्रहों को उनके गुणों के आधार पर श्रेणियों में बाँटा गया है। उदाहरण के लिए, पृथ्वी क्लास M का ग्रह है। ग्रहों की सभी संभावित क्लास ये हैं: D, H, J, K, L, M, N, R, T और Y।
random_planet फंक्शन बनाइए। यह किसी एक ग्रह क्लास को रैंडम रूप से लौटाना चाहिए।
julia> random_planet_class()
'K'
Enterprise (रजिस्ट्री नंबर NCC-1701) अकेला स्टारशिप नहीं है जो अंतरिक्ष में उड़ रहा है! जब उसकी मुलाकात किसी दूसरे स्टारशिप से होती है, तो मैरी को उस स्टारशिप का रजिस्ट्री नंबर लॉग करना पड़ता है।
रजिस्ट्री नंबर "NCC-" उपसर्ग से शुरू होते हैं और उसके बाद 1000 से 9999 (दोनों समेत) तक की कोई संख्या आती है।
random_ship_registry_number फंक्शन बनाइए जो कोई रैंडम स्टारशिप रजिस्ट्री नंबर लौटाता है।
julia> random_ship_registry_number()
"NCC-1947"
अगर लॉग में तारीखें ही न हों, तो उसका क्या फायदा?
स्टारडेट एक फ्लोटिंग पॉइंट संख्या होती है। The Next Generation के पहले सीज़न में Starship Enterprise के कारनामे स्टारडेट 41000.0 और 42000.0 के बीच होते हैं। "4" 24वीं सदी को दर्शाता है और "1" पहले सीज़न को।
random_stardate फंक्शन बनाइए जो 41000.0 (समेत) और 42000.0 के बीच एक फ्लोटिंग पॉइंट संख्या लौटाता है।
julia> random_stardate()
41458.15721310934
स्टारडेट में बहुत ज़्यादा दशमलव अंक होने की शिकायतें मिली हैं, इसलिए मैरी ने लॉग को एक दशमलव स्थान तक राउंड करने का फैसला किया।
हालाँकि यह काम random_stardate() से मिली वैल्यू को राउंड करके भी किया जा सकता है, लेकिन आप देखते हैं कि इसका एक बहुत आसान तरीका मौजूद है।
random_stardate_v2 फंक्शन बनाइए जो 41000.0 और 42000.0 (दोनों समेत) के बीच एक दशमलव स्थान वाली फ्लोटिंग पॉइंट संख्या लौटाता है।
julia> random_stardate_v2()
41732.6
खेल के एक रूप में दूसरे स्टारशिप के साथ बातचीत करनी होती है, और मैरी को उनमें से कुछ चुनने होते हैं।
संभावित स्टारशिप का एक पूरा ऐरे होता है, लेकिन हर खेल में इनमें से कुछ ही चाहिए होते हैं, और उन्हें रैंडम रूप से चुना जाना चाहिए।
pick_starships(starships, number_needed) फंक्शन बनाइए, जो अलग-अलग स्टारशिप रजिस्ट्री नंबरों का एक वेक्टर लेता है और number_needed लंबाई का एक वेक्टर लौटाता है। नतीजे में आने वाली वैल्यू starships से ली जानी चाहिए, और कोई भी वैल्यू दोहराई नहीं जानी चाहिए।
julia> pick_starships(["NCC-5011", "NCC-1228", "NCC-7039", "NCC-3978", "NCC-1476"], 2)
2-element Vector{String}:
"NCC-1228"
"NCC-5011"
हमने starships आर्गुमेंट को वेक्टर तक सीमित किया है। pick_starships() को दूसरे इटरेबल, जैसे टपल या सेट, के साथ काम करने लायक कैसे बनाएँगे?
इस हिस्से के लिए कोई टेस्ट नहीं हैं।
Exercism पर साइन अप कीजिए और Julia को 35 कॉन्सेप्ट128 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।