如何比较Bash中的两个浮点数?

Jon*_*nas 125 floating-point bash comparison numbers

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

let num1=3.17648e-22
let num2=1.5
Run Code Online (Sandbox Code Playgroud)

现在,我只想对这两个数字进行简单的比较:

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

不幸的是,我对num1的正确处理存在一些问题,这可能是"电子格式".:(

任何帮助,欢迎提示!

Ser*_*ndt 139

更方便

使用Bash的数字上下文可以更方便地完成此操作:

if (( $(echo "$num1 > $num2" |bc -l) )); then
  …
fi
Run Code Online (Sandbox Code Playgroud)

说明

通过基本计算器命令管道bc返回1或0.

该选项-l相当于--mathlib; 它加载标准的数学库.

在双括号之间包含整个表达式(( ))将这些值分别转换为true或false.

请确保bc安装了基本的计算器包.

  • 找不到命令错误.我错过了什么 (2认同)
  • 根据“bc -l”,“3.44E6”与“3.4546”相同。如果您想要“3.44*10^6”,请使用字符串“3.44*10^6”或“3440000”。 (2认同)

alr*_*sdi 97

bash只处理整数数学但你可以使用bc如下命令:

$ num1=3.17648E-22
$ num2=1.5
$ echo $num1'>'$num2 | bc -l
0
$ echo $num2'>'$num1 | bc -l
1
Run Code Online (Sandbox Code Playgroud)

请注意,指数符号必须为大写

  • 因为他试图在if语句中使用它,我会证明这一点.如果[$(... | bc -l)== 1]; 然后 ... (6认同)
  • 它不是一个非常相似的*解决方案.Alrusdi的解决方案使用`bc`工具,这是我向任何BASH程序员推荐的.BASH是无类型语言.是的,它可以进行整数运算,但对于浮点运算,你必须使用一些外部工具.BC是最好的,因为它就是它的制作方式. (4认同)
  • 是的,但要解决不正确的计算,需要用科学数字表示法大写"e"符号,并使用-l标志为bc programm进行预定义的数学例程 (3认同)
  • 你应该在你的答案中指出这一点,而不仅仅是发布一个非常类似的解决方案,而不是提到重要的差异. (2认同)

anu*_*ava 24

最好awk用于非整数数学.您可以使用此bash实用程序功能:

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

称之为:

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
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个答案,人们往往会回避awk esp初学者,他们似乎认为它比实际上更难,我认为人们会受到花括号和看似语言混合语法(一目了然)的威胁.并且因为awk几乎可以保证存在于目标系统上,就像bc一样(不确定哪一个,如果有的话,还没有安装).我喜欢bash脚本,但没有浮动点,甚至没有微小的2位小数(我猜有人可以写一个'假的'包装器),真的很烦人...... (2认同)
  • 在shell脚本中使用`awk`和`bc`是一个标准的做法,自古以来,我会说一些功能从未添加到shell中,因为它们在awk,bc和其他Unix工具中可用.shell脚本中不需要纯度. (2认同)
  • 为什么只是“python”。在许多 Linux/Unix 系统上默认安装了“perl”..甚至“php”也安装了 (2认同)

use*_*ser 21

用于比较不带指数表示法,前导或尾随零的浮点数的纯bash解决方案:

if [ ${FOO%.*} -eq ${BAR%.*} ] && [ ${FOO#*.} \> ${BAR#*.} ] || [ ${FOO%.*} -gt ${BAR%.*} ]; then
  echo "${FOO} > ${BAR}";
else
  echo "${FOO} <= ${BAR}";
fi
Run Code Online (Sandbox Code Playgroud)

逻辑运算符的顺序很重要.将整数部分作为数字进行比较,将小数部分有意地作为字符串进行比较.使用此方法将变量拆分为整数和小数部分.

不会将浮点数与整数(没有点)进行比较.


ung*_*rys 14

你可以使用awk结合bash if条件,awk将打印10,这些将由if子句用truefalse解释.

if (( $(awk 'BEGIN {print ("'$d1'" >= "'$d2'")}') )); then
    echo "yes"
else 
    echo "no"
fi
Run Code Online (Sandbox Code Playgroud)

  • 使用 awk 很棒,因为它能够处理浮点数,但我个人更喜欢 Syntax `if (( $(echo $d1 $d2 | awk '{if ($1 &gt; $2) print 1;}') )); 然后回显“是”;否则回显“不”;菲` (2认同)
  • 这不能按规定工作。不管怎样,awk 都会以 0 状态退出。将“print”替换为“exit”,就可以了。 (2认同)
  • @Otheus您需要将其替换为“退出!”,否则它将返回相反的结果。我适当地编辑了答案。 (2认同)

Dan*_*tov 8

支持所有可能的符号的解决方案,包括具有大写和小写指数的科学符号(例如,12.00e4):

if (( $(bc -l <<< "${value1/e/E} < ${value2/e/E}") ))
then
    echo "$value1 is smaller than $value2"
fi 
Run Code Online (Sandbox Code Playgroud)


gle*_*len 6

在比较包版本的数字时要小心,比如检查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
Run Code Online (Sandbox Code Playgroud)

我用这样的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
Run Code Online (Sandbox Code Playgroud)


Gop*_* BG 6

请检查以下编辑后的代码:

#!/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
Run Code Online (Sandbox Code Playgroud)

这效果很好。


Civ*_*Fan 5

AWK和类似的工具(我正盯着你看sed……)应该被扔进旧项目的垃圾箱,其中的代码每个人都不敢碰,因为它是用一种从不读的语言编写的。

或者您是一个相对罕见的项目,需要优先考虑 CPU 使用优化而不是代码维护优化......在这种情况下,请继续。

如果不是,那么,只需使用可读且明确的东西,例如 Python。你的同事和未来的自己都会感谢你。您可以像其他所有代码一样使用与 Bash 内联的 Python 代码。

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
Run Code Online (Sandbox Code Playgroud)

  • 如果您将 awk 和 sed(我指的是您 CivFan)扔进了历史的垃圾箱,那么您就是一个糟糕的系统管理员,并且您输入了太多代码。(而且我喜欢并使用Python,所以这不是重点)。-1 表示不恰当的尖酸刻薄。这些工具在系统领域中占有一席之地,无论是否有 Python。 (2认同)
  • 不要将 awk 与 sed 的语法古怪混为一谈。与 python 不同,awk 是每个 UNIX 安装上的强制实用程序,awk 相当于 `python -c "import sys; sys.exit(0 if float($num1) &lt; float($num2) else 1)"` 就是简单的 ` awk "BEGIN{exit ($num1 &gt; $num2 ? 0 : 1)}"`. (2认同)

tri*_*eee 5

当然,如果您不需要真正的浮点算术,只需对例如总是有两个十进制数字的美元值进行算术,您就可以删除点(有效乘以100)并比较所得的整数。

if [[ $((10#${num1/.})) < $((10#${num2/.})) ]]; then
    ...
Run Code Online (Sandbox Code Playgroud)

显然,这要求您确保两个值的小数位数相同。