shell生成隨機數的幾種方法


shell生成隨機數的幾種方法

cat random_num.sh

!/bin/bash

top=10 #your number toplimit
number=30 #large than top;
while [ "$number" -ge $top ]
do
number=$RANDOM
done
echo "$number"

number2=$(($RANDOM%10))
echo "$number2"

cat random_num.sh

!/bin/bash

number2=$(($RANDOM%$1))
echo "$number2"


[1]
真正的隨機事件(在它存在的范圍內),只發生在特定的幾個未知的自然界現象中,比如放射性衰變.計算機只能產生模擬的隨機事件,並且計算機產生的"隨機"數因此只能稱為偽隨機數.
[2]
計算機產生的偽隨機數序列用的種子可以被看成是一種標識標簽.比如,使用種子23所產生的偽隨機數序列就被稱作序列#23.
一個偽隨機序列的特點就是在這個序列開始重復之前的所有元素的個數的和,也就是這個序列的長度.一個好的偽隨機產生算法將可以產生一個非常長的不重復的序列.

1、在之前,先介紹一個生成隨機數的方法,生成0 - 32767之間的整數隨機數。
echo $RANDOM

2、一個簡單的方法,生成一個 0 - * 的隨機數
如果你需要一個小於某個上限的隨機整數,應該增加測試以便拋棄所有小於此下限值的數值.

!/bin/sh

top=36
number=48 #初始化,否則報錯,不能進行比較,應大於top的隨意的值。
while [ "$number" -ge $top ]
do
number=$RANDOM
done
echo "Random number littler than $top --- $number"

3、使用awk生成0-1之間的隨機數

!/bin/sh

awkscript='{ srand(); print rand() }'
echo |awk "$awkscript"

4、下面的腳本生成指定范圍內的隨機整數。

!/bin/bash randomBetween() { # 產生一個正的或者負的隨機數. #+ 在$max 和$max 之間 #+ 並且可被$divisibleBy 整除的. # 給出一個合理的隨機分配的返回值. # # Bill Gradwohl - Oct 1, 2003 syntax() {

在函數中內嵌函數

echo
echo "Syntax: randomBetween [min] [max] [multiple]"
echo
echo "Expects up to 3 passed parameters, but all are completely optional."
echo "min is the minimum value"
echo "max is the maximum value"
echo "multiple specifies that the answer must be a multiple of this value."
echo " i.e. answer must be evenly divisible by this number."
echo
echo "If any value is missing, defaults area supplied as: 0 32767 1"
echo "Successful completion returns 0, unsuccessful completion returns"
echo "function syntax and 1."
echo "The answer is returned in the global variable randomBetweenAnswer"
echo "Negative values for any passed parameter are handled correctly." }

默認值分配,用來處理沒有參數傳遞進來的時候.

local x
local spread

確認divisibleBy 是正值.

[ ${divisibleBy} -lt 0 ] && divisibleBy=$((0-divisibleBy))

完整性檢查.

if [ $# -gt 3 -o ${divisibleBy} -eq 0 -o ${min} -eq ${max} ]; then
syntax return 1
fi

察看是否min 和max 顛倒了.

if [ ${min} -gt ${max} ]; then

交換它們.

x=${min}
min=${max}
max=${x}
fi #

如果min 自己並不能夠被$divisibleBy 整除,

+ 那么就調整min 的值,使其能夠被$divisibleBy 整除,前提是不能放大范圍.

if [ $((min/divisibleBydivisibleBy)) -ne ${min} ]; then
if [ ${min} -lt 0 ]; then
min=$((min/divisibleBy
divisibleBy))
else
min=$((((min/divisibleBy)+1)*divisibleBy))

fi
fi

如果min 自己並不能夠被$divisibleBy 整除,

+ 那么就調整max 的值,使其能夠被$divisibleBy 整除,前提是不能放大范圍.

if [ $((max/divisibleBydivisibleBy)) -ne ${max} ]; then
if [ ${max} -lt 0 ]; then
max=$((((max/divisibleBy)-1)
divisibleBy))
else max=$((max/divisibleBy*divisibleBy))
fi
fi

---------------------------------------------------------------------

現在,來做真正的工作.

注意,為了得到對於端點來說合適的分配,

+ 隨機值的范圍不得不落在

+ 0 和 abs(max-min)+divisibleBy 之間, 而不是 abs(max-min)+1.

對於端點來說,

+ 這個少量的增加將會產生合適的分配.

修改這個公式,使用abs(max-min)+1 來代替abs(max-min)+divisibleBy 的話,

+ 也能夠產生正確的答案, 但是在這種情況下生成的隨機值對於正好為端點倍數

+ 的這種情況來說將是不完美的,因為在正好為端點倍數的情況的隨機率比較低,

+ 因為你才加1 而已,這比正常的公式所產生的機率要小得多(正常為加divisibleBy)

---------------------------------------------------------------------

spread=$((max-min))
[ ${spread} -lt 0 ] && spread=$((0-spread))
let spread+=divisibleBy
randomBetweenAnswer=$(((RANDOM%spread)/divisibleBy*divisibleBy+min))
return 0

然而,Paulo Marcel Coelho Aragao 指出

+ 當$max 和$min 不能被$divisibleBy 整除時,

+ 這個公式將會失敗.

他建議使用如下的公式:

rnumber = $(((RANDOM%(max-min+1)+min)/divisibleBy*divisibleBy))

}

