📄 randomvar.html
字号:
147 148 displacement=$((0-minimum)) 149 for ((i=${minimum}; i<=${maximum}; i+=divisibleBy)); do 150 answer[i+displacement]=0 151 done 152 153 154 # Now loop a large number of times to see what we get. 155 loopIt=1000 # The script author suggests 100000, 156 #+ but that takes a good long while. 157 158 for ((i=0; i<${loopIt}; ++i)); do 159 160 # Note that we are specifying min and max in reversed order here to 161 #+ make the function correct for this case. 162 163 randomBetween ${max} ${min} ${divisibleBy} 164 165 # Report an error if an answer is unexpected. 166 [ ${randomBetweenAnswer} -lt ${min} -o ${randomBetweenAnswer} -gt ${max} ] && echo MIN or MAX error - ${randomBetweenAnswer}! 167 [ $((randomBetweenAnswer%${divisibleBy})) -ne 0 ] && echo DIVISIBLE BY error - ${randomBetweenAnswer}! 168 169 # Store the answer away statistically. 170 answer[randomBetweenAnswer+displacement]=$((answer[randomBetweenAnswer+displacement]+1)) 171 done 172 173 174 175 # Let's check the results 176 177 for ((i=${minimum}; i<=${maximum}; i+=divisibleBy)); do 178 [ ${answer[i+displacement]} -eq 0 ] && echo "We never got an answer of $i." || echo "${i} occurred ${answer[i+displacement]} times." 179 done 180 181 182 exit 0</PRE></TD></TR></TABLE><HR></DIV><P>Just how random is <TTCLASS="VARNAME">$RANDOM</TT>? The best way to test this is to write a script that tracks the distribution of <SPANCLASS="QUOTE">"random"</SPAN> numbers generated by <TTCLASS="VARNAME">$RANDOM</TT>. Let's roll a <TTCLASS="VARNAME">$RANDOM</TT> die a few times . . .</P><DIVCLASS="EXAMPLE"><HR><ANAME="RANDOMTEST"></A><P><B>Example 9-27. Rolling a single die with RANDOM</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # How random is RANDOM? 3 4 RANDOM=$$ # Reseed the random number generator using script process ID. 5 6 PIPS=6 # A die has 6 pips. 7 MAXTHROWS=600 # Increase this if you have nothing better to do with your time. 8 throw=0 # Throw count. 9 10 ones=0 # Must initialize counts to zero, 11 twos=0 #+ since an uninitialized variable is null, not zero. 12 threes=0 13 fours=0 14 fives=0 15 sixes=0 16 17 print_result () 18 { 19 echo 20 echo "ones = $ones" 21 echo "twos = $twos" 22 echo "threes = $threes" 23 echo "fours = $fours" 24 echo "fives = $fives" 25 echo "sixes = $sixes" 26 echo 27 } 28 29 update_count() 30 { 31 case "$1" in 32 0) let "ones += 1";; # Since die has no "zero", this corresponds to 1. 33 1) let "twos += 1";; # And this to 2, etc. 34 2) let "threes += 1";; 35 3) let "fours += 1";; 36 4) let "fives += 1";; 37 5) let "sixes += 1";; 38 esac 39 } 40 41 echo 42 43 44 while [ "$throw" -lt "$MAXTHROWS" ] 45 do 46 let "die1 = RANDOM % $PIPS" 47 update_count $die1 48 let "throw += 1" 49 done 50 51 print_result 52 53 exit 0 54 55 # The scores should distribute fairly evenly, assuming RANDOM is fairly random. 56 # With $MAXTHROWS at 600, all should cluster around 100, plus-or-minus 20 or so. 57 # 58 # Keep in mind that RANDOM is a pseudorandom generator, 59 #+ and not a spectacularly good one at that. 60 61 # Randomness is a deep and complex subject. 62 # Sufficiently long "random" sequences may exhibit 63 #+ chaotic and other "non-random" behavior. 64 65 # Exercise (easy): 66 # --------------- 67 # Rewrite this script to flip a coin 1000 times. 68 # Choices are "HEADS" and "TAILS".</PRE></TD></TR></TABLE><HR></DIV><P>As we have seen in the last example, it is best to <SPANCLASS="QUOTE">"reseed"</SPAN> the <TTCLASS="VARNAME">RANDOM</TT> generator each time it is invoked. Using the same seed for <TTCLASS="VARNAME">RANDOM</TT> repeats the same series of numbers. <ANAME="AEN5208"HREF="#FTN.AEN5208">[2]</A> (This mirrors the behavior of the <TTCLASS="REPLACEABLE"><I>random()</I></TT> function in <ICLASS="FIRSTTERM">C</I>.)</P><DIVCLASS="EXAMPLE"><HR><ANAME="SEEDINGRANDOM"></A><P><B>Example 9-28. Reseeding RANDOM</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # seeding-random.sh: Seeding the RANDOM variable. 3 4 MAXCOUNT=25 # How many numbers to generate. 5 6 random_numbers () 7 { 8 count=0 9 while [ "$count" -lt "$MAXCOUNT" ] 10 do 11 number=$RANDOM 12 echo -n "$number " 13 let "count += 1" 14 done 15 } 16 17 echo; echo 18 19 RANDOM=1 # Setting RANDOM seeds the random number generator. 20 random_numbers 21 22 echo; echo 23 24 RANDOM=1 # Same seed for RANDOM... 25 random_numbers # ...reproduces the exact same number series. 26 # 27 # When is it useful to duplicate a "random" number series? 28 29 echo; echo 30 31 RANDOM=2 # Trying again, but with a different seed... 32 random_numbers # gives a different number series. 33 34 echo; echo 35 36 # RANDOM=$$ seeds RANDOM from process id of script. 37 # It is also possible to seed RANDOM from 'time' or 'date' commands. 38 39 # Getting fancy... 40 SEED=$(head -1 /dev/urandom | od -N 1 | awk '{ print $2 }') 41 # Pseudo-random output fetched 42 #+ from /dev/urandom (system pseudo-random device-file), 43 #+ then converted to line of printable (octal) numbers by "od", 44 #+ finally "awk" retrieves just one number for SEED. 45 RANDOM=$SEED 46 random_numbers 47 48 echo; echo 49 50 exit 0</PRE></TD></TR></TABLE><HR></DIV><P><ANAME="URANDOMREF"></A></P><DIVCLASS="NOTE"><TABLECLASS="NOTE"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/note.png"HSPACE="5"ALT="Note"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>The <TTCLASS="FILENAME">/dev/urandom</TT> device-file provides a method of generating much more <SPANCLASS="QUOTE">"random"</SPAN> pseudorandom numbers than the <TTCLASS="VARNAME">$RANDOM</TT> variable. <TTCLASS="USERINPUT"><B>dd if=/dev/urandom of=targetfile bs=1 count=XX</B></TT> creates a file of well-scattered pseudorandom numbers. However, assigning these numbers to a variable in a script requires a workaround, such as filtering through <AHREF="extmisc.html#ODREF">od</A> (as in above example and <AHREF="textproc.html#RND">Example 12-13</A>), or using <AHREF="extmisc.html#DDREF">dd</A> (see <AHREF="extmisc.html#BLOTOUT">Example 12-55</A>), or even piping to <AHREF="filearchiv.html#MD5SUMREF">md5sum</A> (see <AHREF="colorizing.html#HORSERACE">Example 33-14</A>).</P><P><ANAME="AWKRANDOMREF"></A></P><P>There are also other ways to generate pseudorandom numbers in a script. <BCLASS="COMMAND">Awk</B> provides a convenient means of doing this.</P><DIVCLASS="EXAMPLE"><HR><ANAME="RANDOM2"></A><P><B>Example 9-29. Pseudorandom numbers, using <AHREF="awk.html#AWKREF">awk</A></B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # random2.sh: Returns a pseudorandom number in the range 0 - 1. 3 # Uses the awk rand() function. 4 5 AWKSCRIPT=' { srand(); print rand() } ' 6 # Command(s) / parameters passed to awk 7 # Note that srand() reseeds awk's random number generator. 8 9 10 echo -n "Random number between 0 and 1 = " 11 12 echo | awk "$AWKSCRIPT" 13 # What happens if you leave out the 'echo'? 14 15 exit 0 16 17 18 # Exercises: 19 # --------- 20 21 # 1) Using a loop construct, print out 10 different random numbers. 22 # (Hint: you must reseed the "srand()" function with a different seed 23 #+ in each pass through the loop. What happens if you fail to do this?) 24 25 # 2) Using an integer multiplier as a scaling factor, generate random numbers 26 #+ in the range between 10 and 100. 27 28 # 3) Same as exercise #2, above, but generate random integers this time.</PRE></TD></TR></TABLE><HR></DIV><P>The <AHREF="timedate.html#DATEREF">date</A> command also lends itself to <AHREF="timedate.html#DATERANDREF">generating pseudorandom integer sequences</A>.</P></TD></TR></TABLE></DIV></DIV><H3CLASS="FOOTNOTES">Notes</H3><TABLEBORDER="0"CLASS="FOOTNOTES"WIDTH="100%"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="5%"><ANAME="FTN.AEN5174"HREF="randomvar.html#AEN5174">[1]</A></TD><TDALIGN="LEFT"VALIGN="TOP"WIDTH="95%"><P>True <SPANCLASS="QUOTE">"randomness,"</SPAN> insofar as it exists at all, can only be found in certain incompletely understood natural phenomena such as radioactive decay. Computers can only simulate randomness, and computer-generated sequences of <SPANCLASS="QUOTE">"random"</SPAN> numbers are therefore referred to as <ICLASS="EMPHASIS">pseudorandom</I>.</P></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="5%"><ANAME="FTN.AEN5208"HREF="randomvar.html#AEN5208">[2]</A></TD><TDALIGN="LEFT"VALIGN="TOP"WIDTH="95%"><P>The <ICLASS="FIRSTTERM">seed</I> of a computer-generated pseudorandom number series can be considered an identification label. For example, think of the pseudorandom series with a seed of <ICLASS="EMPHASIS">23</I> as <ICLASS="EMPHASIS">series #23</I>.</P><P>A property of a pseurandom number series is the length of the cycle before it starts repeating itself. A good pseurandom generator will produce series with very long cycles.</P></TD></TR></TABLE><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLEWIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="ivr.html">Prev</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="dblparens.html">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">Indirect References to Variables</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="variables2.html">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">The Double Parentheses Construct</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -