Integer Random Generator $ RANDOMを使用して、特定の精度で特定の範囲の実際の乱数を生成することは可能ですか?たとえば、0と1の間の4つの精度で実数を生成するにはどうすればよいですか?
0.1234
0.0309
0.9001
0.0000
1.0000
簡単な回避策:
printf "%d04.%d04\n" $RANDOM $RANDOM
_awk -v n=10 -v seed="$RANDOM" 'BEGIN { srand(seed); for (i=0; i<n; ++i) printf("%.4f\n", Rand()) }'
_
これにより、[0,1)の範囲の10進数4桁のn
乱数(この例では10)が出力されます。 awk
のRand()
関数を使用します(標準のawk
ではなく、最も一般的なawk
実装によって実装されます)。その範囲のランダムな値を返します。乱数ジェネレーターは、シェルの_$RANDOM
_変数によってシードされます。
awk
プログラムにBEGIN
ブロックしかない(他のコードブロックがない)場合、awk
は標準入力ストリームから入力を読み取ろうとしません。
OpenBSDシステム(または、同じ jot
ユーティリティ が元の4.2BSDにあるシステム)では、次のように指定したとおりに10の乱数が生成されます。
_jot -p 4 -r 10 0 1
_
別の答えで指摘されているように、乱数を生成するために使用できる他のユーティリティがあります。この回答では、リソースを_$RANDOM
_といくつかの基本的な算術関数に制限しています。
浮動小数点数については、次のようなことを試してください
_printf '%s\n' $(echo "scale=8; $RANDOM/32768" | bc )
_
_$RANDOM
_は0〜32767の数値のみを生成するため(32767を含む!)、最高の精度が得られます。しかし、bc
を呼び出すことにより、基本的な算術関数の使用に関する私の規則も破りました。
しかし次に進む前に、2つの問題precisionとrange浮動小数点数の場合。その後、整数の範囲の生成について見ていきます(整数を生成できる場合は、後でそれを除算して10進数にすることができます。これを実現したいユーティリティを使用したい場合)。
精度
_$RANDOM/32768
_のアプローチを採用すると、_$RANDOM
_は0から32767までの値を生成するため、_$RANDOM/32768
_の結果も同様に有限の値になります。言い換えれば、それはまだ離散確率変数です(そして、コンピューターでは、その事実から逃れることはできません)。これを念頭に置いて、printf
を使用することで、ある程度の精度を達成できます。
間隔をより細かくカバーしたい場合は、ベース32768から考え始めることができます。したがって、理論的には、_$RANDOM + $RANDOM*32768
_は0から1,073,741,823までの均一な分布を与えるはずです。しかし、コマンドラインがその精度を非常にうまく処理できるかどうかは疑問です。この特定のケースに関するいくつかのポイント:
$RANDOM + $RANDOM*32768 = $RANDOM * ( 1 + 32768 )
を簡略化できるとは思わないでください。 _$RANDOM
_の2つの発生は、実際には2つの異なるイベントです。$RANDOM
_がどのように生成されるのか十分にわかりません。範囲
_$RANDOM/32768
_だけを考えてみましょう。範囲内の数値が必要な場合は、_[a,b)
_と言います。
_$RANDOM/32768*(b-a) + a
_
目的の範囲に着陸します。
整数値の生成
まず、_[0,b)
_の間で乱数を生成することを検討してください。ここで、b
は_32768
_より小さいです。製品_q*b
_について考えてみます。ここで、q
は_32768/b
_の整数部分です。次に、0から32767までの乱数を生成することができますが、_q*b
_以上の乱数を破棄します。このように生成された番号をG
に呼び出します。次に、G
は0から_q*b
_の範囲になり、その分布は均一になります。次に、モジュラー演算を適用して、この値を目的の範囲に絞り込みます。
_G % b
_
次のようにランダムに数値を生成することに注意してください
_$RANDOM % b
_
b
が_32768
_の除数の1つである場合を除いて、均一分布は作成されません。
このためのbashスクリプトを作成
上記のように_q*b
_を計算するのは面倒に聞こえます。しかし、実際にはそうではありません。次のようにして入手できます。
_q*b = 32768 - ( 32768 % b )
_
バッシュでは、これを得ることができます
_$((32768 - $((32768 % b)) ))
_
次のコードは、_0..b
_(b
を含まない)の範囲の乱数を生成します。 _b=$1
_
_m=$((32768 - $((32768 % $1)) ))
a=$RANDOM
while (( $a > $m ));
do
a=$RANDOM
done
a=$(($a % $1))
printf "$a\n"
_
補遺
技術的には、作業する理由はほとんどありません
_m=$((32768 - $((32768 % $1)) ))
_
以下は同じことを達成します
_a=$RANDOM
while (( $a > $1 ));
do
a=$RANDOM
done
printf "$a\n"
_
それははるかに多くの作業ですが、コンピュータは高速です。
より大きな範囲で整数を生成する
これを理解させましょう。注意が必要であり、ある時点で、算術演算を処理する際のコンピュータのメモリ制限を考慮する必要があります。
最終メモ
受け入れられた回答は、0から1まで一様に乱数を作成しません。
これを確認するには、次を試してください
_$ for i in {1..1000}; do echo .$RANDOM; done | awk '{ a += $1 } END { print a }'
_
_[0,1)
_の真に均一な分布の場合、平均は_0.500
_に近いはずです。
しかし、上記のスニペットを実行するとわかるように、代わりに_314.432
_または_322.619
_のようなものが取得されます。 1000の数字なので、平均は_.322
_です。この一連の生成された数値の真の平均は_.316362
_です。
Perlスクリプトを使用して、この真の平均を取得できます
_ Perl -e '{ $i=0;
$s=0;
while ( $i<=32767 )
{
$j = sprintf "%.5f", ".$i";
$j =~ s/^0\.//;
print "$j\n";
$s += $j;
$i++
};
printf "%.5f\n", $s/32767;
}'
_
ここに整数を追加して、_.$RANDOM
_を使用するこのアプローチが、あなたが最も望んでいることを実行していないことを確認できるようにしています。言い換えれば、どの整数が生成され、どの整数が完全に失われるかを考えてください。かなりの数がスキップされます。かなりの数が倍増しています。
シェルのprintfが%a
形式(bash ksh zshなど)を理解できるため、内部ベース変更(hex-> dec)([0,1)
の範囲で均一)を実行できるシステム0.00003から0.99997):
printf '%.5f\n' "$(printf '0x0.%04xp1' $RANDOM)"
$RANDOM
(0.000000001から0.999999999へ)への呼び出しを組み合わせることにより、さらに多くの桁を使用することもできます
printf '%.9f\n' "$(printf '0x0.%08xp2' $(( ($RANDOM<<15) + $RANDOM )))"
内部(シェルに対して)の「$ RANDOM」アルゴリズムは、線形フィードバックシフトレジスタ(LFSR)に基づいています。これらは、暗号的に安全な疑似乱数ジェネレータ(CSPRNG)ではありません。より適切なオプションは、/dev/urandom
デバイスからのバイトを使用することです。そのためには、外部の8進または16進ダンプを呼び出す必要があります。
$ printf '%.19f\n' "0x0.$(od -N 8 -An -tx1 /dev/urandom | tr -d ' ')"
0.7532810412812978029
$ printf '%.19f\n' "0x0.$(hexdump -n 8 -v -e '"%02x"' /dev/urandom)"
0.9453460825607180595
フロートを取得するための非常に単純な(ただし、均一ではない)ソリューションは次のとおりです。
printf '0.%04d\n' $RANDOM
[0,1)
(1を含まない)の範囲で均一にする方法:
while a=$RANDOM; ((a>29999)); do :; done; printf '0.%04d\n' "$((a%10000))"
$(( ( RANDOM % N ) + MIN ))
を使用します
N
をMAX番号で置き換え、MINを生成する最小番号で置き換えます(MAXは排他的であるため、N
は_N+1
_にして、MAXとMINの両方を含めます)。
または、代わりに$(shuf -i MIN-MAX -n 1)
を使用できます。
から _man shuf
_ :
_-i, --input-range=LO-HI
treat each number LO through HI as an input line
-n, --head-count=COUNT
output at most COUNT lines
_
ここでshuf
の_-n 1
_は、1つの乱数のみを生成することを意味します。
これは0〜9999の間の乱数を生成し、printf
を使用して先頭にゼロを付けます(結果として、数値1は排他的です)。
_printf "0.%04d\n" $(( RANDOM % 1000 ))
0.0215
_
バッシュで
bc -l <<< "scale=4 ; $((RANDOM % 10000 ))/10000"
どこ 1/10000
はランダムな精度であり、4
出力精度の桁数
zsh
には、_zsh/mathfunc
_モジュール内にRand48()
算術関数(erand48()
標準関数のラッパー)があります。
_zmodload zsh/mathfunc
printf '%.4f\n' $((Rand48()))
_