বাশে কীভাবে দক্ষ, বৃহত্তর, সমানভাবে বিতরণ করা, এলোমেলো পূর্ণসংখ্যার উত্পাদন করা যায়?


30

আমি ভাবছিলাম যে ব্যাশে ভাল এলোমেলো হওয়ার সর্বোত্তম উপায়টি কী হবে, অর্থাত্, এ জাতীয় MINএবং এর মধ্যে একটি এলোমেলো ধনাত্মক পূর্ণসংখ্যা পাওয়ার পদ্ধতি কী হবে?MAX

  1. পরিসীমা নির্বিচারে বড় হতে পারে (বা কমপক্ষে, বলে, 2 32 -1 অবধি );
  2. মানগুলি সমানভাবে বিতরণ করা হয় (অর্থাত্ কোনও পক্ষপাত নয়);
  3. এটা দক্ষ।

ব্যাশে এলোমেলো হওয়ার একটি কার্যকর উপায় হ'ল $RANDOMভেরিয়েবলটি ব্যবহার করা । তবে এটি কেবল 0 এবং 2 15 -1 এর মধ্যে একটি মানকে নমুনা করে , যা সমস্ত কারণে যথেষ্ট পরিমাণে বড় নাও হতে পারে। লোকেরা সাধারণত তাদের পছন্দসই সীমার মধ্যে আনতে একটি মডুলো ব্যবহার করে, যেমন,

MIN=0
MAX=12345
rnd=$(( $RANDOM % ($MAX + 1 - $MIN) + $MIN ))

এটি, অতিরিক্তভাবে, $MAX2 15 -1 = 32767 বিভক্ত না হলে একটি পক্ষপাত তৈরি করে । যেমন, যদি $MIN0 হয় এবং $MAX9, তারপর মান 0 থেকে 7 পালন করুন সামান্য মান 8 এবং 9 বেশী সম্ভবপর হয়, যেমন $RANDOMহবে না 32768 বা 32769. এই পক্ষপাত, পরিসর বৃদ্ধি, যেমন যেমন খারাপ যদি $MIN0 হয় এবং $MAXহয় 9999, তারপর সংখ্যার 0 2767 মাধ্যমে একটি সম্ভাব্যতা আছে 4 / 32767 , যখন সংখ্যা 2768 9999 মাধ্যমে শুধুমাত্র একটি সম্ভাব্যতা আছে 3 / 32767

সুতরাং উপরের পদ্ধতিটি 3 শর্ত পূরণ করে, এটি 1 এবং 2 শর্ত পূরণ করে না।

1 এবং 2 শর্ত পূরণ করার চেষ্টা করার জন্য আমি এখন পর্যন্ত যে সর্বোত্তম পদ্ধতিটি নিয়ে এসেছি তা হ'ল নীচে ব্যবহার /dev/urandomকরা:

MIN=0
MAX=1234567890
while
  rnd=$(cat /dev/urandom | tr -dc 0-9 | fold -w${#MAX} | head -1 | sed 's/^0*//;')
  [ -z $rnd ] && rnd=0
  (( $rnd < $MIN || $rnd > $MAX ))
do :
done

মূলত, কেবল এ থেকে এলোমেলোতা সংগ্রহ করুন /dev/urandom( /dev/randomকোনও ক্রিপ্টোগ্রাফিকভাবে শক্তিশালী সিউডোরোডম নম্বর জেনারেটর চাইলে পরিবর্তে এটির ব্যবহার বিবেচনা করতে পারে এবং যদি আপনার কাছে প্রচুর সময় থাকে, অথবা অন্যথায় সম্ভবত একটি হার্ডওয়্যার এলোমেলো সংখ্যা জেনারেটর), প্রতিটি অক্ষর মুছুন যা দশমিক অঙ্ক নয়, ভাঁজ দৈর্ঘ্য আউটপুট $MAXএবং 0 এর নেতৃস্থানীয় কাটা। যদি আমরা কেবল 0 টি পেতে পারি তবে $rndতা খালি, তাই এই ক্ষেত্রে সেট rndকরা হবে 0। ফলাফলটি আমাদের সীমার বাইরে রয়েছে কিনা তা পরীক্ষা করে দেখুন এবং তা যদি হয় তবে পুনরাবৃত্তি করুন। আমি এখানে পাহারা মধ্যে যখন লুপ "শরীর" বাধ্য তাই শরীরের বল মৃত্যুদন্ড হিসেবে অন্তত একবার, একটি এমুলেট চেতনায় do ... whileলুপ, যেহেতুrnd শুরু undefined করা হয়।

আমি মনে করি যে আমি এখানে 1 এবং 2 শর্ত পূরণ করেছি তবে এখন আমি শর্তটি 3 এড়িয়ে গিয়েছি It's এক সেকেন্ড বা তার বেশি সময় নেয় (আমি ভাগ্যবান যখন সেকেন্ডের দশম)। আসলে, লুপটিও সমাপ্তির গ্যারান্টিযুক্ত নয় (যদিও সমাপ্তির সম্ভাবনা সময় বাড়ার সাথে সাথে 1 তে রূপান্তরিত হয়)।

কোনও পূর্বনির্ধারিত এবং সম্ভাব্য বৃহত্তর পরিসরের মধ্যে ব্যাশে নিরপেক্ষভাবে এলোমেলো পূর্ণসংখ্যাগুলি পাওয়ার জন্য কী কার্যকর উপায় আছে? (সময় দিলে আমি তদন্ত চালিয়ে যাব, তবে ইতিমধ্যে আমি ভেবেছিলাম এখানে কারও কাছে একটি দুর্দান্ত ধারণা থাকতে পারে!)

উত্তরগুলির সারণী

  1. সর্বাধিক বুনিয়াদী (এবং তাই বহনযোগ্য) ধারণাটি হ'ল যথেষ্ট দীর্ঘ একটি এলোমেলো বিটস্ট্রিং তৈরি করা। বাশনের অন্তর্নির্মিত $RANDOMভেরিয়েবল ব্যবহার করে বা ( odএবং ) ব্যবহার করে এলোমেলো বিটস্ট্রিং তৈরির বিভিন্ন উপায় রয়েছে । এলোমেলো সংখ্যাটি যদি এর চেয়ে বেশি হয়/dev/urandom/dev/random$MAX আবার শুরু করুন।

  2. বিকল্পভাবে, বাহ্যিক সরঞ্জাম ব্যবহার করা সম্ভব।

    • পার্ল সমাধান
      • প্রো: বেশ পোর্টেবল, সহজ, নমনীয়
      • বিপরীতে: 2 32 -1 এর উপরে খুব বেশি সংখ্যার জন্য নয়
    • পাইথন সমাধান
      • প্রো: সাধারণ, নমনীয়, এমনকি বিশাল সংখ্যক জন্যও কাজ করে
      • কন্ট্রা: কম পোর্টেবল
    • Zsh সমাধান
      • প্রো: যেভাবে যাইহোক zsh ব্যবহার করেন তাদের পক্ষে ভাল
      • কন্ট্রা: সম্ভবত আরও কম বহনযোগ্য

র্যান্ডম বিটগুলি বেস 64-এনকোডিংয়ের পরিবর্তে কেন কেবল পূর্ণসংখ্যাগুলি বেছে নিন, তারপরে একটি নির্দিষ্ট সংখ্যক অক্ষর (প্রয়োজনীয় পরিসরের উপর নির্ভর করে) এনকোডযুক্ত ফর্ম থেকে বেস 64 থেকে বেস 10 এ রূপান্তর করবেন?
মুরু

এটি কি বাশ করা দরকার ? rand=$(command)যদি commandআপনার প্রয়োজনীয়তাগুলি পূরণ করে এমন একটি পুনরাবৃত্তি ফেরত দেয় তবে কিছু করতে চান ?
টেরডন

@ মুরু এটি আসলে একটি দুর্দান্ত ধারণা। আমি এটি ব্যবহার করে dd if=/dev/urandom 2>/dev/nullএবং পাইপ ব্যবহার করে অনুরূপ ধারণার জন্য কিছুটা চিন্তাভাবনা ব্যয় করেছিলাম od -t d(বেস 64৪ এর মাধ্যমে চৌকসটি এড়ানো হয়), তবে রূপান্তরটি কীভাবে ঘটে এবং এটি বাস্তবে নিরপেক্ষ কিনা তা আমার কাছে স্পষ্ট নয়। আপনি যদি একটি দক্ষ, কার্যকারী স্ক্রিপ্টে আপনার ধারণাটি প্রসারিত করতে পারেন এবং কোন পক্ষপাত নেই কেন তা ব্যাখ্যা করতে পারেন, এটি একটি দুর্দান্ত উত্তর দেবে। :)
মাল্টে স্কারুপ্পা

@terdon আমি বাশ পছন্দ করব আমি বলতে চাচ্ছি, অবশ্যই আপনি ডাকা যাবে pythonবা perlবা আপনার প্রিয় ভাষা, কিন্তু এই সব জায়গায় পাওয়া যায় না। আমি আরও কিছু পোর্টেবল পছন্দ করি। ঠিক আছে, awkএলোমেলো ফাংশনটি ভাল হবে, আমার ধারণা I তবে যত বেশি পোর্টেবল,
ততই

2
হ্যাঁ, আমি লাইন ধরে ভাবছিলাম perl -e 'print int(rand(2**32-1))');। এটি বেশ সুস্পষ্ট পোর্টেবল এবং খুব দ্রুত হবে। বেশিরভাগ বাস্তবায়ন একই বীজ থেকে শুরু হওয়ায় আওক এটিকে কাটবে না। সুতরাং আপনি পরবর্তী রানগুলিতে একই র্যান্ডম নম্বর পান। এটি কেবল একই রানের মধ্যে পরিবর্তন হয়।
টেরডন

