我正在努力比较Bash脚本中的两个浮点数。我有两个变量,例如。

let num1=3.17648e-22
let num2=1.5

现在,我想对这两个数字做一个简单的比较:

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

不幸的是,我有一些问题与num1的正确处理可以是“电子格式”。


当前回答

一行程序解决方案

假设有两个变量A和B,

echo "($A > $B) * $B + ($A < $B) * $A" | bc

其他回答

我使用这里的答案,并把它们放在一个函数中。你可以这样使用它:

is_first_floating_number_bigger 1.5 1.2
result="${__FUNCTION_RETURN}"

一旦被调用,echo $result在这种情况下将为1,否则为0。

功能:

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}"
}

或者带有调试输出的版本:

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}"
}

只需要将函数保存在一个单独的.sh文件中,并像这样包含它:

. /path/to/the/new-file.sh
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

以下是基于gawk+GMP的方法,用于考虑更广泛的潜在输入:

 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
 

对于更明确的情况,它会给你一个明确的答案

小于<, 大于>,或者 完全等于=(目前是纯整数情况)

当它相对不明确时,它输出Unicode字符U+2248≈ALMOST EQUAL TO,而不是试图不惜一切代价解析它。

大多数情况下你不需要1000万的PREC;像PREC = 32767这样的值对于一个人在典型基础上遇到的大多数情况已经足够好了。

当比较包版本的数字时要注意,比如检查grep 2.20是否大于版本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

我用这样一个shell/AWK函数解决了这样的问题:

# 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

有一种简单的方法,比AWK快一点,而且不需要安装bc。它利用sort对浮点数进行排序的能力:

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

当然,对于相等的数字,这是行不通的。