আপনার সমস্ত দুর্দান্ত উত্তরের জন্য আপনাকে ধন্যবাদ। আমি নীচের সমাধানটি দিয়ে শেষ করেছি, যা আমি ভাগ করে নিতে চাই।
হুইস এবং হাউস সম্পর্কে আরও বিশদে যাওয়ার আগে, এখানে টিএল; ডাঃ : আমার চকচকে নতুন স্ক্রিপ্ট :-)
#!/usr/bin/env bash
#
# Generates a random integer in a given range
# computes the ceiling of log2
# i.e., for parameter x returns the lowest integer l such that 2**l >= x
log2() {
local x=$1 n=1 l=0
while (( x>n && n>0 ))
do
let n*=2 l++
done
echo $l
}
# uses $RANDOM to generate an n-bit random bitstring uniformly at random
# (if we assume $RANDOM is uniformly distributed)
# takes the length n of the bitstring as parameter, n can be up to 60 bits
get_n_rand_bits() {
local n=$1 rnd=$RANDOM rnd_bitlen=15
while (( rnd_bitlen < n ))
do
rnd=$(( rnd<<15|$RANDOM ))
let rnd_bitlen+=15
done
echo $(( rnd>>(rnd_bitlen-n) ))
}
# alternative implementation of get_n_rand_bits:
# uses /dev/urandom to generate an n-bit random bitstring uniformly at random
# (if we assume /dev/urandom is uniformly distributed)
# takes the length n of the bitstring as parameter, n can be up to 56 bits
get_n_rand_bits_alt() {
local n=$1
local nb_bytes=$(( (n+7)/8 ))
local rnd=$(od --read-bytes=$nb_bytes --address-radix=n --format=uL /dev/urandom | tr --delete " ")
echo $(( rnd>>(nb_bytes*8-n) ))
}
# for parameter max, generates an integer in the range {0..max} uniformly at random
# max can be an arbitrary integer, needs not be a power of 2
rand() {
local rnd max=$1
# get number of bits needed to represent $max
local bitlen=$(log2 $((max+1)))
while
# could use get_n_rand_bits_alt instead if /dev/urandom is preferred over $RANDOM
rnd=$(get_n_rand_bits $bitlen)
(( rnd > max ))
do :
done
echo $rnd
}
# MAIN SCRIPT
# check number of parameters
if (( $# != 1 && $# != 2 ))
then
cat <<EOF 1>&2
Usage: $(basename $0) [min] max
Returns an integer distributed uniformly at random in the range {min..max}
min defaults to 0
(max - min) can be up to 2**60-1
EOF
exit 1
fi
# If we have one parameter, set min to 0 and max to $1
# If we have two parameters, set min to $1 and max to $2
max=0
while (( $# > 0 ))
do
min=$max
max=$1
shift
done
# ensure that min <= max
if (( min > max ))
then
echo "$(basename $0): error: min is greater than max" 1>&2
exit 1
fi
# need absolute value of diff since min (and also max) may be negative
diff=$((max-min)) && diff=${diff#-}
echo $(( $(rand $diff) + min ))
এটি সংরক্ষণ করুন ~/bin/rand
এবং আপনার প্রাপ্যতায় বাশ এ একটি মিষ্টি এলোমেলো ফাংশন রয়েছে যা প্রদত্ত সালিসী ব্যাপ্তিতে কোনও পূর্ণসংখ্যার নমুনা করতে পারে can ব্যাপ্তিতে নেতিবাচক এবং ধনাত্মক পূর্ণসংখ্যার সমন্বয় থাকতে পারে এবং দৈর্ঘ্যে 2 60 -1 অবধি হতে পারে :
$ rand
Usage: rand [min] max
Returns an integer distributed uniformly at random in the range {min..max}
min defaults to 0
(max - min) can be up to 2**60-1
$ rand 1 10
9
$ rand -43543 -124
-15757
$ rand -3 3
1
$ for i in {0..9}; do rand $((2**60-1)); done
777148045699177620
456074454250332606
95080022501817128
993412753202315192
527158971491831964
336543936737015986
1034537273675883580
127413814010621078
758532158881427336
924637728863691573
অন্যান্য উত্তরদাতাদের সমস্ত ধারণা দুর্দান্ত ছিল। করে উত্তর terdon , জেএফ সেবাস্টিয়ান এবং jimmij সহজ এবং দক্ষ পদ্ধতিতে এই কাজটি করার জন্য বাহ্যিক সরঞ্জামগুলি ব্যবহার করেছিল। তবে আমি সর্বাধিক বহনযোগ্যতার জন্য একটি সত্য বাশ সমাধানকে প্রাধান্য দিয়েছি, এবং সম্ভবত কিছুটা হলেও কেবল বাশের প্রতি ভালবাসার বাইরে;)
রমেশের এবং l0b0 এর উত্তর ব্যবহৃত /dev/urandom
বা /dev/random
এর সাথে মিলিয়ে od
। এটি খুব ভাল তবে তাদের পদ্ধতির 0 থেকে 2 8n পরিসরের মধ্যে এলোমেলো পূর্ণসংখ্যার নমুনা তৈরি করতে পারার অসুবিধা ছিল কিছু এন এর জন্য -1 , যেহেতু এই পদ্ধতির নমুনা বাইটগুলি, অর্থাৎ দৈর্ঘ্যের বিটস্ট্রিংস 8 এটি বেশ বড় জাম্পস রয়েছে are বর্ধমান n।
অবশেষে, ফ্যালকের উত্তরটি সাধারণ ধারণা বর্ণনা করে যে কীভাবে এটি স্বেচ্ছাচারী ব্যাপ্তিগুলির জন্য করা যেতে পারে (কেবলমাত্র দু'জনের শক্তি নয়)। মূলত, একটি নির্দিষ্ট পরিসরের জন্য {0..max}
, আমরা দুটির পরবর্তী শক্তিটি কী তা নির্ধারণ করতে পারি, যেমন, বিটস্ট্রিং হিসাবে উপস্থাপনের জন্য ঠিক কত বিট প্রয়োজন max
। তারপর আমরা ঠিক যে অনেক বিট নমুনা এবং কিনা এই bistring, একটি পূর্ণসংখ্যা হিসাবে, তার চেয়ে অনেক বেশী করতে পারেন max
। যদি তাই হয় তবে পুনরাবৃত্তি করুন। যেহেতু আমরা প্রতিনিধিত্ব করতে প্রয়োজন ঠিক তত বিট নমুনাmax
, প্রতিটি পুনরাবৃত্তির সাফল্যের 50% (সবচেয়ে খারাপ ক্ষেত্রে 50%, সেরা ক্ষেত্রে 100%) এর চেয়ে বড় বা সমান সম্ভাবনা থাকে। সুতরাং এটি খুব দক্ষ।
আমার স্ক্রিপ্টটি মূলত ফ্যালকো জবাবের একটি কংক্রিট বাস্তবায়ন, খাঁটি ব্যাশে লেখা এবং অত্যন্ত দক্ষ কারণ এটি কাঙ্ক্ষিত দৈর্ঘ্যের বিটস্ট্রিংয়ের নমুনার জন্য ব্যাশের অন্তর্নির্মিত বিটওয়াইজ অপারেশনগুলি ব্যবহার করে। এটি অতিরিক্ত হিসাবে এলিয়াহ কাগনের একটি ধারণাকেও সম্মান করে যা $RANDOM
বারবার অনুরোধের ফলে বিটস্ট্রিংগুলি সংঘবদ্ধ করে বিল্ট-ইন ভেরিয়েবলটি ব্যবহার করার পরামর্শ দেয় $RANDOM
। আমি আসলে উভয় সম্ভাবনার ব্যবহার করতে বাস্তবায়িত /dev/urandom
এবং $RANDOM
। ডিফল্টরূপে উপরের স্ক্রিপ্টটি ব্যবহার করে $RANDOM
। (এবং ঠিক আছে, যদি /dev/urandom
আমাদের od এবং tr ব্যবহার করা হয় তবে এগুলি পসিএক্স সমর্থন করে))
সুতরাং কিভাবে এটি কাজ করে?
আমি এটিতে Beforeোকার আগে দুটি পর্যবেক্ষণ:
দেখা যাচ্ছে বাশ 2 63 -1 এর চেয়ে বড় সংখ্যাকে পরিচালনা করতে পারে না । নিজের জন্য দেখুন:
$ echo $((2**63-1))
9223372036854775807
$ echo $((2**63))
-9223372036854775808
এটি প্রদর্শিত হবে যে বাশ অভ্যন্তরীণভাবে পূর্ণসংখ্যার সঞ্চয় করতে স্বাক্ষরিত 64৪-বিট পূর্ণসংখ্যার ব্যবহার করে। সুতরাং, 2 63 এ এটি "চারপাশে মোড়ানো" এবং আমরা একটি নেতিবাচক পূর্ণসংখ্যার পাই। সুতরাং আমরা যাই হোক না কেন র্যান্ডম ফাংশনটি ব্যবহার করে 2-63 -1 এর চেয়ে বড় কোনও রেঞ্জ পাওয়ার আশা করতে পারি না । বাশ কেবল এটি পরিচালনা করতে পারে না।
যখনই আমরা একটি স্বেচ্ছাসেবী সীমার মধ্যে একটি মান নমুনা করতে চাই min
এবং max
সম্ভবত min != 0
, আমরা কেবল এর মধ্যে 0
এবং max-min
পরিবর্তে একটি মান নমুনা করতে পারি এবং তারপরে min
চূড়ান্ত ফলাফলটিতে যুক্ত করতে পারি। এটি এমনকি যদি min
এবং সম্ভবত নেতিবাচকmax
হয় তবেও এটি কাজ করে , তবে এর মান 0
এবং পরম মানের মধ্যে একটি নমুনা দেওয়ার জন্য আমাদের যত্নবান হওয়া দরকার max-min
। অতএব, আমরা মধ্যে একটি র্যান্ডম মান নমুনা কিভাবে উপর নজর দিতে পারেন 0
এবং একটি অবাধ ধনাত্মক পূর্ণসংখ্যা max
। বাকিটা সহজ।
পদক্ষেপ 1: একটি পূর্ণসংখ্যার প্রতিনিধিত্ব করতে কতগুলি বিট প্রয়োজন তা নির্ধারণ করুন (লগারিদম)
সুতরাং প্রদত্ত মানটির জন্য max
, আমরা এটি জানতে চাই যে এটি বিটস্ট্রিং হিসাবে উপস্থাপনের জন্য কত বিট প্রয়োজন needed এটি তাই যে পরে আমরা এলোমেলোভাবে কেবলমাত্র যত বিট প্রয়োজন ততগুলি নমুনা করতে পারি, যা স্ক্রিপ্টটিকে এত দক্ষ করে তোলে।
দেখা যাক. যেহেতু n
বিটস সহ, আমরা 2 এন -1 মান পর্যন্ত প্রতিনিধিত্ব করতে পারি , তারপরে n
একটি স্বেচ্ছাচারিত মান উপস্থাপনের জন্য প্রয়োজনীয় বিটের সংখ্যাটি x
সিলিং (লগ 2 (x + 1)) হয়। সুতরাং, লগারিদমের সিলিংটি বেস 2 তে গণনা করার জন্য আমাদের একটি ফাংশন প্রয়োজন এটি বরং স্ব-ব্যাখ্যামূলক:
log2() {
local x=$1 n=1 l=0
while (( x>n && n>0 ))
do
let n*=2 l++
done
echo $l
}
আমাদের শর্তটি দরকার n>0
তাই এটি যদি খুব বড় হয়, চারপাশে আবৃত হয় এবং নেতিবাচক হয়ে যায় তবে লুপটি সমাপ্ত হওয়ার গ্যারান্টিযুক্ত।
পদক্ষেপ 2: দৈর্ঘ্যের এলোমেলো একটি বিটস্ট্রিংয়ের নমুনা করুন n
সর্বাধিক বহনযোগ্য ধারণাগুলি হয় হয় /dev/urandom
(বা /dev/random
কোনও শক্ত কারণ থাকলেও ) বা ব্যাশের অন্তর্নির্মিত $RANDOM
ভেরিয়েবল ব্যবহার করা। এটি দিয়ে কীভাবে করা যায় তা দেখুন$RANDOM
প্রথমে ।
বিকল্প একটি: ব্যবহার $RANDOM
এটি এলিয়াহ কাগান দ্বারা উল্লিখিত ধারণাটি ব্যবহার করে । মূলত, যেহেতু $RANDOM
15-বিট পূর্ণসংখ্যার নমুনা, তাই আমরা $((RANDOM<<15|RANDOM))
30-বিট পূর্ণসংখ্যার নমুনা ব্যবহার করতে পারি । এর অর্থ, $RANDOM
বামে 15 বিটের প্রথম অনুরোধটি স্থানান্তরিত করুন , এবং খানিকটা প্রয়োগ করুন বা দ্বিতীয় অনুরোধের সাথে $RANDOM
কার্যকরভাবে দুটি স্বতন্ত্র নমুনাযুক্ত বিটস্ট্রিংগুলি (বা কমপক্ষে বাশের অন্তর্নির্মিত ব্যবস্থাগুলির মতো স্বতন্ত্র $RANDOM
) উপস্থাপন করুন apply
আমরা এটি একটি 45-বিট বা 60-বিট পূর্ণসংখ্যা পেতে পুনরাবৃত্তি করতে পারি। এর পরে বাশ এটিকে আর পরিচালনা করতে পারে না তবে এর অর্থ আমরা সহজেই 0 এবং 2 60 -1 এর মধ্যে একটি এলোমেলো মান নমুনা করতে পারি । সুতরাং, একটি এন-বিট পূর্ণসংখ্যার নমুনা হিসাবে, আমরা আমাদের এলোমেলো বিটস্ট্রিংয়ের, যার দৈর্ঘ্য 15-বিট ধাপে বৃদ্ধি পায়, তার দৈর্ঘ্য এন এর চেয়ে বড় বা সমান হয় repeat অবশেষে, আমরা ডানদিকে যথাযথভাবে বিটওয়াইজ স্থানান্তরিত করে খুব বেশি বিটগুলি কেটে দিয়েছি এবং আমরা একটি এন-বিট এলোমেলো পূর্ণসংখ্যা দিয়ে শেষ করি।
get_n_rand_bits() {
local n=$1 rnd=$RANDOM rnd_bitlen=15
while (( rnd_bitlen < n ))
do
rnd=$(( rnd<<15|$RANDOM ))
let rnd_bitlen+=15
done
echo $(( rnd>>(rnd_bitlen-n) ))
}
বিকল্প বি: ব্যবহার /dev/urandom
বিকল্পভাবে, আমরা ব্যবহার করতে পারি od
এবং /dev/urandom
একটি এন-বিট পূর্ণসংখ্যা নমুনা করতে পারি । od
বাইটগুলি, অর্থাৎ দৈর্ঘ্যের বিটস্ট্রিংগুলি পড়বে Similarly একইভাবে পূর্ববর্তী পদ্ধতির মতো আমরা কেবলমাত্র এতগুলি বাইট নমুনা করি যে নমুনা বিটের সমতুল্য সংখ্যা এন এর চেয়ে বেশি বা সমান, এবং খুব বেশি বিটগুলি কেটে দেয়।
কমপক্ষে এন বিট পেতে সর্বনিম্ন সংখ্যার বাইটগুলি হ'ল সর্বনিম্ন 8 টির চেয়ে বেশি যা n এর চেয়ে বড় বা সমান (NN 7) / 8)।
এটি কেবল 56-বিট পূর্ণসংখ্যা পর্যন্ত কাজ করে। আরও একটি বাইট স্যাম্পলিংয়ের ফলে আমাদের একটি 64-বিট পূর্ণসংখ্যার অর্থাত্ 2 64 -1 অবধি মান পাওয়া যায় যা বাশ হ্যান্ডেল করতে পারে না।
get_n_rand_bits_alt() {
local n=$1
local nb_bytes=$(( (n+7)/8 ))
local rnd=$(od --read-bytes=$nb_bytes --address-radix=n --format=uL /dev/urandom | tr --delete " ")
echo $(( rnd>>(nb_bytes*8-n) ))
}
টুকরা একসাথে রাখা: স্বেচ্ছাসেবী রেঞ্জগুলিতে এলোমেলো পূর্ণসংখ্যা পান
আমরা নমুনা করতে n
এখন bitstrings -বিট, কিন্তু আমরা থেকে একটি সীমার মধ্যে নমুনা পূর্ণসংখ্যার করতে চান 0
করতে max
, অবিশেষে এলোমেলোভাবে , যেখানেmax
অগত্যা দুই একটি ক্ষমতা নির্বিচারে হতে পারে। (আমরা মডুলো ব্যবহার করতে পারি না কারণ এটি একটি পক্ষপাতিত্ব তৈরি করে))
মানটির প্রতিনিধিত্ব করার জন্য max
আমরা যত বিটকে প্রয়োজনীয় পরিমাণে নমুনা দেওয়ার জন্য কেন এত কঠোর প্রচেষ্টা করেছি , তা হ'ল আমরা এখন নিরাপদে (এবং দক্ষতার সাথে) বার বার একটি- n
বিট বিটস্ট্রিংকে নমুনা করতে একটি লুপ ব্যবহার করতে পারি যতক্ষণ না আমরা কম মানটির নমুনা দিই বা এর সমান max
। সবচেয়ে খারাপ ক্ষেত্রে ( max
দুটি একটি শক্তি), প্রতিটি পুনরাবৃত্তি 50% এর সম্ভাব্যতার সাথে শেষ হয় এবং সর্বোত্তম ক্ষেত্রে ( max
দুটি বিয়োগের একটি শক্তি), প্রথম পুনরাবৃত্তিটি নিশ্চিত হয়ে শেষ হয়।
rand() {
local rnd max=$1
# get number of bits needed to represent $max
local bitlen=$(log2 $((max+1)))
while
# could use get_n_rand_bits_alt instead if /dev/urandom is preferred over $RANDOM
rnd=$(get_n_rand_bits $bitlen)
(( rnd > max ))
do :
done
echo $rnd
}
জিনিস গুটিয়ে রাখা
পরিশেষে, আমরা মধ্যে নমুনা পূর্ণসংখ্যার করতে চান min
এবং max
সেখানে min
এবংmax
অবাধ হতে পারে, এমনকি নেতিবাচক। পূর্বে উল্লিখিত হিসাবে, এটি এখন তুচ্ছ।
আসুন এটি সব বাশ স্ক্রিপ্টে রাখি। কিছু যুক্তি স্টাফ পার্সিং করুন ... আমরা দুটি আর্গুমেন্ট min
এবং max
বা একটি মাত্র যুক্তি চাই max
যেখানে min
ডিফল্ট হয় 0
।
# check number of parameters
if (( $# != 1 && $# != 2 ))
then
cat <<EOF 1>&2
Usage: $(basename $0) [min] max
Returns an integer distributed uniformly at random in the range {min..max}
min defaults to 0
(max - min) can be up to 2**60-1
EOF
exit 1
fi
# If we have one parameter, set min to 0 and max to $1
# If we have two parameters, set min to $1 and max to $2
max=0
while (( $# > 0 ))
do
min=$max
max=$1
shift
done
# ensure that min <= max
if (( min > max ))
then
echo "$(basename $0): error: min is greater than max" 1>&2
exit 1
fi
... আর, পরিশেষে, অবিশেষে মধ্যে র্যান্ডম একটি মান এ নমুনা min
এবং max
আমরা মধ্যে একটি র্যান্ডম পূর্ণসংখ্যা নমুনা 0
এবং পরম মান max-min
, এবং যোগ min
চূড়ান্ত ফলাফল হবে। :-)
diff=$((max-min)) && diff=${diff#-}
echo $(( $(rand $diff) + min ))
এর দ্বারা অনুপ্রাণিত হয়ে , আমি এই পিআরএনজি পরীক্ষা এবং বেঞ্চমার্ক করার জন্য ডাইহার্ডার ব্যবহার করার চেষ্টা করতে পারি এবং আমার অনুসন্ধানগুলি এখানে রাখি। :-)