讓我們測試一下這個函數.

min=-14
max=20
divisibleBy=3

產生一個數組answers,answers 的下標用來表示在范圍內可能出現的值,

+ 而內容記錄的是對於這個值出現的次數,如果我們循環足夠多次,一定會得到

+ 一次出現機會.

declare -a answer
minimum=${min}
maximum=${max}
if [ $((minimum/divisibleBydivisibleBy)) -ne ${minimum} ]; then
if [ ${minimum} -lt 0 ]; then
minimum=$((minimum/divisibleBy
divisibleBy))
else
minimum=$((((minimum/divisibleBy)+1)*divisibleBy))
fi
fi

如果maximum 自己並不能夠被$divisibleBy 整除,

+ 那么就調整maximum 的值,使其能夠被$divisibleBy 整除,前提是不能放大范圍.

if [ $((maximum/divisibleBydivisibleBy)) -ne ${maximum} ]; then
if [ ${maximum} -lt 0 ]; then
maximum=$((((maximum/divisibleBy)-1)
divisibleBy))
else
maximum=$((maximum/divisibleBy*divisibleBy))
fi
fi

我們需要產生一個下標全為正的數組,

+ 所以我們需要一個displacement 來保正都為正的結果.

displacement=$((0-minimum))
for ((i=${minimum}; i<=${maximum}; i+=divisibleBy)); do
answer[i+displacement]=0
done

main function

if [ $# -lt 2 ]; then
echo "Usage: $0 [divisible]"
echo

echo "e.g $0 2 100 3"
echo
exit
fi
min=${1:-0}
max=${2:-32767}
divisibleBy=${3:-1}
randomBetween ${max} ${min} ${divisibleBy}
echo ${randomBetweenAnswer}
exit

補充
產生隨機整數

1 #!/bin/bash
2
3 # 每次調用$RANDOM都會返回不同的隨機整數.
4 # 范圍為: 0 - 32767 (帶符號的16位整數).
5
6 MAXCOUNT=10
7 count=1
8
9 echo
10 echo "$MAXCOUNT random numbers:"
11 echo "-----------------"
12 while [ "$count" -le $MAXCOUNT ] # 產生10($MAXCOUNT)個隨機整數.
13 do
14 number=$RANDOM
15 echo $number
16 let "count += 1" # 增加計數.
17 done
18 echo "-----------------"
19
20 # 如果你需要某個范圍的隨機整數,可以使用取模操作符.(譯者注:事實上,這不是一個非常好的辦法。理由請見man 3 rand)
21 # 取模操作會返回除法的余數.
22
23 RANGE=500
24
25 echo
26
27 number=$RANDOM
28 let "number %= $RANGE"
29 # ^^
30 echo "Random number less than $RANGE --- $number"
31
32 echo
33
34
35
36 # 如果你需要一個大於某個下限的隨機整數,
37 #+ 應該增加測試以便拋棄所有小於此下限值的數值.
38
39 FLOOR=200
40
41 number=0 #初始化
42 while [ "$number" -le $FLOOR ]
43 do
44 number=$RANDOM
45 done
46 echo "Random number greater than $FLOOR --- $number"
47 echo
48
49 # 讓我們檢測另外一個完成上面循環作用的簡單辦法,即
50 # let "number = $RANDOM + $FLOOR"
51 # 這能避免了while循環,並且運行得更快。
52 # 但,使用這個技術可能會產生問題,思考一下是什么問題?
53
54
55
56 # 聯合上面兩個技巧重新產生在兩個限制值之間的隨機整數.
57 number=0 #初始化
58 while [ "$number" -le $FLOOR ]
59 do
60 number=$RANDOM
61 let "number %= $RANGE" # Scales $number down within $RANGE.
62 done
63 echo "Random number between $FLOOR and $RANGE --- $number"
64 echo
65
66
67
68 # 產生二元值,即"真"或"假".
69 BINARY=2
70 T=1
71 number=$RANDOM
72
73 let "number %= $BINARY"
74 # 注意 let "number >>= 14" 會產生更平均的隨機分布 #(譯者注:正如在man手冊里提到的,更高位的隨機分布更平均,
75 #+ (除了最后的二元值右移出所有的值). #取模操作使用低位來產生隨機會相對不平均)
76 if [ "$number" -eq $T ]
77 then
78 echo "TRUE"
79 else
80 echo "FALSE"
81 fi
82
83 echo
84
85
86 # 模擬擲骰子.
87 SPOTS=6 # 模除 6 會產生 0 - 5 之間的值.
88 # 結果增1會產生 1 - 6 之間的值.
89 # 多謝Paulo Marcel Coelho Aragao的簡化.
90 die1=0
91 die2=0
92 # 這會比僅設置SPOTS=7且不增1好?為什么會好?為什么會不好?
93
94 # 單獨地擲每個骰子,然后計算出正確的機率.
95
96 let "die1 = $RANDOM % $SPOTS +1" # 擲第一個.
97 let "die2 = $RANDOM % $SPOTS +1" # 擲第二個.
98 # 上面的算術式中,哪個操作符優先計算 --
99 #+ 取模 (%) 還是 加法 (+)?
100
101
102 let "throw = $die1 + $die2"
103 echo "Throw of the dice = $throw"
104 echo
105
106
107 exit 0


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM