How to compare two floating point numbers in Bash?

前端 未结 17 2156
無奈伤痛
無奈伤痛 2020-11-22 02:17

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

let num1=3.17648e-22
let num2=1.5

No

相关标签:
17条回答
  • 2020-11-22 02:47

    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
    
    0 讨论(0)
  • 2020-11-22 02:48

    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.

    0 讨论(0)
  • 2020-11-22 02:48

    Use korn shell, 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
    
    0 讨论(0)
  • 2020-11-22 02:50

    It's better to use awk for non integer 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
    
    0 讨论(0)
  • 2020-11-22 02:53

    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 problem with such 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
    
    0 讨论(0)
  • 2020-11-22 02:56

    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.

    This equally works for floats in scientific format, provided a capital letter E is employed, e.g. num1=3.44E6

    0 讨论(0)
提交回复
热议问题