Storing or Using Numeric Output From a Function


 
Thread Tools Search this Thread
Top Forums Shell Programming and Scripting Storing or Using Numeric Output From a Function
# 1  
Old 07-19-2011
Storing or Using Numeric Output From a Function

Hi all,

I'm trying to implement a linear congruential pseudorandom number generator (<http://en.wikipedia.org/wiki/Linear_congruential_generator>), since $RANDOM and /dev/random aren't standardized. I'm referring to the Shell & Utilities volume of POSIX.1-2008, but I'm running into some odd issues. This works fine:
Code:
#! /bin/sh

rand_x=1

rand()
{
    rand_x=$(((($rand_x * 1103515245) + 12345) % 4294967296))
    echo $rand_x
}

while true; do
    rand
    sleep 2
done

But I want to use the generated integer in an arithmetic expansion, for modular arithmetic (I know it's a sloppy way of limiting the range of values, but it's good enough for my purpose).

I've tried the following, but it simply repeats "1103527590 0" over and over:
Code:
#! /bin/sh

rand_x=1

rand()
{
    rand_x=$(((($rand_x * 1103515245) + 12345) % 4294967296))
    echo $rand_x
}

while true; do
    r=`rand`
    printf '%i %i\n' $r $(($r % 3))
    sleep 2
done

Similarly, this repeats "1103527590":
Code:
#! /bin/sh

rand_x=1

rand()
{
    rand_x=$(((($rand_x * 1103515245) + 12345) % 4294967296))
    echo $rand_x
}

while true; do
    printf '%i\n' `rand`
    sleep 2
done

It looks like, if I try to store or use the output of rand(), either $rand_x is being reset to 1 each time or the arithmetic substitution in rand() isn't being used.

But if I access $rand_x directly, as in the following script, I get the correct sequence:
Code:
#! /bin/sh

rand_x=1

rand()
{
    rand_x=$(((($rand_x * 1103515245) + 12345) % 4294967296))
}

while true; do
    rand
    printf '%i %i\n' $rand_x $(($rand_x % 3))
    sleep 2
done

However I'd like to avoid exposing $rand_x like that (rand() will eventually become a library function). So does anyone have any idea why using echo and capturing/using the output of rand() isn't working?

I'm testing this in GNU Bash and dash on GNU/Linux. When I get this working, I'll test it in more shells.

---------- Post updated at 23:58 ---------- Previous update was at 23:26 ----------

Quote:
Originally Posted by PehJota
It looks like, if I try to store or use the output of rand(), either $rand_x is being reset to 1 each time or the arithmetic substitution in rand() isn't being used.
The former seems to be the case. If I echo $rand_x from rand() and just store the output of rand(), $rand_x is reset to 1 for some reason.

The following script illustrates this:
Code:
#! /bin/sh

rand_x=1

rand()
{
    rand_x=$(((($rand_x * 1103515245) + 12345) % 4294967296))
    echo $rand_x >&2
    echo $rand_x
}

while true; do
    r=`rand`
    printf '%i %i\n' $rand_x $(($rand_x % 3))
    sleep 2
done

Note that in rand(), $rand_x is now also printed to standard error (file descriptor 2) so it appears on the terminal even though standard output is stored in $r.

Output (file descriptors 1 and 2):
Quote:
1103527590
1 1
1103527590
1 1
1103527590
1 1
...
Anyone have any idea why this is happening?
# 2  
Old 07-19-2011
try with below

Code:
rand_x=1
rand()
{
    rand_x=$(((($rand_x * 1103515245) + 12345) % 4294967296))
    echo $rand_x >&2
    return $rand_x
}
while true; do
    rand
    printf '%i %i\n' $rand_x $(($rand_x % 3))
    sleep 2
done


output

Code:
1103527590
1103527590 0
2524885223
printf: 2524885223: Result too large
2147483647 2
662824084
662824084 1
3295386429
printf: 3295386429: Result too large
2147483647 0

Since it is an infinite loop the output will keep on printing on the prompt

Cheers
Harish
# 3  
Old 07-19-2011
It's because you are running the function in a sub-shell. The value of the $rand_x in your current shell is not altered.

Without sub-shell it works fine...
Code:
$ function rand() { rand_x=$(((($rand_x * 1103515245) + 12345) % 4294967296)); echo $rand_x; }

$ for i in 1 2 3; do rand; done
1448521415
3776134388
3397090333

...but using a sub-shell...
Code:
$ for i in 1 2 3; do (rand); done
835903122
835903122
835903122

This User Gave Thanks to Ygor For This Post:
# 4  
Old 07-19-2011
This is in response to a private message I received (since I can't send PMs until I have 10 posts...).

I've implemented this linear congruential generator in C to generate the correct sequence of integers (that is, what I'm expecting from this shell function):
Code:
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>

uint32_t
myrand()
{
    static uint32_t rand_x = 1;

    rand_x = (rand_x * 1103515245 + 12345) % 4294967296;

    return rand_x;
}

int
main(int argc, char **argv)
{
    for (;;) {
        printf("%u\n", myrand());
        sleep(2);
    }   

    return 0;
}

And here is the printed sequence:
Quote:
1103527590
2524885223
662824084
3295386429
4182499122
2516284547
3655513600
2633739833
...
If I use "return" instead of "echo" and get the value in $? after calling rand(), my shell terminates with the following:
Quote:
1103527590 0
return: 15: Illegal number: 2524885223
So it's generating the correct number. I guess the problem is that this number is 32 bits long and would exceed a signed long integer on my i686 system. Oops. Smilie

