#!/bin/sh # #!/usr/local/bin/dash # #!/bin/dash # #!/bin/ksh # # Fully POSIX random number generator for input numbers 2 to 1000. # # Wichmann-Hill method using 32 bit integer arithmetic. # https://en.wikipedia.org/wiki/Wichmann%E2%80%93Hill # # This version is for the Classic AMIGA and ADE, the *NIX _emulator_ and 'KSH88' run as 'sh'. # WH_RANDOM.sh # Initialise variables as global. EPOCH=1234567890.987654 SEED1=1 SEED2=1 SEED3=1 RAND_VAL=0.0 WH_RANDOM=0 TEST_NUM=256 # Get epoch value to microseonds. if [ ! -f /tmp/epoch_microsecs ] then cat << 'EPOCH_MICROSECS' > /tmp/epoch_microsecs.c /* 'epoch_microsecs.c' */ #include #include #include int main(void) { struct timeval tv; gettimeofday(&tv, NULL); printf("%ld.%06ld", tv.tv_sec, tv.tv_usec); exit(0); } EPOCH_MICROSECS # Compile the above using gcc. echo '' echo 'Compiling "epoch_microsecs", please wait...' gcc -Wall -pedantic -ansi -o /tmp/epoch_microsecs /tmp/epoch_microsecs.c -lm echo 'Done!' echo '' fi # Use clock timer for seeds. time_seeds() { # Create the three required seeds using the clock. # Each must be between 1 and 300 inclusive. EPOCH=$( /tmp/epoch_microsecs ) SEED1=${EPOCH#??????????????} SEED1=$( expr ${SEED1} + 1 ) if [ ${SEED1} -gt 300 ] then SEED1=$(( SEED1 / 4 )) fi # EPOCH=$( /tmp/epoch_microsecs ) SEED2=${EPOCH#??????????????} SEED2=$( expr ${SEED2} + 1 ) if [ ${SEED2} -gt 300 ] then SEED2=$(( SEED2 / 4 )) fi # EPOCH=$( /tmp/epoch_microsecs ) SEED3=${EPOCH#??????????????} SEED3=$( expr ${SEED3} + 1 ) if [ ${SEED3} -gt 300 ] then SEED3=$(( SEED3 / 4 )) fi } # Use user defined values for seeds. fixed_seeds() { # All seeds must be an integer, 1 to 300! # Called as 'fixed_seeds ' SEED1=${1} SEED2=${2} SEED3=${3} check_seeds } # Use external user defined values for seeds. manual_seeds() { # All seeds must be an integer, 1 to 300! printf "Enter first integer seed, 1 to 300:- " read -r SEED1 printf "Enter second integer seed, 1 to 300:- " read -r SEED2 printf "Enter third integer seed, 1 to 300:- " read -r SEED3 check_seeds } # Check user seeds for basic errors. # Any other errors are taken care of by the shell itself. check_seeds() { if [ "${SEED1}" = "" ] || [ "${SEED2}" = "" ] || [ ${SEED3} = "" ] then echo "Usage1: fixed_seeds " echo "OR..." echo "Usage2: manual_seeds and then follow the on screen prompts!" echo "Aborting..." exit 1 fi if [ ${SEED1} -lt 1 ] || [ ${SEED2} -lt 1 ] || [ ${SEED3} -lt 1 ] then echo "ERROR! One or more of the seeds are wrong! Aborting..." exit 2 fi if [ ${SEED1} -gt 300 ] || [ ${SEED2} -gt 300 ] || [ ${SEED3} -gt 300 ] then echo "ERROR! One or more of the seeds are wrong! Aborting..." exit 3 fi } # This is the working part of this Wichmann-Hill random module... whrandom() { SEED1=$(( ( 171 * SEED1 ) % 30269 )) SEED2=$(( ( 172 * SEED2 ) % 30307 )) SEED3=$(( ( 170 * SEED3 ) % 30323 )) RAND_VAL=$(( ( ( ( SEED1 * 1000 ) / 30269 ) + ( ( SEED2 * 1000 ) / 30307 ) + ( ( SEED3 * 1000 ) / 30323 ) ) % 1000 )) # Global 'RAND_VAL' displays as 0.000 to 0.999 RAND_VAL=$( printf "%0.3f" "${RAND_VAL}e-3" ) } # Test loop only, press Ctrl-C to stop... test() { while true do # Call 'whrandom' function... whrandom # Remove front '0.' first and any leading zeros, (0), after. RAND_VAL=$( expr ${RAND_VAL#??} + 0 ) # Give a test number, 256 for this DEMO so as to have 0 to 255 values. TEST_NUM=256 # Multiply the two integer variables together and integer division by 1000. WH_RANDOM=$(( ( RAND_VAL * TEST_NUM ) / 1000 )) echo "${WH_RANDOM}" done } time_seeds test