How to compare two floating-point values in shell script
I had to do a division in shell script and the best way was:
result1=`echo "scale=3; ($var1 / $total) * 100"| bc -l`
result2=`echo "scale=3; ($var2 / $total) * 100"| bc -l`
but I want to compare the values of $res开发者_StackOverflowult1
and $result2
Using if test $result1 -lt $result2
or if [ $result1 -gt $result2 ]
didn't work :(
Any idea how to do that?
You can compare floating-point numbers using expr(1)
:
: nr@yorkie 3724 ; expr 3.1 '<' 3.3
1
: nr@yorkie 3725 ; expr 3.1 '<' 3.09
0
You can also have bc
do the comparisons as well as the calculations:
if [ "$(echo $result1 '<' $result2 | bc -l)" -eq 1 ];then ... fi
Finally, ksh93 can do arithmetic evaluation $(($result1 < $result2))
with floating-point numbers, although bash cannot.
note that you've gotta be a bit careful when dealing with floating point numbers and if you are testing for equality you really want to decide on some precision and then compare using that. Something like:
if (abs(x1-x2) < 0.0001) then equal # pseudo-code
the reason being that with computers we're dealing with limited-precision binary fractions not true mathematical reals. Limiting the precision in bc with the scale=3 will have this effect.
I'd also advise against trying to do this stuff in shell script. It's not that you can't do it but you'll have to fork off lots of little sub commands to do the tricky bits and that's slow to execute and generally a pain to write - you spend most of your time trying to get the shell to do what you want rather than writing the code you really want. Drop into a more sophisticated scripting language instead; my language of choice is perl but there are others. like this...
echo $var1 $var2 $total | perl -ne 'my ($var1, $var2, $tot) = split /\s+/; if ($var1/$tot == $var2/$tot) { print "equal\n"; }'
also note that you're dividing by the same value ($total in your question) so the whole comparison can be done against the numerators (var1 and var2) provided $total is positive
Posting a new answer since I cannot yet comment...
@Norman Ramsey's answer is not quite accurate:
expr
will perform an integer or string comparison, not a floating-point comparison.
Here's what the man page says:expr1 {=, >, >=, <, <=, !=} expr2
Return the results of integer comparison if both arguments are integers; otherwise, returns the results of string comparison using the locale-specific collation sequence.
(just try
expr 8.9 '<' 10
and get0
where it should be1
).bc
works great, but isn't always installed.
So another alternative is using perl -e
:
perl -e 'print expression'
will print1
if expression is true and nothing (empty string) otherwise.e.g.
perl -e 'print 8.9 < 10'
- prints "1", whileperl -e 'print 2>4'
prints nothing.And when used in
if
statement:if [ $(perl -e "print $result1 < $result2") ];then ... fi
精彩评论