Advertisement
pintcat

whrandom.sh - POSIX compliant random number generator using Wichmann-Hill method

Oct 29th, 2023 (edited)
1,496
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 6.83 KB | Science | 0 0
  1. ######################################################################################################################
  2. # whrandom v2.17 - POSIX compliant random number generator using old or new improved Wichmann-Hill method from 2006. #
  3. # Handshake:                                                                                                         #
  4. # $WH_MAX contains the maximum value for the random number. If set to 0 no limiter will be applied (default: 0).     #
  5. # $WH_LOOP contains the number of random numbers to be generated. Set it to "U" for an unlimited random number       #
  6. #  generation (default: 1).                                                                                          #
  7. # $WH_PREC contains the precision level for the calculation. The lower the level the less percise and thus less      #
  8. #  random the result will be. Must be between 1 and 9 (default: 9).                                                  #
  9. # $WH_DEL contains the delimiter used to separate multiple values (default: \n (new line)).                          #
  10. # $WH_ALGO tells which algorithm will be used - WH_OLD, WH_NEW or WH_NEW64() (default: WH_NEW).                      #
  11. # $WH_RMETHOD tells the rounding method - A for arithmetic expression, P for parameter expansion (default: A)        #
  12. # Usage:                                                                                                             #
  13. # Simply call WH_RANDOM() to generate one or more random numbers. These numbers will be written to stdout.           #
  14. # The old Wichmann-Hill algorrithm requires 3, the new one 4 seeds each between 1 and 30000. By default, whrandom    #
  15. # automatically creates 4 unique seeds using the millisecond counter of the system clock. Alternatively, you can     #
  16. # call WH_RANDOM() with up to 4 integers. They will be checked and exchanged with automatically generated ones if    #
  17. # they don't fit the needs. Beware: If you use 4 fixed seeds whrandom will always create an identical chain of       #
  18. # random numbers as long as you use the same seeds.                                                                  #
  19. ######################################################################################################################
  20.  
  21. WH_MAX=0
  22. WH_LOOP=1
  23. WH_PREC=9
  24. WH_DEL="\n"
  25. WH_ALGO=WH_NEW
  26. WH_RMETHOD=A
  27.  
  28. # WH_CHECK() - checks if a value is given, if this value is a number and if it's between 1 and 30000. If so it
  29. #  returns that very number and if not it generates a suitable one using the system clock's nanosecond counter.
  30. # IN:  $1 should contain an integer between 1 and 30000.
  31. # OUT: Prints the fitting number to stdout.
  32.  
  33. WH_CHECK(){
  34.     if [ -n "${1##*[!0-9]*}" ] && [ $1 -gt 0 ] && [ $1 -le 30000 ]; then
  35.         printf $1
  36.     else # fetch 5 digits of nanoseconds; removes leading zeros & adds 1 to prevent zero; if value is >30000 divide by 4
  37.         WH_TMP=$(date +%5N)
  38.         [ $((WH_TMP=${WH_TMP#${WH_TMP%%[1-9]*}}+1)) -gt 30000 ] && WH_TMP=$(($WH_TMP/4))
  39.         printf $WH_TMP
  40.     fi
  41. }
  42.  
  43. # WH_OLD() - generates a random number using the older 16bit integer based algorithm.
  44. # IN:  $WH_S1, $WH_S2 & $WH_S3 contain the values (seeds) needed by the algorithm for computation.
  45. #      $WH_F contains a decimal factor to produce larger, more precise random integers.
  46. # OUT: $WH_RND contains the random number to be handed over to the core function for further operations.
  47.  
  48. WH_OLD(){
  49.     [ $((WH_S1=171*($WH_S1%177)-2*($WH_S1/177))) -lt 0 ] && WH_S1=$(($WH_S1+30269))
  50.     [ $((WH_S2=172*($WH_S2%176)-35*($WH_S2/176))) -lt 0 ] && WH_S2=$(($WH_S2+30307))
  51.     [ $((WH_S3=170*($WH_S3%178)-63*($WH_S3/178))) -lt 0 ] && WH_S3=$(($WH_S3+30323))
  52.     WH_RND=$(($WH_S1*$WH_F/30269+$WH_S2*$WH_F/30307+$WH_S3*$WH_F/30323))
  53. }
  54.  
  55. # WH_NEW() - generates a random number using the newer 32bit integer based algorithm.
  56. # IN:  $WH_S1, $WH_S2, $WH_S3 & $WH_S4 contain the values (seeds) needed by the algorithm for computation.
  57. #      $WH_F contains a decimal factor to produce larger, more precise random integers.
  58. # OUT: $WH_RND contains the random number to be handed over to the core function for further operations.
  59.  
  60. WH_NEW(){
  61.     [ $((WH_S1=11600*($WH_S1%185127)-10379*($WH_S1/185127))) -lt 0 ] && WH_S1=$(($WH_S1+2147483579))
  62.     [ $((WH_S2=47003*($WH_S2%45688)-10479*($WH_S2/45688))) -lt 0 ] && WH_S2=$(($WH_S2+2147483543))
  63.     [ $((WH_S3=23000*($WH_S3%93368)-19423*($WH_S3/93368))) -lt 0 ] && WH_S3=$(($WH_S3+2147483423))
  64.     [ $((WH_S4=33000*($WH_S4%65075)-8123*($WH_S4/65075))) -lt 0 ] && WH_S4=$(($WH_S4+2147483123))
  65.     WH_RND=$(($WH_S1*$WH_F/2147483579+$WH_S2*$WH_F/2147483543+$WH_S3*$WH_F/2147483423+$WH_S4*$WH_F/2147483123))
  66. }
  67.  
  68. # WH_NEW64() - same result as WH_NEW(), but uses 64bit integer based algorithm with less steps & thus being slightly faster.
  69.  
  70. WH_NEW64(){
  71.     WH_S1=$((11600*$WH_S1%2147483579))
  72.     WH_S2=$((47003*$WH_S2%2147483543))
  73.     WH_S3=$((23000*$WH_S3%2147483423))
  74.     WH_S4=$((33000*$WH_S4%2147483123))
  75.     WH_RND=$(($WH_S1*$WH_F/2147483579+$WH_S2*$WH_F/2147483543+$WH_S3*$WH_F/2147483423+$WH_S4*$WH_F/2147483123))
  76. }
  77.  
  78. # WH_RANDOM() - core function: prepares seeds and generates the output.
  79. # IN:  $1, $2, $3 and $4 can contain integers between 1 and 30000 to be used as seeds. These values will be checked and -
  80. #       if not suitable - replaced with auto generated ones.
  81. #      $WH_PREC is the precision level. Each seed is multiplied with 10^$WH_PREC to receive a larger, more accurate value.
  82. #      $WH_LOOP tells how many numbers will be generated. "U" will generate a never ending chain of random numbers.
  83. #      $WH_RND contains the random number which was handed over by the algorithm for further operations.
  84. #      $WH_MAX contains the maximum value which will not be exceeded by the random number. 0 leaves the result unaltered.
  85. #      $WH_DEL contains the delimiter which is placed after each value.
  86. #      $WH_RMETHOD tells the rounding method used if $WH_MAX is >0 - A for arithmetic expression, P for parameter expansion.
  87. # OUT: $WH_F contains a decimal factor used by the algorithm to produce larger, more precise random integers.
  88. #      $WH_SEEDS contains the original seeds used for the 1st iteration.
  89. #      $WH_RND contains the current random number
  90. #      Also prints the random numbers with delimiter appended to stdout.
  91.  
  92. WH_RANDOM(){
  93.     WH_F=10
  94.     WH_TMP=$WH_PREC
  95.     while [ $((WH_TMP=$WH_TMP-1)) -gt 0 ]; do
  96.         [ $WH_F -lt 1000000000 ] && WH_F=$(($WH_F*10)) || WH_TMP=1
  97.     done
  98.     WH_S1=$(WH_CHECK $1)
  99.     WH_S2=$(WH_CHECK $2)
  100.     WH_S3=$(WH_CHECK $3)
  101.     WH_S4=$(WH_CHECK $4)
  102.     WH_SEEDS="$WH_S1 $WH_S2 $WH_S3 $WH_S4"
  103.     while [ $WH_LOOP = U ] || [ $((WH_TMP=$WH_TMP+1)) -le $WH_LOOP ]; do
  104.         $WH_ALGO
  105.         if [ $WH_MAX -gt 0 ]; then
  106.             case $WH_RMETHOD in
  107.                 [Aa])
  108.                     printf $(((($WH_RND%$WH_F*$WH_MAX)+$WH_F*10/18)/$WH_F))"$WH_DEL"
  109.                     ;;
  110.                 [Pp])
  111.                     WH_RND=$(($WH_RND%$WH_F*$WH_MAX))
  112.                     printf "%.0f$WH_DEL" "${WH_RND}e-$WH_PREC"
  113.                     ;;
  114.             esac
  115.         else
  116.             printf $WH_RND"$WH_DEL"
  117.         fi
  118.     done
  119. }
  120.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement