236

I am trying hard to compare two floating point numbers within a Bash script. I have two variables, e.g.

let num1=3.17648e-22
let num2=1.5

Now, I just want do a simple comparison of these two numbers:

st=`echo "$num1 < $num2" | bc`
if [ $st -eq 1]; then
  echo -e "$num1 < $num2"
else
  echo -e "$num1 >= $num2"
fi

Unfortunately, I have some problems with the right treatment of the num1 which can be of the "e-format".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jonas
  • 2,974
  • 4
  • 24
  • 23
  • 2
    With "e-format" I mean the exponential notation (also called scientific notation) – Jonas Dec 28 '11 at 09:32
  • Related: [Floating-point arithmetic in UNIX shell script](http://stackoverflow.com/q/14222250/2157640) – Palec Feb 10 '15 at 23:39

22 Answers22

311

More conveniently

This can be done more conveniently using Bash's numeric context:

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

Explanation

Piping through the basic calculator command bc returns either 1 or 0.

The option -l is equivalent to --mathlib; it loads the standard math library.

Enclosing the whole expression between double parenthesis (( )) will translate these values to respectively true or false.

Please, ensure that the bc basic calculator package is installed.

Caveat: Exponential notation should be written as *10^; not E, nor e.

For example:

$ echo "1*10^3==1000" |bc
1

Whereas

$ echo "1E3==1000" |bc
0

Strategies to overcome this bc limitation are discussed here.

tdy
  • 36,675
  • 19
  • 86
  • 83
Serge Stroobandt
  • 28,495
  • 9
  • 107
  • 102
  • 1
    Same issue as https://stackoverflow.com/questions/8654051/how-to-compare-two-floating-point-numbers-in-a-bash-script#comment10752980_8654191 e.g. $ echo "1.1+2e+02" | bc (standard_in) 1: syntax error – Nemo Feb 02 '16 at 10:55
  • 1
    @MohitArora Please, ensure that you have the `bc` calculator package installed. – Serge Stroobandt Mar 28 '17 at 18:52
  • 1
    I get a `0: not found` with the statement `if (( $(echo "$TOP_PROCESS_PERCENTAGE > $THRESHOLD" | bc -l) )); then`. – Stephane Aug 04 '17 at 13:14
  • 1
    To all those who get "command not found", remember you need to enclose the `bc` into either backticks or `$()` and then into `(( ))` ... i.e. `(( $(bc -l<<<"$a>$b") ))` and not `(( bc -l<<<"$a>$b" ))`. – Normadize Apr 13 '18 at 01:13
  • @Nemo Write numbers in scientific notation with a capital letter `E`, and all syntax errors will be gone. – Serge Stroobandt May 19 '19 at 07:35
  • @SergeStroobandt Good to know. I don't remember what I was doing 3 years ago but the numbers probably came from some other source parsed with lowly grep hence the inconsistency. – Nemo May 25 '19 at 06:06
  • FWIW, this answer is not POSIX complaint. See [this link](https://unix.stackexchange.com/questions/558544/bc-does-posix-prohibit-standalone-use-of-relational-operators/) for more information. – Harold Fischer Dec 23 '19 at 02:53
  • if (( $(echo "$num1 > $num2" |bc -l) )); // not ok, if [[ $(echo "$num1 > $num2" |bc -l) == 1 ]]; // ok – sailfish009 Mar 20 '20 at 04:32
  • 2
    `3.44E6` is the same as `3.4546` according to `bc -l`. If you want `3.44*10^6` than use the string `3.44*10^6`, or `3440000`. – Kusalananda Mar 16 '21 at 11:34
  • Thanks for the answer! Just to point it out, this also works with equality check `if (( $(echo "$num1 >= $num2" |bc -l) )); then ...` – nish-ant May 30 '23 at 20:36
115

Bash handles only integer maths, but you can use the bc command as follows:

$ num1=3.17648E-22
$ num2=1.5
$ echo $num1'>'$num2 | bc -l
0
$ echo $num2'>'$num1 | bc -l
1

Note that the exponent sign must be uppercase.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
alrusdi
  • 1,273
  • 1
  • 7
  • 9
  • 3
    yes, but to workaround incorrect calculations its needed to uppercase 'e' sign in scientific number notation and use -l flag to bc programm for predefined math routines – alrusdi Dec 28 '11 at 10:24
  • 2
    you should point that out in your answer then, instead of just posting a very similar solution and not mention the important differances. – Daniel Persson Dec 28 '11 at 10:34
  • 4
    It is not a *very similar* solution. Alrusdi's solution uses the `bc` tool and that is what I would recommend to any BASH programmer. BASH is typeless language. Yeah, it can do integer arithmetic, but for floating point you must use some external tool. BC is the best because that is what it is made for. – DejanLekic Dec 28 '11 at 14:42
  • 12
    Since he is trying to use it in an if statement, I would show that. if [ $(... | bc -l) == 1 ] ; then ... – Robert Jacobs Mar 03 '15 at 22:12
  • This simple solution does not work. You need to change the exponential representations as described in Serge Stroobandt's answer. In practice,`bc` does not understand the scientific E notation. Even worse, `bc` (or at least my `bc` version) does not prints an error when the E notation is used. – Robin Hsu Mar 16 '23 at 08:25
31

It's better to use AWK for noninteger mathematics. You can use this Bash utility function:

numCompare() {
   awk -v n1="$1" -v n2="$2" 'BEGIN {printf "%s " (n1<n2?"<":">=") " %s\n", n1, n2}'
}

And call it as:

numCompare 5.65 3.14e-22
5.65 >= 3.14e-22

numCompare 5.65e-23 3.14e-22
5.65e-23 < 3.14e-22

numCompare 3.145678 3.145679
3.145678 < 3.145679
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 2
    i like this answer, people tend to shy away from awk esp beginners, they seem to think it is harder than it actually is, i think people get intimidated by the curly braces and the seemingly language mixed syntax (at a glance). And since awk is pretty much guaranteed to be present on the target system as well, just like bc (not sure which one, if any, is ever NOT installed). I love bash scripting but that no floating point, not even a meager 2 decimal places (i guess someone could write a 'fake' wrapper for that), really is annoying... – osirisgothra Nov 06 '13 at 11:03
  • Agreed, awk provides pretty much everything that pure shells could not do. – anubhava Nov 06 '13 at 11:30
  • 2
    Using `awk` and `bc` in shell scripts is a standard practice since ancient time, I would say some features have never been added to shells because they are available in awk, bc and other Unix tools. No need for purity in shell scripts. – piokuc Sep 15 '14 at 10:06
  • How to modify this code to set a variable value as a result of condition (say 0 or 1), which can be used for further processing? – rambalachandran May 21 '16 at 20:21
  • 1
    @WanderingMind One way to do that would be to pass the 0 or 1 to `exit` so that Awk communicates the result back to the shell in a proper, machine-readable way. `if awk -v n1="123.456" -v n2="3.14159e17" 'BEGIN { exit (n1 <= n2) }' /dev/null; then echo bigger; else echo not; fi` ... though note how the condition is inverted (the exit status 0 means success to the shell). – tripleee Aug 12 '16 at 05:13
  • 1
    People considering this answer, do yourself a favor and don't bother with `awk`. If you get to the point that you think awk is the answer, just do it with inline python instead. Your coworkers and future self will thank you. – CivFan Jul 19 '17 at 14:56
  • 2
    Why just `python`. You have `perl` installed by default on many Linux/Unix systems.. even `php` also – anubhava Jul 19 '17 at 15:44
  • 1
    Your coworkers and future self will only give you partial credit if you use `perl` or `php`. – CivFan Jul 19 '17 at 16:02
  • 1
    Trust me, they will curse me if they see me invoking a full fledge programming language from a shell script for this trivial task. – anubhava Jul 19 '17 at 16:08
  • `if python -c "import sys; result = 0 if float($num1) < float($num2) else 1; sys.exit(result)"; then echo yes num1 is less than num2; else echo nope, num2 is greater than num1; fi` – CivFan Jul 19 '17 at 16:23
  • 1
    That's just it, if you're already at a place where you're using `awk`, it's no longer a trivial task. :) – CivFan Jul 19 '17 at 16:24
  • No one is using `awk` just for the heck of it... if it is a `bash` script then it comes naturally as-and-when-needed. Don't forget it is a `bash` script. – anubhava Jul 19 '17 at 16:26
  • Just giving `awk` a hard time. It's fine. – CivFan Jul 19 '17 at 16:27
  • 1
    This `awk` solution is more robust in my case than the one with `bc` that returns wrong results for a reason I didn't get. – MBR Oct 16 '18 at 09:51
29

A pure Bash solution for comparing floats without exponential notation, leading or trailing zeros:

if [ ${FOO%.*} -eq ${BAR%.*} ] && [ ${FOO#*.} \> ${BAR#*.} ] || [ ${FOO%.*} -gt ${BAR%.*} ]; then
  echo "${FOO} > ${BAR}";
else
  echo "${FOO} <= ${BAR}";
fi

The order of logical operators matters. Integer parts are compared as numbers and fractional parts are intentionally compared as strings. Variables are split into integer and fractional parts using this method.

It won't compare floats with integers (without dot).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user
  • 23,260
  • 9
  • 113
  • 101
29

You can use AWK combined with a Bash if condition:

if awk "BEGIN {exit !($d1 >= $d2)}"; then
    echo "yes"
else
    echo "no"
fi
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ungalcrys
  • 5,242
  • 2
  • 39
  • 23
  • 2
    Using awk is great since it is able to handle floating point numbers, but I personally prefer the synthax `if (( $(echo $d1 $d2 | awk '{if ($1 > $2) print 1;}') )); then echo "yes"; else echo "no"; fi` – David Georg Reichelt Jul 13 '20 at 13:04
  • I'm having to do this in a debian-based docker image, where `bc` is not found. This is the cleanest `awk` implementation, IMO. – SiHa Aug 14 '23 at 11:22
11

Beware when comparing numbers that are package versions, like checking if grep 2.20 is greater than version 2.6:

$ awk 'BEGIN { print (2.20 >= 2.6) ? "YES" : "NO" }'
NO

$ awk 'BEGIN { print (2.2 >= 2.6) ? "YES" : "NO" }'
NO

$ awk 'BEGIN { print (2.60 == 2.6) ? "YES" : "NO" }'
YES

I solved such problems with such a shell/AWK function:

# Get version of GNU tool
toolversion() {
    local prog="$1" operator="$2" value="$3" version

    version=$($prog --version | awk '{print $NF; exit}')

    awk -vv1="$version" -vv2="$value" 'BEGIN {
        split(v1, a, /\./); split(v2, b, /\./);
        if (a[1] == b[1]) {
            exit (a[2] '$operator' b[2]) ? 0 : 1
        }
        else {
            exit (a[1] '$operator' b[1]) ? 0 : 1
        }
    }'
}

if toolversion grep '>=' 2.6; then
   # Do something awesome
fi
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
glen
  • 1,657
  • 19
  • 19
  • 1
    On a Debian-based system, `dpkg --compare-versions` is often useful. It has the full logic for comparing Debian package versions built into it, which are more complex than just `x.y`. – Neil Mayhew Dec 14 '17 at 21:10
  • @NeilMayhew just what I needed. – Edheldil Apr 07 '21 at 08:08
  • sorting versions like this is a bad idea. It won't be able to handle things like `v1.5.1` or `12.1.3-a`. `sort -V` or `sort --version-sort` would be much better – phuclv May 24 '23 at 12:17
8

A solution that supports all possible notations, including the scientific notation with both uppercase and lowercase exponents (e.g., 12.00e4):

if (( $(bc -l <<< "${value1/e/E} < ${value2/e/E}") ))
then
    echo "$value1 is smaller than $value2"
fi 
Danila Piatov
  • 1,201
  • 15
  • 15
7

Of course, if you don't need really floating-point arithmetic, just arithmetic on e.g. dollar values where there are always exactly two decimal digits, you might just drop the dot (effectively multiplying by 100) and compare the resulting integers.

if [[ $((10#${num1/.})) < $((10#${num2/.})) ]]; then
    ...

This obviously requires you to be sure that both values have the same number of decimal places.

tripleee
  • 175,061
  • 34
  • 275
  • 318
6

Please check the below edited code:

#!/bin/bash

export num1=(3.17648*e-22)
export num2=1.5

st=$((`echo "$num1 < $num2"| bc`))
if [ $st -eq 1 ]
  then
    echo -e "$num1 < $num2"
  else
    echo -e "$num1 >= $num2"
fi

This works well.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gopika BG
  • 797
  • 6
  • 10
5

AWK and tools like it (I'm staring at you sed...) should be relegated to the dustbin of old projects, with code that everyone is too afraid to touch since it was written in a read-never language.

Or you're the relatively rare project that needs to prioritize CPU usage optimization over code maintenance optimization... in which case, carry on.

If not, though, instead just use something readable and explicit, such as Python. Your fellow coders and future self will thank you. You can use Python code inline with Bash just like all the others.

num1=3.17648E-22
num2=1.5
if python -c "exit(0 if $num1 < $num2 else 1)"; then
    echo "yes, $num1 < $num2"
else
    echo "no, $num1 >= $num2"
fi
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
CivFan
  • 13,560
  • 9
  • 41
  • 58
  • @Witiko My original version was a bit snarkier. – CivFan Oct 16 '17 at 15:39
  • Even more succinct: use `not(...)` instead of `0 if ... else 1` – Neil Mayhew Dec 14 '17 at 21:06
  • @NeilMayhew I thought about that, but it's rather confusing to read, since the translation from Python True/False (1, 0) to bash True/False (0, 1) is not real obvious. I figure being explicit in the translation is the best compromise. – CivFan Dec 14 '17 at 21:11
  • 2
    If you're relegating awk and sed (I'm looking at you CivFan) to the dustbin of history, you're a lousy systems administrator and you're typing too much code. (And I like and use Python, so it's not about that). -1 for misplaced snarkiness. There's a place in the systems domain for those tools, Python or no. – Mike S Dec 14 '17 at 21:42
  • @MikeS I appreciate the return snark. :] I have little against `awk` and `sed` as command-line tools, one-off things. I have everything against them when they get injected into code projects. And hazarding a generalization, if you're doing floating point comparisons with scientific notation, you're not likely at your terminal but instead writing code for a project. – CivFan Dec 14 '17 at 21:49
  • @CivFan, then I agree with you. And, I have to admit, I am doing a bc comparison of a large body of floating point numbers on the command line and finding it too slow. So I'm starting to think about Python... :-! Bad snarky StackOverflower, bad! – Mike S Dec 14 '17 at 22:08
  • 1
    Interestingly, I ended up with good ol' Perl! `awk '${print $5}' ptpd_log_file | perl -ne '$_ > 0.000100 && print' > /tmp/outfile`. Easy peasy. Every language has its place. – Mike S Dec 14 '17 at 22:22
  • @MikeS I have to admit, that's a pretty one-liner. I still feel like I know what it's doing at quick glance. – CivFan Dec 15 '17 at 16:03
  • My logic was broken. I needed an 'abs'; it should be: `awk -F, '${print $5}' ptpd_log_file | perl -ne 'abs > 0.000100 && print' > /tmp/outfile` Or, as perl-only (which actually is a little uglier IMHO, if more efficient): `perl -F, -ane '$x=abs($F[5]); $x > 0.000001 && printf "%1.6f\n", $x;' ptpd_log_file` – Mike S Dec 26 '17 at 14:15
  • 2
    Don't lump awk in with seds syntacic wackiness. Unlike python, awk is a mandatory utility on every UNIX installation and the awk equivalent of `python -c "import sys; sys.exit(0 if float($num1) < float($num2) else 1)"` is simply `awk "BEGIN{exit ($num1 > $num2 ? 0 : 1)}"`. – Ed Morton Jun 02 '19 at 14:40
  • @EdMorton You got the logic inverted, but sure, that's fair. Though once in `python`, you're only one step away from removing the `bash` requirement, too. – CivFan Jun 03 '19 at 22:43
  • @EdMorton you inspired me to simplify the python further to `python -c "exit(0 if $num1 < $num2 else 1)"`, which has the benefit of easier to read ternary operation, and python is more cross-platform friendly than awk. – CivFan Jun 06 '19 at 20:35
  • I assume you mean easier to read than your previous python scripts expression as it's still got that convoluted "result1 if condition else result2" logic compared to the much clearer "if condition then result1 else result2" logic I have in the awk script. awk is more portable across UNIX systems than python since it's a mandatory tool required to exist on all UNIX systems and it's available for Windows which knocks off the 2 biggest platforms. – Ed Morton Jun 06 '19 at 22:42
  • @EdMorton That's... not how `$num1 > $num2 ? 0 : 1` reads. It's more like "condition if result1 else result2" but not really even that since it's all in symbols. But anyway, I personally like that (awk) ternary syntax, but I've heard many a complaint about it from others. – CivFan Jun 07 '19 at 01:21
  • @CivFan : python3 is so painfully slow compared to awk (esp mawk2) it's not even funny – RARE Kpop Manifesto Apr 24 '22 at 20:32
  • @RAREKpopManifesto Maintaining the awk version will generally be more costly and slow. – CivFan Apr 25 '22 at 17:28
  • @CivFan : python3 is suffering mightily from feature bloat - if they don't start reigning it in it may commence a downtrend and obsoletion cycle within a couple years, if it hasn't started already. C++ is in worse shape - they try to bolt on every new idea from the likes of python3/go, and now the spec is all over the place, since they had to maintain backward compatibility by-and-large. It has an extreme identity crisis as it tries to be both a very low level AND a very high level language at the same time. – RARE Kpop Manifesto Apr 28 '22 at 18:12
4
num1=0.555
num2=2.555


if [ `echo "$num1>$num2"|bc` -eq 1 ]; then
       echo "$num1 is greater then $num2"
else
       echo "$num2 is greater then $num1"
fi
rmil
  • 76
  • 2
  • An explanation would be in order. E.g., how is it different from previous answers and what is the idea/gist? Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/52470704/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Oct 26 '21 at 14:34
3

I used the answers from here and put them in a function. You can use it like this:

is_first_floating_number_bigger 1.5 1.2
result="${__FUNCTION_RETURN}"

Once called, echo $result will be 1 in this case, otherwise 0.

The function:

is_first_floating_number_bigger () {
    number1="$1"
    number2="$2"

    [ ${number1%.*} -eq ${number2%.*} ] && [ ${number1#*.} \> ${number2#*.} ] || [ ${number1%.*} -gt ${number2%.*} ];
    result=$?
    if [ "$result" -eq 0 ]; then result=1; else result=0; fi

    __FUNCTION_RETURN="${result}"
}

Or a version with debug output:

is_first_floating_number_bigger () {
    number1="$1"
    number2="$2"

    echo "... is_first_floating_number_bigger: comparing ${number1} with ${number2} (to check if the first one is bigger)"

    [ ${number1%.*} -eq ${number2%.*} ] && [ ${number1#*.} \> ${number2#*.} ] || [ ${number1%.*} -gt ${number2%.*} ];
    result=$?
    if [ "$result" -eq 0 ]; then result=1; else result=0; fi

    echo "... is_first_floating_number_bigger: result is: ${result}"

    if [ "$result" -eq 0 ]; then
        echo "... is_first_floating_number_bigger: ${number1} is not bigger than ${number2}"
    else
        echo "... is_first_floating_number_bigger: ${number1} is bigger than ${number2}"
    fi

    __FUNCTION_RETURN="${result}"
}

Just save the function in a separated .sh file and include it like this:

. /path/to/the/new-file.sh
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Thomas Kekeisen
  • 4,355
  • 4
  • 35
  • 54
3

For simplicity and clarity, just use AWK for the calculations as it's a standard Unix tool and so just as likely to be present as bc and much easier to work with syntactically.

For this question:

$ cat tst.sh
#!/bin/bash

num1=3.17648e-22
num2=1.5

awk -v num1="$num1" -v num2="$num2" '
BEGIN {
    print "num1", (num1 < num2 ? "<" : ">="), "num2"
}
'

$ ./tst.sh
num1 < num2

And for that other question that was closed as a duplicate of this one:

$ cat tst.sh
#!/bin/bash

read -p "Operator: " operator
read -p "First number: " ch1
read -p "Second number: " ch2

awk -v ch1="$ch1" -v ch2="$ch2" -v op="$operator" '
BEGIN {
    if ( ( op == "/" ) && ( ch2 == 0 ) ) {
        print "Nope..."
    }
    else {
        print ch1 '"$operator"' ch2
    }
}
'

$ ./tst.sh
Operator: /
First number: 4.5
Second number: 2
2.25

$ ./tst.sh
Operator: /
First number: 4.5
Second number: 0
Nope...

I was posting this as an answer to '4.5: syntax error: invalid arithmetic operator (error token is ".5")' - but the code still seems to work. Why? when it got closed as a duplicate of this question, so here it is as it applies here too.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
2

This script may help where I'm checking if the installed Grails version is greater than the minimum required.

#!/bin/bash

min=1.4
current=`echo $(grails --version | head -n 2 | awk '{print $NF}' | cut -c 1-3)`

if [ 1 -eq `echo "${current} < ${min}" | bc` ]
then
    echo "Yo, you have an older version of Grails."
else
    echo "Hurray, you have the latest version"
fi
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
prayagupa
  • 30,204
  • 14
  • 155
  • 192
1

Use KornShell. In Bash you may have to compare the decimal part separately:

#!/bin/ksh
X=0.2
Y=0.2
echo $X
echo $Y

if [[ $X -lt $Y ]]
then
     echo "X is less than Y"
elif [[ $X -gt $Y ]]
then
     echo "X is greater than Y"
elif [[ $X -eq $Y ]]
then
     echo "X is equal to Y"
fi
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 3
    the problem is that many distributions do not come with ksh installed, and if your script is going to be used by others, they tend to not like having to install extra stuff, especially when its just a script that is supposed to be written in bash -one would think they didnt need ANOTHER shell to do that, which undermines the whole reason of using a bash script in the first place --sure we could ALSO go code it in C++, but why? – osirisgothra Nov 06 '13 at 10:56
  • What are the distributions which come without ksh installed? – piokuc Sep 15 '14 at 10:01
  • 2
    @piokuc for example, Ubuntu Desktop & Server. I would say it's pretty major one... – Olli Dec 21 '14 at 11:57
  • Also, question specifically asks for solution that works in bash. There might be really good reasons for that. Say, it's part of large application and migrating everything to ksh is not feasible. Or it's running on embedded platform where installing another shell is really a problem. – Olli Dec 21 '14 at 12:00
1

Use this:

VAL_TO_CHECK="1.00001"
if [ $(awk '{printf($1 >= $2) ? 1 : 0}' <<<" $VAL_TO_CHECK 1 ") -eq 1 ] ; then
    echo "$VAL_TO_CHECK >= 1"
else
    echo "$VAL_TO_CHECK < 1"
fi
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Eduardo Lucio
  • 1,771
  • 2
  • 25
  • 43
  • 1
    The Awk script should simply `exit 0` to report truth and `exit 1` to return false; then you can simplify to the remarkably elegant `if awk 'BEGIN { exit (ARGV[1] >= ARGV[2]) ? 0 : 1 }' "$VAL_TO_CHECK" 1; then`... (more elegant still if you encapsulate the Awk script in a shell function). – tripleee Dec 08 '17 at 10:45
1

Using bashj, a Bash mutant with Java support, you just write (and it is easy to read):

#!/usr/bin/bashj

#!java
static int doubleCompare(double a,double b) {return((a>b) ? 1 : (a<b) ? -1 : 0);}

#!bashj
num1=3.17648e-22
num2=1.5
comp=j.doubleCompare($num1,$num2)
if [ $comp == 0 ] ; then echo "Equal" ; fi
if [ $comp == 1 ] ; then echo "$num1 > $num2" ; fi
if [ $comp == -1 ] ; then echo "$num2 > $num1" ; fi

Of course, the bashj Bash/Java hybridation offers much more...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Fil
  • 27
  • 4
1

A very simple perl solution:

$ num1=3.2E8
$ num2=2.5E9
$ perl -e "print $num2 > $num1? 'true' : 'false', qq(\n);"
true
$ perl -e "print $num2 < $num1? 'true' : 'false', qq(\n);"
false

This proves that perl really understands the 'E' notation for scientific numerical representation:

$ perl -e "print $num1, qq(\n);"
320000000

If you need a 'if' statment in your shell script, use exit command in perl:

$ if perl -e "exit ($num1 > $num2? 0 : 1);"; then echo true; else echo false; fi
false

Note that in shell script, a command returning 0 is a success, and passes the 'if' condition (so the if-clause is executed). Any other non-zero return values means a failure.

Robin Hsu
  • 174
  • 1
  • 9
0

Just replace the echo with a printf (it understands floats):

st=$(  printf '%50G < %50G\n' "$num1" "$num2" | bc -l  )
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

There's one simple approach which is a bit faster than AWK and does not require bc to be installed. It leverages sort's ability to sort float numbers:

A=1280.4
B=9.325
LOW=$(sort -n <<< "$A"$'\n'"$B" | head -1)
if [[ "$LOW" == "$A" ]]; then
    echo "A <= B"
else
    echo "A >= B"
fi

Of course, it does not work for numbers that are equal.

Newerth
  • 449
  • 2
  • 12
0

A one-liner solution

Suppose you have two variables A and B,

echo "($A > $B) * $B + ($A < $B) * $A" | bc
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bobby
  • 197
  • 1
  • 7
0

Here's a gawk+GMP based approach to account for a broader range of potential input :

 echo " 5.65e-23 3.14e-22\n
        5.65 3.14e-2203\n
        3.145678 3.145679\n
        3.25353E+9293 325353e9288\n
        3.14159e+200000000001 3.1415899999999999999999E200000000001\n
        100000 100000.0\n
             4096 4096" \
                         \
 | gawk -v PREC=9999999 -nMbe '
  
   NF+=OFS=sprintf(" %s ",
          (+($!_=sprintf("%24s",$!_)<+$NF) \
     ? "<" \
        : (+$NF<+$!_) \
     ? ">" \
        : (int(+$!_)==(__=int(+$NF)))*\
          (__==+$NF)*index($!_,$NF  )  \
     ? "=" \
         : "\342\211\210")' | ecp 
 
                5.65e-23 < 3.14e-22
                    5.65 > 3.14e-2203
                3.145678 < 3.145679
           3.25353E+9293 ≈ 325353e9288
   3.14159e+200000000001 ≈ 3.1415899999999999999999E200000000001
                  100000 ≈ 100000.0
                    4096 = 4096
 

For more clear-cut cases, it'll give you back a definitive answer of

  • less than <,
  • greater than >, or
  • exactly equal to = (purely integer cases, for now)

When it's relatively ambiguous, it outputs the Unicode character U+2248 ≈ ALMOST EQUAL TO instead of attempting to resolve it at all cost.

Most of the time you won't need PREC of 10-million; something like PREC = 32767 is good enough for most scenarios one encounters on a typical basis.

RARE Kpop Manifesto
  • 2,453
  • 3
  • 11