উত্তর:


17

আমি এখান থেকে আরও একটি আকর্ষণীয় পদ্ধতি দেখতে পাচ্ছি ।

rand=$(openssl rand 4 | od -DAn)

এটি একটি ভাল বিকল্প বলে মনে হচ্ছে। এটা তোলে র্যান্ডম ডিভাইস থেকে 4 বাইট পড়ে এবং তাদের মধ্যে স্বাক্ষরবিহীন পূর্ণসংখ্যা হিসাবে ফরম্যাট 0এবং 2^32-1

rand=$(od -N 4 -t uL -An /dev/urandom | tr -d " ")


কেন odআদেশ পৃথক হয়। উভয়ই 4-বাইট স্বাক্ষরবিহীন পূর্ণসংখ্যাগুলি মুদ্রণ করে: 1 ম - ওপেনসেল থেকে, দ্বিতীয় - থেকে /dev/random
jfs

1
@ রমেশ আমি /dev/urandomপরিবর্তে ব্যবহারের জন্য সম্পাদনা করেছি /dev/random- আমি ব্যবহারের কোনও কারণ দেখতে পাচ্ছি না /dev/randomএবং এটি সত্যই ব্যয়বহুল / ধীর হতে পারে বা সিস্টেমের অন্যান্য অংশগুলিকে ধীর করে দিতে পারে। (যদি এডিট দরকার হয় তবে ফ্রি এডিট করুন এবং ব্যাখ্যা করুন)
ভলকার সিগেল

1
কোনও উদ্বেগ নেই, সত্যিই অবাক হওয়ার বিষয় যে এই সাধারণ পার্থক্যের এত জটিল প্রভাব রয়েছে। এই কারণেই আমি উদাহরণটিকে ডানদিকে পরিবর্তন করার জন্য জোর দিয়েছিলাম - লোকেরা উদাহরণ থেকে শিখেন।
ভোলকার সিগেল

