Comparison of floating point numbers in bash

I have the following code snippet in bash

        if [[ $diff < $minm ]]; then
		minm=`echo "$diff" | bc`
	fi

It works well for most of the cases. However lets say diff is -0.17 and minm is -0.0017. In such a case the comparison seems to fail. Is the correct way to compare a mixture of positive and negative numbers in bash.
Appreciate your help.

bash doesn't handle floating point numbers, only integers. On top, ( man bash )

You might want to consider the -gt operator.

1 Like

Use bc

if (( $(echo "$num1 > $num2" |bc -l) )); then
  echo "ok"
fi

bc does floating point comparisons, in bash you have to surround it with (( )) to get a boolean (true/false) result.

3 Likes

You could also use awk:

if awk "BEGIN{exit !($diff < $minm)}"; then
1 Like

Hi Chubler_XL...
Modified to suit OSX 10.14.6, default bash terminal:

Last login: Tue Oct 22 22:05:17 on ttys000
AMIGA:amiga~> bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.
AMIGA:amiga~> num1=1.2345
AMIGA:amiga~> num2=0.09876
AMIGA:amiga~> if awk 'BEGIN{exit !('"$num1"' > '"$num2"')}'; then echo "OK."; fi
OK.
AMIGA:amiga~> _

As Python doesn't lend itself to one liners at all here is a Python version for Python Versions 2.7.x to 3.8.0.

if python -c 'if '"$num1"' > '"$num2"':exit(1)'; then :; else echo "OK."; fi

OSX 10.14.6, default bash terminal:

Last login: Tue Oct 22 23:15:20 on ttys000
AMIGA:amiga~> num1=1.2345
AMIGA:amiga~> num2=0.9876
AMIGA:amiga~> if python3.8 -c 'if '"$num1"' < '"$num2"':exit(1)'; then :; else echo "OK."; fi
AMIGA:amiga~> if python3.8 -c 'if '"$num1"' > '"$num2"':exit(1)'; then :; else echo "OK."; fi
OK.
AMIGA:amiga~> _

Thanks wisecracker, I'm curious does OSX 10.14.6, default bash terminal have an issue with

awk "BEGIN{exit !($num1 > $num2)}"; then echo "OK."; fi

The only thing I can think could be causing it trouble is the bracketed expressions within double quotes.

Hi Chubler_XL...

This is the result, (including the missing 'if'):

Last login: Wed Oct 23 09:21:10 on ttys000
AMIGA:amiga~> num1=1.2345
AMIGA:amiga~> num2=0.9876
AMIGA:amiga~> if awk "BEGIN{exit !($num1 > $num2)}"; then echo "OK."; fi
-bash: !: event not found
AMIGA:amiga~> _

I am getting good at _fudging_ with single and double quotes.
But unless I use my Linux box I only have bash version 3.2.x, but almost everyone has POSIX compliance. <wink>

-------------------------
OT, in fact I used a method of exiting AudioScope.sh that was perfect until bash 4.4.x when someone must have noticed it was a serious bug and I thought it was a feature, post #7:
AudioScope Project.

EDIT:
My modified version also works in 'dash'.

Perl is even shorter than awk.
It can even be hidden in a function:

fff(){
perl -e "exit ! ($*)"
}

num1=1.2345
num2=0.9876
if fff "$num1 > $num2"; then echo "OK"; fi

Or

if fff "$num1" ">" "$num2"; then echo "OK"; fi
1 Like

Then, why not

bc <<< "$num1 > $num2"
1

?

1 Like

Perhaps because the OP might mistake '1' as being a result or a '$?' as opposed to a 'true'.
(Also it does not work in POSIX but that is my reason not the OP's.)

1 Like

Oh, OK. ! is a command line history expansion thing. This is really quite sad as even this simple command will fail with a weird error about events:

echo "Hello, World!"

This expanson should only impact command line code, scripts using ! should work fine in 3.2.x. I also believe that if a whitespace character follows bash will not try to expand from the history. I don't have access to 3.2.x bash to test, but believe this should work OK from the command line:

if awk "BEGIN{exit ! ($num1 > $num2)}"; then echo "OK."; fi

Works as expected now! <thumbs_up>

Last login: Wed Oct 23 21:29:52 on ttys000
AMIGA:amiga~> num1=1.2345
AMIGA:amiga~> num2=0.9876
AMIGA:amiga~> if awk "BEGIN{exit ! ($num1 > $num2)}"; then echo "OK."; fi
OK.
AMIGA:amiga~> if awk "BEGIN{exit ! ($num1 < $num2)}"; then echo "OK."; fi
AMIGA:amiga~> _
Moderator comments were removed during original forum migration.