I changed my modulus, multiplier, and increment so the returned value doesn't exceed 2^31. So now this works:
Code:
#! /bin/sh

rand_x=1

rand()
{
    rand_x=$(((($rand_x * 65537) + 12345) % 2147483648))
    return $rand_x
}

while true; do
    rand
    printf '%i %i\n' $? $(($? % 3))
    sleep 2
done

For some reason "echo" still just resets $rand_x to its original value... I wish I knew why it did that. But I'll just use "return".

I'll test this script in a few different shells now to see if the signed long issue affects numbers before they're wrapped with modulo. If not, I think this problem is solved. Smilie

EDIT:
Harish: I know it's an infinite loop. I just interrupt it after a few iterations.
Ygor: Oh, I didn't realize command substitution used a subshell (I see it now in POSIX.1-2008) or that variables are set differently in a subshell. Yeah, that explains the weird behavior with "echo" then. Thanks!

EDIT 2:
I used these new values in three different shells so far (GNU Bash, dash, and BusyBox ash) and in C (modifying the above code). I generated 1000 pseudorandom numbers using all four test cases, and all four results were equal. I think the results are undefined if there is overflow in the intermediate arithmetic though. Oh well; I'll test more shells to be sure.

EDIT 3:
Well I've tested 8 shells (GNU Bash, dash, BusyBox ash, zsh, csh, tcsh, ksh, and mksh) across two PC architectures, haha. All give the same 1000 numbers (seeded at 1), so the arithmetic seems portable. Anyway, thanks again Ygor and Harish!

Last edited by PehJota; 07-19-2011 at 03:55 AM..
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

Storing command output in an array

Hi, I want keep/save one command's output in an array and later want to iterate over the array one by one for some processing. instead of doing like below- for str in `cat /etc/passwd | awk -F: '$3 >100 {print $1}' | uniq` want to store- my_array = `cat /etc/passwd | awk -F: '$3 >100 {print... (4 Replies)
Discussion started by: sanzee007
4 Replies

2. Shell Programming and Scripting

sed not storing output in shell script

Hello, Following my learning of shell scripting.. I got stuck yet again. If I execute this command on terminal: $ sed "s/off/on/g" file > fileAUX I successfully change the text off to on from file to fileAUX. But the same command is not working inside a shell script. I tested and... (2 Replies)
Discussion started by: quinestor
2 Replies

3. Shell Programming and Scripting

Storing output into a variable

My script below seems to be choking because I need the the output of the find command to be stored as a variable that can then be called by used lower in the script. #!/bin/bash cd "/resumes_to_be_completed" var1=find . -mmin -1 -type f \( -name "*.doc" -o -name "*.docx" \)... (1 Reply)
Discussion started by: binary-ninja
1 Replies

4. Programming

Storing the output of a Unix cmd in my C program

Hello experts, How can I retrieve the output from a Unix command and use it as string variable in my C program? For example, when I issue the command 'date' I get: Tue Jun 11 09:54:16 EEST 2009 I do not want to redirect the output of the command to a file and then open the file from... (3 Replies)
Discussion started by: Goseib
3 Replies

5. UNIX for Dummies Questions & Answers

Storing lines of output into a script variable

I'm sure this is a simple thing but I can't figure it out. In a script that I'm writing, I'd like to be able to store each line of output from "ls -l" into a variable. Ultimately I'd like to end up with something like: for a in `ls -l` do something with $a doneBut that's reading each... (2 Replies)
Discussion started by: ewoods
2 Replies

6. Shell Programming and Scripting

Storing awk output into variables

Hi all, Currently, i have a log file seperated by 'tab' and each record starting with a new line. i managed to retrieve the column that i'm interested in. (source_ip_address: xxx.xxx.xxx.xxx). example of awk output: '{ print $43 }' assuming the field is at column 43. 10.10.10.10... (4 Replies)
Discussion started by: faelric
4 Replies

7. UNIX for Dummies Questions & Answers

Storing a Function

Hi, I am running Sco Unix v3.2B. I want to know how can I store a function I create so I can use it later simply by just calling it from the command prompt. Sorry if I am asking such a noob question. Thanks. (7 Replies)
Discussion started by: sdilucca
7 Replies

8. Shell Programming and Scripting

Using 'defaults read' and storing the output in a variable

Hi all, I'm creating a script which uses 'defaults read' to retrieve details from an Info.plist like this; defaults read "/Path/Contents/Info" CFBundleShortVersionString This works fine in Terminal and returns the expected values. Is it possible to use this command in a script, and... (0 Replies)
Discussion started by: davewg
0 Replies

9. UNIX for Dummies Questions & Answers

Storing the output into a variable

Hi unix gurus, I am trying to store the result of a command into a variable. But it is not getting stored. x='hello' y=echo $x | wc -c but it is giving the output as 0(zero) Pls help me its very urgent (7 Replies)
Discussion started by: ravi raj kumar
7 Replies

10. Shell Programming and Scripting

storing output of awk in variable

HI I am trying to store the output of this awk command awk -F, {(if NR==2) print $1} test.sr in a variable when I am trying v= awk -F, {(if NR==2) print $1} test.sr $v = awk -F, {(if NR==2) print $1} test.sr but its not working out . Any suggestions Thanks Arif (3 Replies)
Discussion started by: mab_arif16
3 Replies
Login or Register to Ask a Question