Generate a random number in a fully POSIX compliant shell, 'dash'...
Hi all...
Apologies for any typos, etc...
This took a while but it didn't beat me...
Although there are many methods of generating random numbers in a POSIX shell this uses integer maths and a simple C source to create an executable to get epoch to microseconds accuracy if it is needed. I take no credit for the C source, the credit is inside the script.
It is an exercise in futility but I love finding the limits of a language.
This is only tested in OSX 10.14.6 and not Linux at the moment for the C source only as I have no idea if gcc will compile.
Code:
#!/usr/local/bin/dash
# #!/bin/sh
#
# Fully POSIX random number generator.
# Wichmann-Hill method.
# https://en.wikipedia.org/wiki/Wichmann%E2%80%93Hill
# Initialise variables as global.
EPOCH=1234567890.987654
SEED1=1
SEED2=1
SEED3=1
VALUE=0
TEST_VAL=1
TEST_NUM=256
# Get epoch value to microseonds.
epoch()
{
cat << 'EPOCH_MICROSECS' > /tmp/epoch_microsecs.c
/* 'epoch_microsecs.c' */
/* Thanks to Perderabo for this little snippet modified to suit my needs. */
/* It saved me the bother of working it out by myself. */
/* https://www.unix.com/programming/1991-time-microseconds-2.html */
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
int main(void)
{
struct timeval tv;
struct timezone tz;
struct tm *tm;
gettimeofday(&tv, &tz);
tm=localtime(&tv.tv_sec);
printf("%ld.%06d", tv.tv_sec, tv.tv_usec);
exit(0);
}
EPOCH_MICROSECS
# Compile the above using gcc.
gcc -Wall -pedantic -ansi -o /tmp/epoch_microsecs /tmp/epoch_microsecs.c -lm
}
# Use clock timer for seeds.
time_seeds()
{
# Create the three required seeds using the clock.
# Each must be between 1 and 30000 inclusive.
EPOCH=$( /tmp/epoch_microsecs )
SEED1=${EPOCH#????????????}
SEED1=$( expr ${SEED1} + 1 )
if [ ${SEED1} -gt 30000 ]
then
SEED1=$(( SEED1 / 4 ))
fi
#
EPOCH=$( /tmp/epoch_microsecs )
SEED2=${EPOCH#????????????}
SEED2=$( expr ${SEED2} + 1 )
if [ ${SEED2} -gt 30000 ]
then
SEED2=$(( SEED2 / 4 ))
fi
#
EPOCH=$( /tmp/epoch_microsecs )
SEED3=${EPOCH#????????????}
SEED3=$( expr ${SEED3} + 1 )
if [ ${SEED3} -gt 30000 ]
then
SEED3=$(( SEED3 / 4 ))
fi
}
# Use user defined values for seeds.
fixed_seeds()
{
# All seeds must be an integer, 1 to 30000!
# Called as 'fixed_seeds <SEED1> <SEED2> <SEED3><CR>'
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 30000!
printf "Enter first integer seed, 1 to 30000:- "
read -r SEED1
printf "Enter second integer seed, 1 to 30000:- "
read -r SEED2
printf "Enter third integer seed, 1 to 30000:- "
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 <SEED1> <SEED2> <SEED3>"
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 30000 ] || [ ${SEED2} -gt 30000 ] || [ ${SEED3} -gt 30000 ]
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 ))
VALUE=$(( ( ( SEED1 * 1000000000 ) / 30269 ) + ( ( SEED2 * 1000000000 ) / 30307 ) + ( ( SEED3 * 1000000000 ) / 30323 ) ))
VALUE=$(( VALUE % 1000000000 ))
printf "%.9f" "${VALUE}e-9"
}
# Test loop only, press Ctrl-C to stop...
test()
{
while true
do
# Save fixed point value to disk...
# For some reason this does not work, 'TEST_VAL=$( whramdom )'. ;'(
whrandom > /tmp/VAL
# Immediately read it back.
read -r TEST_VAL < /tmp/VAL
# Remove any leading zeros, (0).
TEST_VAL=$( expr ${TEST_VAL#??} + 0 )
# Give a test number, 256 for this DEMO so as to have 0 to 255 values.
TEST_NUM=256
# Multiply the two variables together......
TEST_VAL=$(( TEST_VAL * TEST_NUM ))
# ......AND correct for the fixed point position removing anything beyond a decimal point.
printf "%.0f\n" "${TEST_VAL}e-9"
done
}
epoch
time_seeds
test
Results OSX 10.14.6, using dash called from default shell...
Code:
Last login: Sat Jan 18 21:21:52 on ttys000
AMIGA:amiga~> cd Desktop/Code/Shell
AMIGA:amiga~/Desktop/Code/Shell> ./WH_random_POSIX.sh
98
49
123
233
4
90
73
145
56
198
166
10
205
110
153
.
.
.
.
155
235
141
245
242
45
50
^C
AMIGA:amiga~/Desktop/Code/Shell> _
Looking forwards to input from the big guns to improve upon it...
Last edited by wisecracker; 01-20-2020 at 10:50 AM..
Reason: Copy and paste error, although it makes no difference.
These 4 Users Gave Thanks to wisecracker For This Post:
How to generate a random integer with specific range(for example, from 1 to 1000)?
Also, how to convert a floating point number into a integer? (2 Replies)
I want to be able to generate a random number within a korn shell script..
Preferably i would like to be able to state how many digits should be in this random number... ie 4 digits or 5 digits etc
Any ideas? (2 Replies)
I saw this formula to generate random number between two specified values in shell script.the following.
$(((RANDOM%(max-min+divisibleBy))/divisibleBy*divisibleBy+min))
Give a example in book.
Generate random number between 6 and 30.like this.
$(((RANDOM%30/3+1)*3))
But I have a... (1 Reply)
Hi All,
I have extracted some report from database for few activities done.
Now I have a requirement to add some random time(In range of 10-35) in front of each activity.
Can be generated random numbers in any bash/sh shell within a given number range, let's say in between 10-30.
... (10 Replies)
Hi,
i want to check if a variable var1 is not a or b or c
pseudo code:
If NOT (var1 = a or var1 = b or var1 = c)
then
...
fi
I want to use POSIX complaint Korn shell, and for string comparison
For the following code, logical.sh
#!/usr/bin/ksh
var="j"
echo "Var : $var"
if ! { || ||... (12 Replies)
Dear all,
I have a question. I have a txt file say 4000 rows X 1800 Column. I 'd like to creat a new column as the first column which is a column of random numbers (n=4000)
thanks a lot!
Lin (2 Replies)
Hi,
Is anybody experience generate a pair of random number by using awk command?
I wanna to generate a pair of random number (range from 1 to 4124) and repeats it 416 times.
Desired output
2 326
123 1256
341 14
3245 645
.
.
.
I did write the below command:
awk... (5 Replies)
Hi Guys and gals...
As you know I am getting to grips with POSIX and hit this stumbling block.
Generating two random numbers 0 to 255 POSIXly. Speed in not important hence the 'sleep 1' command.
I have done a demo that works, but it sure is ugly! Is there a better way?
#!/bin/sh
# Random... (12 Replies)
Hi all...
This is just a fun project to see if it is possible to get a square root of a positive integer from 1 to 9200000 to 6 decimal places on a 64 bit architecture machine.
It is coded around dash and the results show the values from 0 to 10000.
Complex numbers can easily be catered for by... (3 Replies)