1
@ মাল্টসকোরুপা: এর Iঅর্থ দাঁড়ায় নীতিগত দিক sizeof(int)থেকে এটি কম 4। বিটিডব্লিউ, od -DAnব্যর্থ হয়েছে (2**32-1)তবে od -N4 -tu4 -Anকাজ চালিয়ে যাচ্ছে।
jfs

8

আপনার সমস্ত দুর্দান্ত উত্তরের জন্য আপনাকে ধন্যবাদ। আমি নীচের সমাধানটি দিয়ে শেষ করেছি, যা আমি ভাগ করে নিতে চাই।

হুইস এবং হাউস সম্পর্কে আরও বিশদে যাওয়ার আগে, এখানে টিএল; ডাঃ : আমার চকচকে নতুন স্ক্রিপ্ট :-)

#!/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োকার আগে দুটি পর্যবেক্ষণ:

  1. দেখা যাচ্ছে বাশ 2 63 -1 এর চেয়ে বড় সংখ্যাকে পরিচালনা করতে পারে না । নিজের জন্য দেখুন:

    $ echo $((2**63-1))
    9223372036854775807
    $ echo $((2**63))
    -9223372036854775808

    এটি প্রদর্শিত হবে যে বাশ অভ্যন্তরীণভাবে পূর্ণসংখ্যার সঞ্চয় করতে স্বাক্ষরিত 64৪-বিট পূর্ণসংখ্যার ব্যবহার করে। সুতরাং, 2 63 এ এটি "চারপাশে মোড়ানো" এবং আমরা একটি নেতিবাচক পূর্ণসংখ্যার পাই। সুতরাং আমরা যাই হোক না কেন র্যান্ডম ফাংশনটি ব্যবহার করে 2-63 -1 এর চেয়ে বড় কোনও রেঞ্জ পাওয়ার আশা করতে পারি না । বাশ কেবল এটি পরিচালনা করতে পারে না।

  2. যখনই আমরা একটি স্বেচ্ছাসেবী সীমার মধ্যে একটি মান নমুনা করতে চাই 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

এটি এলিয়াহ কাগান দ্বারা উল্লিখিত ধারণাটি ব্যবহার করে । মূলত, যেহেতু $RANDOM15-বিট পূর্ণসংখ্যার নমুনা, তাই আমরা $((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 ))

এর দ্বারা অনুপ্রাণিত হয়ে , আমি এই পিআরএনজি পরীক্ষা এবং বেঞ্চমার্ক করার জন্য ডাইহার্ডার ব্যবহার করার চেষ্টা করতে পারি এবং আমার অনুসন্ধানগুলি এখানে রাখি। :-)


আপনার সমাধান ধরে নেয় যে sizeof(int) == 8কারণে (64bit)--format=u
JFS

1
আপনার সমাধানটি আমাকে মনে করিয়ে দেয় যে এলোমেলো.পি কীভাবে লেখা হয়। random.Randomক্লাস 53 বিট ব্যবহার করে? জেনারেটর স্বেচ্ছাসেবী বড় এলোমেলো সংখ্যা (একাধিক আহবান) ফেরত, random.SystemRandomব্যবহার os.urandom()করে প্রয়োগ করা যেতে পারে একই ব্যবহার করে /dev/urandom
jfs

uL পরিসীমাটির জন্য আকার (দীর্ঘ)> = 8 কে বোঝায়। এটির নিশ্চয়তা নেই। প্ল্যাটফর্মটির এমন পূর্ণসংখ্যা রয়েছে তা জোর দিয়ে আপনি u8 ব্যবহার করতে পারেন।
jfs

