整数ランダムを使用して、特定の精度で特定の範囲の実際の乱数を生成することは可能ですか?ジェネレーター$ RANDOM?たとえば、0から1までの4つの精度で実数を生成するにはどうすればよいですか?
0.1234 0.0309 0.9001 0.0000 1.0000
簡単な回避策:
printf "%d04.%d04\n" $RANDOM $RANDOM
コメント
- “実数の意味を指定してください”。粒子崩壊のようなものによって生成された乱数のソースが必要ですか、それとも疑似乱数ジェネレーターに満足しますか?これらの数の暗号的または科学的重要性を適用していますか、それとも”ランダムに見えるものが必要ですか”。
- …または、実際には” float “または”フローティングを意味しますかポイント番号?
- コメントありがとうございます。 $ RANDOMに基づく浮動小数点数用の疑似乱数ジェネレーターが必要です。
- … bashでメタヒューリスティックアルゴリズムを実装するため。
回答
awk -v n=10 -v seed="$RANDOM" "BEGIN { srand(seed); for (i=0; i<n; ++i) printf("%.4f\n", rand()) }"
これにより、n
の乱数が出力されます(例では10)。 [0,1)の範囲で、小数点以下4桁です。 awk
のrand()
関数を使用します(標準のawk
にはありませんが、最も一般的に実装されていますawk
実装)、その範囲のランダムな値を返します。乱数ジェネレーターは、シェルの$RANDOM
変数によってシードされます。
awk
プログラムにawk
のみがある場合div id = “84696bfc3f”>
ブロック(および他のコードブロックなし)、awk
は標準の入力ストリームから入力を読み取ろうとしません。
任意のOpenBSDシステム(または同じ jot
ユーティリティを備えたシステム、元々は4.2BSD)では、次のようになります。指定されたとおりに10個の乱数を生成します。
jot -p 4 -r 10 0 1
コメント
- 出力以来、厳密に言えば
rand()
は[0,1)内の浮動小数点数であり、小数点以下4桁に四捨五入すると、’正確に均等に分散されない可能性があります。フロートの精度が無限である場合はそうですが、’ t:’はランダムビットから生成される可能性があります、したがって2 ^ Nの異なる値があり、 ‘ 1000個の値のセットに均一にマッピングされません。ただし、これらの疑似乱数フロートに十分なビットがあり、’実際に正確なことを何もしていない限り、おそらく’ t
回答
別の回答で指摘されているように、生成に使用できるユーティリティは他にもあります。乱数。この回答では、リソースを$RANDOM
といくつかの基本的な算術関数に制限しています。
浮動小数点数については、
$RANDOM
は0から32767までの数値しか生成しないため、最高の精度が得られます。(32767を含む!)しかし、私は “また、bc
を呼び出すことで、基本的な算術関数の使用に関するルールを破りました。
しかし、先に進む前に、2つの問題を確認したいと思います精度浮動小数点数の場合はおよび範囲。その後、整数の範囲を生成する方法を見ていきます(整数を生成できる場合は、後で除算して、目的のユーティリティを使用して小数を取得できます)。
精度
$RANDOM/32768
のアプローチを取る、$RANDOM
は0から32767までの値を生成し、$RANDOM/32768
の結果も同様に有限の数の値になります。言い換えれば、それはまだ離散確率変数です(そして、コンピューターを使用すると、その事実から逃れることはできません)。そのことを念頭に置いて、printf
を使用することである程度の精度を達成できます。
より細かいカバーが必要な場合間隔では、ベース32768で考え始めることができます。したがって、理論的には、$RANDOM + $RANDOM*32768
は0から1,073,741,823の間の一様分布を与えるはずです。しかし、コマンドラインがその精度をうまく処理できるかどうかは疑わしいです。この特定のケースに関連するいくつかのポイント:
- 一般的に均一ではない2つの独立した均一に分布した確率変数の合計。この場合、少なくとも理論的には(3番目のポイントを参照)、そうです。
-
$RANDOM + $RANDOM*32768 = $RANDOM * ( 1 + 32768 )
を単純化できるとは思わないでください。$RANDOM
の2つの発生は、実際には2つの異なるイベントです。 -
$RANDOM
がどのようになっているのかよくわかりません。このように2回呼び出すと、2つの独立したランダムイベントが本当に生成されるかどうかを知るために生成されます。
範囲
$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
。
このためのbashスクリプトの記述
計算
は苦痛のように聞こえます。しかし、実際にはそうではありません。次のように取得できます。
q*b = 32768 - ( 32768 % b )
Bashでは、これは
次のコードは、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)
全体で真に均一な分布の場合、平均で。
ただし、上記のスニペットを実行するとわかるように、代わりに314.432
または。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
を使用するこのアプローチがおそらく期待どおりに機能していないことを確認できるようにします。言い換えると、どの整数が生成され、どの整数が完全に欠落しているかを考えてください。かなりの数がスキップされます。かなりの数が2倍になっています。
回答
シェルのprintfが形式(bash ksh zshなど)であるため、内部ベース変更(hex-> dec)を実行できます([0,1)
の範囲は0.00003から均一です。 to 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)に基づいています。これらは暗号化されていません。 Secure Pseudo Random Number Generators(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は生成する最小番号です。(N
MAXは排他的であるため、N+1
MAXとMINの両方を含める必要があります。
または、代わりに$(shuf -i MIN-MAX -n 1)
を使用できます。
from 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
-n 1
shufの/ div>は、ここで1つの乱数のみを生成することを意味します。
これにより、先行ゼロを含む 0〜9999 の乱数が生成されます。 printf
を使用(結果として、番号 1
は排他的です)。
printf "0.%04d\n" $(( RANDOM % 1000 )) 0.0215
コメント
- これまた、Nが32767($ RANDOMの上限)の除数である場合を除いて、指定された範囲で真の乱数を生成しません。
回答
オンバッシュ
bc -l <<< "scale=4 ; $((RANDOM % 10000 ))/10000"
ここで、1/10000
はランダムです精度と4
桁の出力精度
回答
zsh
のivid =” 2002b32e4dには、rand48()
算術関数(erand48()
標準関数のラッパー)があります。 “>
モジュール:
zmodload zsh/mathfunc printf "%.4f\n" $((rand48()))
$RANDOM
は15ビットですが、疑似ランダムで再現可能ですが、 bash
5.1+には、利用可能な場合は真にランダムなソースに基づいて、より安全な32ビット整数$SRANDOM
があります。浮動小数点演算はサポートしていませんが、少なくともawk
の疑似乱数ジェネレーターをシードするために使用できます(それ以外の場合は、デフォルトでtime()
):
echo "$SRANDOM" | awk " { srand($1) for (i = 0; i < 20; i++) printf "%.4f\n", rand() }"
(覚えておいてください “はまだ32ビットのエントロピーであり、awk
は、そのシードに基づいて決定論的な疑似ランダム生成を行います)