Decimal Math in shell scripts
I was reading about inserting random delays in cron jobs and was surprised when I saw this code to get a random number:
# Grab a random value between 0-240.
value=$RANDOM
while [ $value -gt 240 ] ; do
value=$RANDOM
done
I thought, there’s got to be a better way to get a random number within a specific range. I mean, that kind of seems like a waste of CPU cycles, particularly when $RANDOM can be anywhere in between 0 and 32767. And a quick test verified that was exactly the case. On average (out of 500 samples), using that method to get a random number below 240 requires 134 attempts. Not a horrid performance impact, but enough to get my anal retentive brain in a twist.
My first thought was to use the expr command to do some simple math to properly adjust the $RANDOM variable into the desired range. But soon enough, I realized the expr only deals with integers…bummer. Looking around to see what else I could use for decimal math, I eventually came across the dc command - a reverse-polish desk calculator:echo -e "6\nk\n$RANDOM\n32767\n/\n1\nk\n240\n*\np" | dc | cut -f1 -d.
This definitely seems to be faster.
time echo -e “6\nk\n$RANDOM\n32767\n/\n1\nk\n240\n*\np” | dc | cut -f1 -d.
104real 0m0.003s
user 0m0.003s
sys 0m0.002sCOUNT=0; time while [ $RANDOM -gt 240 ]; do COUNT=`expr $COUNT + 1`; done; echo $COUNT
real 0m0.445s
user 0m0.158s
sys 0m0.297s
295
Update: After pondering the comment below, I realized this can be done in bash by using factors of 100 to resolve the integer math issue. There are several ways to do this, but here are a couple options:
RAND1=`expr $RANDOM \* 100`; FACTOR=`expr $RAND1 \/ 32767`; DIV=`expr $FACTOR \* 240`; RESULT=`expr $DIV \/ 100`;
or
expr $(expr $(expr $(expr 9264 \* 100) \/ 32767) \* 240) \/ 100
They appear to take about the same time, around 0.050s real time and 0.015s sys time.
2 Comments so far
Leave a comment
Just a quickie on why the variable was chosen, even if slightly longer compute. $RANDOM was chosen because it’s part of bash; when dealing cross-platform (Solaris, AIX, Linux), we found that bash was always a common package loaded.
By Alexon 10.21.05 7:13 am
Ah, very good point. I had never even heard of dc prior to playing with this and was surprised to find that bash could only do integer math. Thanks for the update!
By Damonon 10.21.05 12:28 pm
Leave a comment
Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>