@ জেএসএবেস্টিয়ান আমি ভাবছিলাম যে এখন পর্যন্ত আমার স্ক্রিপ্ট দীর্ঘ ইনট আকার সম্পর্কে কোনও অনুমানকে কঠোর কোড দেয় না। সম্ভবত, দীর্ঘ সাইন ইনডের আকার যদি 64 বিটের চেয়ে বড় (বা কম) হয় তবে এটি কাজ করবে, উদাহরণস্বরূপ, 128 বিট। তবে, যদি আমি ব্যবহার করি--format=u8 তবে আমি অনুমানটিকে হার্ডকোড করব sizeof(int)==8। অন্যদিকে, যদি ব্যবহার --format=uLকোন সমস্যা নেই: আমি মনে করি না একটি প্ল্যাটফর্ম যে হয় না হয়েছে 64-বিট ইন্টিজার কিন্তু এখনও কম কিছু যতদিন আছে ints সংজ্ঞায়িত করে। সুতরাং মূলত আমি --format=uLআরও নমনীয়তার জন্য যুক্তি দিতে চাই । আপনার চিন্তা কি?
Malte Skoruppa

নেই long longযে 64bit হতে পারে যখন int- এ = দীর্ঘ = কিছু প্ল্যাটফর্মের উপর 32bit। আপনি যদি সমস্ত প্ল্যাটফর্মে গ্যারান্টি না দিতে পারেন তবে আপনাকে 0..2 ** 60 রেঞ্জের দাবি করা উচিত নয়। অন্যদিকে ব্যাশ এ জাতীয় প্ল্যাটফর্মগুলিতে এই ব্যাপ্তিটি নিজেই সমর্থন করে না (আমি জানি না, সম্ভবত এটি ম্যাক্সিন্ট_ টি ব্যবহার করে এবং তারপর আপনি যদি নির্ধারিত ব্যাপ্তিটি জোড় করতে চান তবে u8 আরও সঠিক হয় ( odযদি আপনার সীমাটি থাকে তবে সর্বাধিক নির্দিষ্টকরণকে সমর্থন করে না বাশের প্ল্যাটফর্ম নির্ভর - পরিসীমা যাই হ'ল) ​​যদি ব্যাশের পরিসর দীর্ঘ আকারের উপর নির্ভর করে তবে ইউএল আরও উপযুক্ত হতে পারে)। আপনি কী সম্পূর্ণ পরিসর চান যা ব্যাশ সমস্ত ওএস বা একটি নির্দিষ্ট ব্যাপ্তিতে সমর্থন করে?
jfs

6

এটা zsh হতে পারে?

max=1000
integer rnd=$(( $(( rand48() )) * $max ))

আপনি বীজ পাশাপাশি ব্যবহার করতে পারেন rand48(seed)। আগ্রহী হলে বিস্তারিত বিবরণ দেখুন man zshmodulesএবং দেখুন man 3 erand48


আমি ব্যক্তিগতভাবে zsh ব্যবহার করি না, তবে এটি একটি দুর্দান্ত সংযোজন :)
মাল্টে স্কোরুপ্পা


5

আপনি যদি 0 থেকে (2 ^ n) -1 এর মধ্যে একটি নম্বর চান যেখানে n মোড 8 = 0 আপনি কেবল n / 8 বাইট পেতে পারেন/dev/random । উদাহরণস্বরূপ, এলোমেলো দশমিক প্রতিনিধিত্ব পেতে intআপনি যা করতে পারেন তা:

od --read-bytes=4 --address-radix=n --format=u4 /dev/random | awk '{print $1}'

আপনি যদি শুধু এন বিট নিতে চান তবে আপনি প্রথমে সিলিং (এন / 8) বাইট এবং নিতে পারেন ডান শিফট আপনার যে পরিমাণ চান তা নিতে পারেন। উদাহরণস্বরূপ যদি আপনি 15 বিট চান:

echo $(($(od --read-bytes=2 --address-radix=n --format=u4 /dev/random | awk '{print $1}') >> 1))

যদি আপনি পুরোপুরি নিশ্চিত হন যে আপনি এলোমেলো মানের গুণমান সম্পর্কে চিন্তা করেন না এবং আপনি তার পরিবর্তে ব্যবহার করতে পারেন এমন ন্যূনতম রান সময় গ্যারান্টি দিতে চান । ব্যবহারের আগে আপনি কী করছেন তা নিশ্চিত হয়ে নিন !/dev/urandom/dev/random/dev/urandom


ধন্যবাদ. সুতরাং, nএলোমেলো বাইটগুলি পান /dev/urandomএবং ব্যবহার করে ফর্ম্যাট করুন odএই উত্তর হিসাবে আত্মা অনুরূপ । উভয়ই সমানভাবে ভাল :) যদিও উভয়েরই একটি নির্দিষ্ট পরিসীমা 0 থেকে 2 ^ (এন * 8) -1 বিটগুলির মধ্যে থাকার অসুবিধা রয়েছে, যেখানে এন বাইটের সংখ্যা। আমি একটি স্বেচ্ছাসেবী ব্যাপ্তির জন্য একটি পদ্ধতি পছন্দ করি , 2 ^ 32-1 অবধি , তবে কিছু কমও। এটি পক্ষপাতদুষ্টর সৃষ্টি করে।
মাল্টে স্কোরুপ্পা

