Bash:$ RANDOMを使用して乱数を生成する方法

整数ランダムを使用して、特定の精度で特定の範囲の実際の乱数を生成することは可能ですか?ジェネレーター$ 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桁です。 awkrand()関数を使用します(標準の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)ここで、b32768未満です。製品q*bについて考えてみます。ここで、q32768/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 1shufの/ 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は、そのシードに基づいて決定論的な疑似ランダム生成を行います)

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です