Sponsored Content
Operating Systems OS X (Apple) Generate a random number in a fully POSIX compliant shell, 'dash'... Post 303043116 by wisecracker on Saturday 18th of January 2020 04:53:17 PM
Old 01-18-2020
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:
 

10 More Discussions You Might Find Interesting

1. Programming

How to generate a random number?

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)
Discussion started by: MacMonster
2 Replies

2. Shell Programming and Scripting

generate random number in korn shell

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)
Discussion started by: frustrated1
2 Replies

3. Shell Programming and Scripting

generate random number in perl

Could any one tell how can I generate random number from (0, 100..200) in perl? Thanks! (2 Replies)
Discussion started by: zx1106
2 Replies

4. Programming

Generate random number

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)
Discussion started by: luoluo
1 Replies

5. Shell Programming and Scripting

Unix random number generate in given range

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)
Discussion started by: gr8_usk
10 Replies

6. Shell Programming and Scripting

Logical expression in POSIX compliant Korn Shell

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)
Discussion started by: ysrini
12 Replies

7. UNIX for Dummies Questions & Answers

how to generate random number as as the first column of a txt file

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)
Discussion started by: forevertl
2 Replies

8. Shell Programming and Scripting

Help with generate a pair of random number

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)
Discussion started by: perl_beginner
5 Replies

9. Shell Programming and Scripting

Generating a POSIX random number?

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)
Discussion started by: wisecracker
12 Replies

10. Shell Programming and Scripting

Q: Is SQRT(n) possible in a POSIX compliant shell? A: Yes within limits.

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)
Discussion started by: wisecracker
3 Replies
All times are GMT -4. The time now is 06:03 PM.
Unix & Linux Forums Content Copyright 1993-2022. All Rights Reserved.
Privacy Policy