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

posted @ 2020-04-20 15:41  ChanixChen  阅读(5199)  评论(0编辑  收藏  举报