bashで大きく、均一に分布したランダムな整数を効率的に生成する方法は?


30

私が取得するための最良の方法だろうかと思ってきた良い手順の間のランダムな正の整数を取得するにはどうなるか、すなわちbashの、中にランダム性を、MINそしてMAX、そのようなことを

  1. 範囲は任意に大きくすることができます(少なくとも2 32 -1まで)。
  2. 値は均一に分布しています(つまり、バイアスはありません)。
  3. 効率的です。

bashでランダム性を取得する効率的な方法は、$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は、その後、2767までの数字0の確率有する4 / 32767 9999 2768数字のみの確率たが、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暗号的に強力な擬似乱数ジェネレータが必要な場合、代わりに使用することを検討するかもしれません、そしてあなたが多くの時間、またはハードウェア乱数ジェネレータを持っている場合)、10進数ではないすべての文字を削除します出力を$MAX先頭の0の長さに切り取ります。たまたま0しか取得できなかった場合$rndは空なので、この場合はに設定rnd0ます。結果が範囲外かどうかを確認し、そうであれば、繰り返します。ループをエミュレートするという精神でdo ... whilernd最初に定義されていないため、少なくとも1回はボディの実行を強制するために、whileループの「ボディ」をガードに強制しました。

ここで条件1と2を満たしたと思いますが、今では条件3を台無しにしました。それはちょっと遅いです。1秒ほどかかります(運が良ければ10分の1秒)。実際には、ループは終了することさえ保証されていません(ただし、終了の確率は時間の経過とともに1に収束します)。

事前に指定された潜在的に大きな範囲内で、bashで不偏ランダム整数を取得する効率的な方法はありますか?(時間が許せば調査を続けますが、その間、ここの誰かがクールなアイデアを持っているかもしれないと思いました!)

回答表

  1. 最も基本的な(したがって移植性のある)アイデアは、十分な長さのランダムなビット列を生成することです。ランダムビット文字列を生成するには、bashの組み込み$RANDOM変数を使用する方法odと、and /dev/urandom(または/dev/random)を使用する方法があります。乱数がより大きい場合$MAX、最初からやり直してください。

  2. または、外部ツールを使用することもできます。

    • Perlソリューション
      • プロ:非常にポータブル、シンプル、柔軟
      • 対照:2 32 -1を超える非常に大きな数ではない
    • Pythonソリューション
      • プロ:シンプルで柔軟性があり、多数でも機能します
      • 対照:移植性が低い
    • zshソリューション
      • プロ:とにかくzshを使用する人に良い
      • 対照:おそらくさらに移植性が低い

ランダムビットをbase64エンコードしてから、必要な範囲に応じて特定の数の文字をエンコードされた形式からbase64からbase10に変換するのではなく、整数のみを選択するのはなぜですか?
ムル

それ bash である必要がありますか?たい何かrand=$(command)場合の対処command戻り、あなたの要件を満たしてiteger?
テルドン

@muru実際にはいいアイデアです。私は似たようなアイデアを考えて、それを使ってdd if=/dev/urandom 2>/dev/nullそれをパイピングしましたod -t d(base64を迂回するのを避けます)が、変換がどのように起こり、本当に偏っていないかはわかりません。アイデアを効率的で実用的なスクリプトに拡張し、バイアスがない理由を説明できれば、すばらしい答えになります。:)
マルテスコルッパ

@terdon私はbashを好むでしょう。私が意味する、もちろん、あなたが呼び出すことができるpythonか、perlまたはお好みの言語が、これはどこでも利用できません。よりポータブルなものが欲しいです。まあ、awkのランダム関数は問題ないでしょう。しかし、よりポータブル、より良い:)
マルタSkoruppa

2
はい、私はの線に沿って考えていましたperl -e 'print int(rand(2**32-1))');。これは非常に移植性が高く、非常に高速です。ほとんどの実装は同じシードから開始されるため、Awkはそれを削減しません。したがって、後続の実行で同じ乱数を取得します。同じ実行内でのみ変更されます。
テルドン

回答:


17

私はここから別の興味深い方法を見ます

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

これも良い選択肢のようです。ランダムデバイスから4バイトを読み取り、0との間の符号なし整数としてフォーマットします2^32-1

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

7
必要だとわかっている場合を除き、使用/dev/urandomする必要があり/dev/randomます。/dev/randomLinuxでブロックします。
jfs 14

なぜodコマンドが異なるのですか。どちらも、4バイトの符号なし整数を出力するだけです:1番目-opensslから、2番目-から/dev/random
jfs 14

1
@Rameshの/dev/urandom代わりに使用するように編集しました/dev/random-を使用する理由はありませ/dev/randomん。本当に高価/遅いか、システムの他の部分が遅くなる可能性があります。(自由に編集して、本当に必要かどうかを説明してください。)
Volker Siegel 14

1
心配する必要はありません。この単純な違いが非常に複雑な効果をもたらすのは本当に驚くべきことです。だからこそ、例を正しいものに変えようと主張しました。人々は例から学ぶのです。
フォルカーシーゲル14

1
@MalteSkoruppa:これIは、原則sizeof(int)よりも少ないかもしれません4。ところで、od -DAn失敗しますが(2**32-1)、動作しod -N4 -tu4 -An続けます。
jfs 14

8

すばらしい回答をありがとうございました。私は共有したい次の解決策になりました。

理由と方法についてさらに詳しく説明する前に、tl; drを紹介します。これは、私の新しいスクリプトです:-)

#!/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と、与えられた任意の範囲の整数をサンプリングできるbashの甘いランダム関数が利用可能になります。範囲には、負の整数と正の整数を含めることができ、最大長は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

他の回答者によるすべてのアイデアは素晴らしかった。terdonJF Sebastian、およびjimmijの回答では、外部ツールを使用して、タスクをシンプルかつ効率的な方法で実行しました。ただし、移植性を最大限に高めるためには真のbashソリューションを好みました。

Rameshl0b0の回答が使用される/dev/urandom/dev/random、または組み合わせて使用されodます。ただし、この方法はバイト、つまり長さ8のビット文字列をサンプリングするため、nに対して0から2 8n -1の範囲のランダムな整数しかサンプリングできないという欠点がありました。これらは非常に大きなジャンプですnを増やします。

最後に、Falcoの答えは、2のべき乗だけでなく、任意の範囲に対してこれをどのように行うことができるかについての一般的な考えを説明しています。基本的に、与えられた範囲{0..max}に対して、次の2のべき乗、つまりビット文字列として表現するのに必要なビット数を決定できmaxます。次に、そのビットだけをサンプリングして、このバイストリングが整数であるかどうかを確認できますmax。その場合、繰り返します。表現maxに必要なだけのビットをサンプリングするため、各反復には、成功の50%(最悪の場合は50%、最良の場合は100%)以上の確率があります。したがって、これは非常に効率的です。

私のスクリプトは基本的にFalcoの回答の具体的な実装であり、bashの組み込みビット単位操作を使用して目的の長さのビット文字列をサンプリングするため、純粋なbashで記述され、非常に効率的です。さらに、Eliah Kaganによるアイデアを尊重します。このアイデアは$RANDOM、の繰り返しの呼び出しから生じるビット文字列を連結することにより、組み込み変数を使用することを提案しています$RANDOM。私は実際に使用する可能性の両方を実装/dev/urandomして$RANDOM。デフォルトでは、上記のスクリプトはを使用し$RANDOMます。(そして、使用/dev/urandomする場合、odtrが必要ですが、これらはPOSIXによってサポートされています。)

それでは、どのように機能しますか?

私がこれに入る前に、2つの観察:

  1. bashは2 63 -1 より大きい整数を処理できないことがわかりました。自分で見て:

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

    bashは内部で符号付き64ビット整数を使用して整数を格納しているようです。したがって、2 63で「ラップアラウンド」し、負の整数を取得します。したがって、使用する任意のランダム関数で2 63 -1を超える範囲を取得することはできません。Bashは単にそれを処理できません。

  2. 我々は間の任意の範囲の値にサンプリングしたいときminmax可能性を持つがmin != 0、我々は単に間の値をサンプリングすることができます0し、max-min代わりにして、追加min最終的な結果に。これは負のmin場合でも機能しますが、の絶対値間の値をサンプリングするよう注意する必要があります。それでは、私たちは、間のランダムな値サンプリングする方法に焦点を当てることができますし、任意の正の整数を。残りは簡単です。max0 max-min0max

ステップ1:整数(対数)を表すのに必要なビット数を決定する

そのため、指定された値maxについて、ビット文字列として表現するために必要なビット数を知りたいのです。これにより、後で必要なビットだけをランダムにサンプリングできるため、スクリプトが非常に効率的になります。

どれどれ。ためnのビット、我々は値2まで表すことができるN -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強い理由がある場合でも)bashの組み込み$RANDOM変数を使用することです。$RANDOM最初にそれを行う方法を見てみましょう。

オプションA:使用 $RANDOM

これは、Eliah Kaganが言及したアイデアを使用しています。基本的に、$RANDOM15ビット整数$((RANDOM<<15|RANDOM))をサンプリングするため、30ビット整数のサンプリングに使用できます。つまり、最初の呼び出しを$RANDOM15ビット左にシフトし、ビット単位または2回目の呼び出しで$RANDOM、2つの独立してサンプリングされたビット文字列を連結します(または少なくともbashの組み込みと同じくらい独立してい$RANDOMます)。

これを繰り返して、45ビットまたは60ビットの整数を取得できます。その後、bashはそれを処理できなくなりますが、これは0〜2 60 -1のランダムな値を簡単にサンプリングできることを意味します。したがって、nビット整数をサンプリングするには、長さが15ビットステップで増加するランダムビット文字列の長さがn以上になるまで手順を繰り返します。最後に、ビット単位で右に適切にシフトすることにより、多すぎるビットを切り取り、最終的にnビットのランダムな整数にします。

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) ))
}

オプションB:使用 /dev/urandom

または、とを使用od/dev/urandomてnビット整数をサンプリングすることもできます。odは、バイト、つまり長さ8のビット文字列を読み取ります。前の方法と同様に、サンプリングされたビットの等価数がn以上になるほど多くのバイトをサンプリングし、多すぎるビットを切り取ります。

少なくともnビットを取得するために必要な最小バイト数は、n以上の8の最小倍数、つまりfloor((n + 7)/ 8)です。

これは、最大56ビットの整数でのみ機能します。さらに1バイトをサンプリングすると、64ビットの整数、つまり、bashが処理できない最大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、今ビットビット文字列を、私たちは、範囲内のサンプル整数にしたい0max一様にランダムに、どこmax必ずしも、2の累乗任意でよいです。(バイアスを作成するため、モジュロは使用できません。)

値を表現するのに必要なだけのビットをサンプリングしようと努力した理由はmax、ループを安全に(そして効率的に)使用して、nより低い値をサンプリングするまで-bitビット文字列を繰り返しサンプリングできるようになったからですまたはに等しいmax。最悪の場合(max2のべき乗)、各反復は50%の確率で終了し、最良の場合(max2のべき乗-1)、最初の反復は確実に終了します。

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
}

物事をまとめる

最後に、我々は間のサンプル整数にしたいminmaxminそしてmax任意の、さえ否定することができます。前述のように、これは今では簡単です。

すべてをbashスクリプトに入れましょう。いくつかの引数解析のものを行う...我々は2つの引数たいminmax、あるいは唯一の引数maxminデフォルトにします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

...と、最終的には、間のランダムなA値で均一にサンプリングするminmax、我々は間のランダムな整数のサンプル0との絶対値をmax-min、そして追加min最終的な結果に。:-)

diff=$((max-min)) && diff=${diff#-}

echo $(( $(rand $diff) + min ))

これに触発され、私はdieharderを使用してこのPRNGのテストとベンチマークを試み、私の発見をここに入れようとします。:-)


ソリューションは、次のことを前提としていますsizeof(int) == 8(64ビット)--format=u
jfs

1
あなたのソリューションは、random.pyがどのように書かれているかを思い出させてくれます。random.Randomクラスは53ビットを使用しますか?任意の大きな乱数(複数の呼び出し)を返すジェネレータrandom.SystemRandomは、を使用しos.urandom()て実装できるものを使用して同じことを行い/dev/urandomます。
jfs

uLは、範囲に対してsizeof(long)> = 8を意味します。保証されません。u8を使用して、プラットフォームにそのような整数があることをアサートできます。
jfs 14

@JFSebastianこれまでのところ、私のスクリプトはlong intのサイズに関する仮定をハードコーディングしないと考えていました。潜在的に、長い符号付き整数のサイズが64ビット(128ビットなど)よりも大きい(または小さい)場合でも機能します。ただし、使用する場合は--format=u8、仮定をハードコーディングしsizeof(int)==8ます。一方、使用する場合--format=uLは問題ありません。64ビット整数を持つプラットフォームがあり、それでもlong intをより低いものとして定義しているとは思いません。したがって、基本的には--format=uL柔軟性を高めることができると主張します。あなたの考えは何ですか?
マルテスコルッパ14

そこにあるlong longいくつかのプラットフォームでint型=長い= 32ビットながら、それは64ビットすることができます。すべてのプラットフォームで保証できない場合、0..2 ** 60の範囲を要求しないでください。一方、bashはこのようなプラットフォームではこの範囲自体をサポートしていない可能性があります(おそらく、maxint_tを使用し、固定範囲をアサートしたい場合はu8がより正確odです(範囲がbashのプラットフォームに依存する範囲は何ですか?)bashの範囲がsizeof longに依存する場合、uLの方が適切かもしれません)。bashがすべてのOSでサポートする全範囲または固定範囲が必要ですか?
jfs 14

6

zshにできますか?

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

シードも使用したい場合がありrand48(seed)ます。参照してくださいman zshmodulesman 3 erand48興味があれば詳細な説明のために。


私は個人的にzshを使用しませんが、これは素晴らしい追加です:)
Malte Skoruppa 14


5

あなたがから数たい場合は0通じ(2 ^ n)を-1どこN MOD 8 = 0あなたは、単に取得することができますN / 8からバイトを/dev/random。たとえば、ランダムの10進表現を取得するには、int次のようにします。

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

n ビットだけを取得する場合は、最初にceiling(n / 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 ^(n * 8)-1ビットの固定範囲があるという欠点があります(nはバイト数)。私は、最大 2 ^ 32-1 までの任意の範囲のメソッドを好みますが、それより低いものも好きです。これにより、バイアスの難しさが生じます。
マルテスコルッパ14

/dev/urandom代わりに使用するように編集されています/dev/random-を使用する理由はありません/dev/randomが、本当に高価/遅いか、システムの他の部分が遅くなる可能性があります。(自由に編集して、本当に必要かどうかを説明してください。)
Volker Siegel 14

それは正反対でなければなりません:/ dev / randomが必要だとわかっているのでない限り、/ dev / urandomを使用してくださいほとんどの場合、urandomを使用できない/dev/urandomよりも結果が非常に悪いと仮定するのは正しく/dev/randomありません。一度初期化されます(システムの開始時)。その結果は、Linux上のほとんどすべてのアプリケーションと同じくらい良好です。一部のシステムでは、randomとurandomは同じです。/dev/urandom/dev/random
jfs 14

1
--format=u理論よりも小さい可能性がある--format=u4ため、に置き換える必要がsizeof(int)あります4
jfs 14

@JFSebastian この論文では、この主題に関する非常に興味深い議論があります。彼らの結論は、両方とも不十分であり、「Linuxは、適切なシードエントロピーを収集し、その後のように動作するまでブロックする安全なRNGを追加する必要がある」/dev/randomと思われます。/dev/urandomurandom
l0b0 14

3

外部ツールの使用に反対しないと仮定すると、これは要件を満たしているはずです。

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

randパラメータとして上限をとるperlの関数を使用しています。好きなように設定できます。これが抽象的な数学的定義の真のランダム性にどれだけ近いかは、このサイトの範囲を超えていますが、非常に機密性の高い暗号化などに必要な場合を除き、問題ないはずです。おそらくそこにいたとしても、私は意見を述べることはありません。



1
@JFSebastianはい、そうです。OPが指定されているのでこれを投稿しました1^32-1が、より大きな数値に調整する必要があります。
テルドン

2

必要な最大値に等しいかそれ以上の最も近い(2 ^ X)-1を取得し、ビット数を取得する必要があります。次に、/ dev / randomを複数回呼び出し、十分になるまですべてのビットを追加し、多すぎるすべてのビットを切り捨てます。結果の数が最大繰り返し数より大きい場合。最悪の場合、最大値を下回る乱数を取得する可能性は50%を超えるため、(この最悪の場合)平均で2回の呼び出しが行われます。


これは、効率を改善するために実際にはかなり良い考えです。Rameshの回答l0b0の回答はどちらも基本的にからランダムビットを取得します/dev/urandomが、両方の回答では常に8ビットの倍数です。odあなたがうまく説明しているように、ループは2回の反復の予想数しか持っていないので、10進数にフォーマットする前に低範囲に対して多すぎるビットを切り捨てることは効率を改善するための良い考えです。上記の回答のいずれかと組み合わせて、これはおそらく進むべき道です。
マルテスコルッパ14

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.