Sunday, June 8, 2008

Bash float comparison - bc


Lets have a script to compare some float values.


$ cat floatcomp.sh
#!/bin/sh

array=(0.255 0.8569 5.356 3.8521)
max=0
len=${#array[*]}
i=0

while [ $i -lt $len ]
do
echo "$i: ${array[$i]}"
val=`echo "${array[$i]}" `
if [ $val -gt $max ]
then
max=$val
fi
let i++
done
echo "MAX IS => $max"


Running the script:


0: 0.255
./floatcomp.sh: line 12: [: 0.255: integer expression expected
1: 0.8569
./floatcomp.sh: line 12: [: 0.8569: integer expression expected
2: 5.356
./floatcomp.sh: line 12: [: 5.356: integer expression expected
3: 3.8521
./floatcomp.sh: line 12: [: 3.8521: integer expression expected
MAX IS => 0


HUH!! Where is the problem ? Got it, problem is with the if statement above we are using to compare two float values, we just can't compare float values like the ints and strings.
To make it work, we have to use "bc" command. Some of its sample uses are below:


$ echo "3.2 > 3.2" | bc
0

$ echo "3.2 > 3.4" | bc
0

$ echo "3.2 < 3.4" | bc
1


Note: Notice the output of the above comparisons.

Based upon it, we will modify our script, the if condition will be like this


if [ $(echo "$max < $val"|bc) -eq 1 ]

instead of

if [ $val -gt $max ]


So the script will look like this:

$ cat floatcomp1.sh
#!/bin/sh

array=(0.255 0.8569 5.356 3.8521)
max=0
len=${#array[*]}
i=0

while [ $i -lt $len ]
do
echo "$i: ${array[$i]}"
val=`echo "${array[$i]}" `
if [ $(echo "$max < $val"|bc) -eq 1 ]
then
max=$val
fi
let i++
done
echo "MAX IS => $max"


The output:

$ ./floatcomp1.sh
0: 0.255
1: 0.8569
2: 5.356
3: 3.8521
MAX IS => 5.356

4 comments:

Zdenek said...

great! thank you.

Jadu Kumar Saikia said...

@Zdnek, :-)

Micael999 said...

I am not a shell expert, but I thought of an alternative solution:

Sort the two numbers and get the top or tail (depending which one you want ) then compare it against the previous one but just to see if they are different (as strings), if so, you have acomplished the concept of greater than or less than

Terry Romphf said...

I struggled with inconsistent results for months, searching, editing, searching again. Finally I utilized my meagre store of knowledge to rewrite my script to do away with the floating point math altogether at the cost of a dramatic increase in time. The script is for my personal use, so I could handle it.Then I stumbled accross this post. I had never seen anything quite like this (I've only been scripting a short time so there's a lot I've yet to see.)

I incorporated your ideas into a re-rewrite of my script and am checking them against the results of my earlier version, and so far I'm impressed but want to test it more thoroughly.

Kudos!

© Jadu Saikia www.UNIXCL.com