/dev/urandomপরিবর্তে ব্যবহারের জন্য সম্পাদিত /dev/random- আমি ব্যবহার করার কোনও কারণ দেখতে পাচ্ছি না /dev/randomএবং এটি সত্যই ব্যয়বহুল / ধীর হতে পারে বা সিস্টেমের অন্যান্য অংশগুলিকে ধীর করে দিতে পারে। (বিনামূল্যে সম্পাদনা করুন নিখরচায় এবং এটির সত্যই দরকার হলে ব্যাখ্যা করুন))
ভলকার সিগেল

এটি ঠিক বিপরীত হওয়া উচিত: আপনি যদি / ডি / র্যান্ডম প্রয়োজন জানেন না তবে / dev / urandom ব্যবহার করুন । এটি অনুমান করা ভুল যে /dev/urandomফলাফলগুলি /dev/randomইউরেনডমের চেয়ে অনেক খারাপ যে বেশিরভাগ ক্ষেত্রে ব্যবহারযোগ্য নয় । একবার শুরু /dev/urandomকরা হয় (সিস্টেমের শুরুতে); এর ফলাফলগুলি /dev/randomলিনাক্সের প্রায় সমস্ত অ্যাপ্লিকেশনের মতোই দুর্দান্ত । কিছু সিস্টেমে এলোমেলো এবং ইউরেনডম একই থাকে।
jfs

1
--format=uসাথে প্রতিস্থাপন করা উচিত --format=u4কারণ তত্ত্বের sizeof(int)চেয়ে কম হতে পারে 4
jfs

@ জেফএসবাবাসিয়ান এই প্রবন্ধটির এই বিষয়টির চারপাশে খুব আকর্ষণীয় আলোচনা রয়েছে। তাদের উপসংহারটি মনে হয় যে এটি উভয়ই /dev/randomএবং /dev/urandomঅসন্তুষ্টিজনক এবং "লিনাক্সকে এমন একটি সুরক্ষিত আরএনজি যুক্ত করা উচিত যা এটি পর্যাপ্ত পরিমাণে বীজ এনট্রপি সংগ্রহ না করে এবং এরপরে আচরণ না করে অবরুদ্ধ করে urandom" "
l0b0

3

বাহ্যিক সরঞ্জামগুলি ব্যবহারে আপনার আপত্তি নেই তা ধরে নিলে, এটি আপনার প্রয়োজনীয়তা পূরণ করবে:

rand=$(perl -e 'print int(rand(2**32-1))'); 

এটি পার্লের randফাংশনটি ব্যবহার করছে যা প্যারামিটার হিসাবে একটি উচ্চতর সীমা নেয়। আপনি যা পছন্দ করতে পারেন এটি সেট করতে পারেন। এটি বিমূর্ত গাণিতিক সংজ্ঞাতে সত্যিকারের এলোমেলোভাবে কতটা কাছাকাছি এই সাইটের ক্ষেত্রের বাইরে নয় তবে এটি যদি আপনার অত্যন্ত সংবেদনশীল এনক্রিপশন বা এর মতো প্রয়োজন না হয় তবে তা ঠিক হওয়া উচিত। সম্ভবত সেখানেও কিন্তু আমি কোনও মতামত প্রকাশ করব না।


