Click to See Complete Forum and Search --> : bash scripting, how do i make it handle decimals?


Zeddicus
04-26-2001, 12:16 PM
Hey guys, newbie question here :-)
I'm reading up on bash scripting and have been writing little scripts to do various things, but I'm somewhat stuck trying to get it to handle numbers with decimals, ie 1.1...
While searching the net I came across a command; | bc -l
but this doesnt make my bash script do decimals..

Here's my unfinished script:

#!/bin/bash

amps=11 #number of wave amps
roids=6 #number of asteroids

x=$(($roids*2))
y=$(($amps / $x))
z=$((1+$y))
echo "$x $y $z"

That's it. Very simple but hey, gotta start somewhere :-)

Anyway, how do i make this script calculate using decimals and not just whole numbers?

Thanks for the help,

Zeddicus

jemfinch
04-26-2001, 02:05 PM
Honestly, you should be using a Real Programming Language (like, ahem, Python.) If you insist on using shell scripting, then you'll need to use "bc" to do decimal math.

Jeremy

TheLinuxDuck
04-26-2001, 06:18 PM
Zeddicus:

In case you haven't done anything with it yet, here is a simple bash script for doing decimal math, using bc

#!/bin/bash

amps=11.9 #number of wave amps
roids=6.9 #number of asteroids

echo "amps=$amps roids=$roids"
x=`echo "2*$roids" | bc`;
y=`echo "$amps/$x" | bc`;
z=`echo "1+$y" | bc`;

echo "x=$x y=$y z=$z"

exit 0

Spacecake
04-26-2001, 11:23 PM
Wouldn't it be easier just to use fixed point? :)

Zeddicus
04-27-2001, 06:57 AM
Linuxduck, thanks for the advice. However, when i run this script it only gives X in decimals, y and z turn out in integers. For the set numbers, Y should be something like 0.88, however it turns out to be 0.
Any idea how i can get the entire script to use decimals?

Jemfinch, im just interested in learning a bit of bash scripting, im not considering
this to be a first class programming language.

Spacecake.. explain further please! :)

Zeddicus

Spacecake
04-27-2001, 09:52 AM
I too am a *total* bash newbie, and have no experience of _bc_, so this might not be the easiest way - just the way that comes naturally to me.

Fixed point is what people use in proper programming languages when you want to use decimals with an integer only variable (usually for speed).
Basically you multiply the decimal by a constant so that it is a whole number. Then you can do the math on this number as normal, having greater accuracy than you would be able to with just the plain integer. When you want the result to output, you just divide by the constant again.
This means you don't lose any accuracy (well, much. depends on the constant obviously) in the math, but has the disadvantage of a conversion every time you want to output it (but in my opinion is neater than sticking echo's and bc's in there all the time... :p)

simple eg, in normal math with bash:
a=$[ 3 / 2 ]
b=$[ $a * 2 ]
echo $b

That would output 2, which is obviously the wrong number.

Using fixed point:
a=$[ 3 / 2 << 16 ] # shl 16, same as mul 65536
b=$[ $a * 2 ]
# can insert loads more math here without losing accuracy
echo $[ $b >> 16 ] # shr 16, same as div 65536

That would output 3. Of course this could be used with lots more decimal places. And say you need even more places, just shift a bigger number instead of 16.

(i make it sound so complicated, it really isnt :))

I guess there are times when you need not just calulation accuracy but to have exact output and input too...

To do a=10.15, you could just do:
a=$[ (10 << 16) + ((15 << 16) / 100) ]

Most of the time you would round off a variable before using it in the final operation anyway, so the following isn't really needed, but just incase:
int=$[ $a >> 16 ]
echo "${int}.$[ ($a - ($int << 16))*100 >> 16 ]


You could always make functions to handle the input and output to the variables though.

TheLinuxDuck
04-27-2001, 10:12 AM
Originally posted by Zeddicus:
<STRONG>Linuxduck, thanks for the advice. However, when i run this script it only gives X in decimals, y and z turn out in integers. For the set numbers, Y should be something like 0.88, however it turns out to be 0.
Any idea how i can get the entire script to use decimals?</STRONG>

According to the <STRONG>bc</STRONG> manpage, the number of digits after the decimal is refered to as <STRONG>scale</STRONG>. And, the scale defaults to 0... so, if you add a scale=3; into the echo statement, you'll get decimal precision up to 3 decimal places.

Such as:

#!/bin/bash

amps=11.9 #number of wave amps
roids=6.9 #number of asteroids

echo "amps=$amps roids=$roids"
x=`echo "scale=3; 2*$roids" | bc`;
y=`echo "scale=3; $amps/$x" | bc`;
z=`echo "scale=3; 1+$y" | bc`;

echo "x=$x y=$y z=$z"

exit 0

TheLinuxDuck
04-27-2001, 10:13 AM
Here is the output from that program on my system:

brad@www2:~$ ./fp.sh
amps=11.9 roids=6.9
x=13.8 y=.862 z=1.862