如何在 Bash 中比较两个浮点数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8654051/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to compare two floating point numbers in Bash?
提问by Jonas
I am trying hard to compare two floating point numbers within a bash script. I have to variables, e.g.
我正在努力比较 bash 脚本中的两个浮点数。我必须变量,例如
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". :(
不幸的是,我对 num1 的正确处理有一些问题,它可能是“电子格式”。:(
Any help, hints are welcome!
任何帮助,欢迎提示!
回答by Serge Stroobandt
More conveniently
更方便
This can be done more conveniently using Bash's numeric context:
这可以使用 Bash 的数字上下文更方便地完成:
if (( $(echo "$num1 > $num2" |bc -l) )); then
…
fi
Explanation
解释
Piping through the basic calculator command bc
returns either 1 or 0.
通过基本计算器命令管道bc
返回 1 或 0。
The option -l
is equivalent to --mathlib
; it loads the standard math library.
该选项-l
等效于--mathlib
; 它加载标准数学库。
Enclosing the whole expression between double parenthesis (( ))
will translate these values to respectively true or false.
将整个表达式括在双括号之间(( ))
会将这些值分别转换为 true 或 false。
Please, ensure that the bc
basic calculator package is installed.
请确保bc
安装了基本计算器包。
This equally works for floats in scientific format, provided a capital letter E
is employed, e.g. num1=3.44E6
如果使用大写字母,这同样适用于科学格式的浮点数E
,例如num1=3.44E6
回答by alrusdi
bash handles only integer maths
but you can use bc
command as follows:
bash 只处理整数数学,但您可以使用bc
如下命令:
$ num1=3.17648E-22
$ num2=1.5
$ echo $num1'>'$num2 | bc -l
0
$ echo $num2'>'$num1 | bc -l
1
Note that exponent sign must be uppercase
注意指数符号必须大写
回答by anubhava
It's better to use awk
for non integer mathematics. You can use this bash utility function:
最好awk
用于非整数数学。您可以使用此 bash 实用程序功能:
numCompare() {
awk -v n1="" -v n2="" '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
回答by user
Pure bash solution for comparing floats without exponential notation, leading or trailing zeros:
用于比较没有指数符号、前导或尾随零的浮点数的纯 bash 解决方案:
if [ ${FOO%.*} -eq ${BAR%.*} ] && [ ${FOO#*.} \> ${BAR#*.} ] || [ ${FOO%.*} -gt ${BAR%.*} ]; then
echo "${FOO} > ${BAR}";
else
echo "${FOO} <= ${BAR}";
fi
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.
逻辑运算符的顺序很重要。整数部分作为数字进行比较,小数部分有意作为字符串进行比较。使用此方法将变量拆分为整数部分和小数部分。
Won't compare floats with integers (without dot).
不会将浮点数与整数(不带点)进行比较。
回答by ungalcrys
you can use awk combined with a bash if condition, awk will print 1or 0and those will be interpreted by if clause with trueor false.
您可以将 awk 与 bash if 条件结合使用,awk 将打印1或0,这些将被 if 子句解释为true或false。
if (( $(awk 'BEGIN {print ("'$d1'" >= "'$d2'")}') )); then
echo "yes"
else
echo "no"
fi
回答by Elan Ruusam?e
beware when comparing numbers that are package versions, like checking if grep 2.20 is greater than version 2.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
I solved such problem with such shell/awk function:
我用这样的 shell/awk 函数解决了这个问题:
# get version of GNU tool
toolversion() {
local prog="" operator="" value="" 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
回答by tripleee
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.
当然,如果您不需要真正的浮点算术,只需对美元值进行算术运算,其中始终只有两位十进制数字,您可能只需删除点(有效乘以 100)并比较结果整数。
if [[ $((10#${num1/.})) < $((10#${num2/.})) ]]; then
...
This obviously requires you to be sure that both values have the same number of decimal places.
这显然要求您确保两个值具有相同的小数位数。
回答by Thomas Kekeisen
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
.
一旦调用,echo $result
将1
在这种情况下,否则0
。
The function:
功能:
is_first_floating_number_bigger () {
number1=""
number2=""
[ ${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=""
number2=""
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:
只需将函数保存在一个单独的.sh
文件中,并像这样包含它:
. /path/to/the/new-file.sh
回答by Ed Morton
I was posting this as an answer to https://stackoverflow.com/a/56415379/1745001when it got closed as a dup of this question so here it is as it applies here too:
当它作为这个问题的副本被关闭时,我将其发布为https://stackoverflow.com/a/56415379/1745001的答案,因此它也适用于此处:
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.
为简单起见,只需使用 awk 进行计算,因为它是标准的 UNIX 工具,因此与 bc 一样可能出现,并且在语法上更易于使用。
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 dup 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...
回答by prayagupd
This script may help where I'm checking if installed grails
version is greater than minimum required. Hope it helps.
这个脚本可以帮助我检查安装的grails
版本是否大于最低要求。希望能帮助到你。
#!/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 older version of grails."
else
echo "Hurray, you have the latest version"
fi