এটি বৃহত সংখ্যার জন্য বিরতি যেমন, 5 ** 1234
jfs

1
@ জেফএসবেস্তিয়ান হ্যাঁ তা করে। ওপি নির্দিষ্ট করা থেকে আমি এটি পোস্ট করেছি 1^32-1তবে আপনাকে বৃহত্তর সংখ্যার জন্য এটি টুইট করতে হবে।
terdon

2

আপনার পছন্দসই সর্বাধিকের চেয়ে নিকটতম (2 ^ এক্স) -1 সমান বা গ্রেটার পাওয়া উচিত এবং বিটের সংখ্যা পাওয়া উচিত। তারপরে কেবল / ডিভ / এলোমেলো একাধিকবার কল করুন এবং আপনার পর্যাপ্ত পরিমাণ না হওয়া পর্যন্ত সমস্ত বিট একসাথে সংযুক্ত করুন, সমস্ত বিট যা খুব বেশি কেটে দেওয়া হবে। ফলাফলটি যদি আপনার সর্বোচ্চ পুনরাবৃত্তির চেয়ে বড় হয়। সবচেয়ে খারাপ ক্ষেত্রে আপনার সর্বোচ্চের নিচে এলোমেলো নম্বর পাওয়ার 50% এরও বেশি সম্ভাবনা রয়েছে (এই সবচেয়ে খারাপ ক্ষেত্রে) আপনি গড়ে দুটি কল নেবেন।


দক্ষতা বৃদ্ধির জন্য এটি আসলে একটি বেশ ভাল ধারণা। রমেশের উত্তর এবং l0b0 এর উত্তর উভয়ই এলোমেলো বিট পেতে পারে তবে উভয় উত্তরে/dev/urandom এটি সর্বদা 8 বিটের একাধিক। ফর্ম্যাট করার আগে নিম্ন রেঞ্জগুলির জন্য খুব বেশি যে বিটগুলি কাটা হচ্ছে এটি odদক্ষতা উন্নত করার জন্য একটি ভাল ধারণা, যেহেতু আপনি সুন্দরভাবে ব্যাখ্যা করার সাথে লুপটিতে কেবল একটি প্রত্যাশিত সংখ্যা 2 থাকে। এটি, উল্লিখিত উত্তরগুলির একটির সাথে মিলিত, সম্ভবত এটি যাওয়ার উপায়।
মাল্টে স্কোরুপ্পা

0

আপনার উত্তর আকর্ষণীয় তবে বেশ দীর্ঘ।

আপনি যদি ইচ্ছামত বড় সংখ্যক সংখ্যা চান তবে আপনি সহায়তায় একাধিক এলোমেলো সংখ্যায় যোগদান করতে পারেন:

# $1 - number of 'digits' of size base
function random_helper()
{
  base=32768
  random=0
  for((i=0; i<$1; ++i)); do
    let "random+=$RANDOM*($base**$i)"
  done
  echo $random
}

যদি সমস্যাটি পক্ষপাতদুষ্ট হয় তবে কেবল এটি সরিয়ে দিন।

# $1 - min value wanted
# $2 - max value wanted
function random()
{
  MAX=32767
  min=$1
  max=$(($2+1))
  size=$((max-min))
  bias_range=$((MAX/size))
  while
    random=$RANDOM
  [ $((random/size)) -eq $bias_range ]; do :; done
  echo $((random%size+min))
}

এই ফাংশনগুলিতে একসাথে যোগদান

# $1 - min value wanted
# $2 - max value wanted
# $3 - number of 'digits' of size base
function random()
{
  base=32768
  MAX=$((base**$3-1))
  min=$1
  max=$(($2+1))
  size=$((max-min))
  bias_range=$((MAX/size))
  while
    random=$(random_helper)
  [ $((random/size)) -eq $bias_range ]; do :; done
  echo $((random%size+min))
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.