[英]How to compare two floating point numbers in Bash?
I am trying hard to compare two floating point numbers within a bash script.我正在努力比较 bash 脚本中的两个浮点数。 I have to variables, eg
我必须变量,例如
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 的正确处理有一些问题,它可能是“电子格式”。
This can be done more conveniently using Bash's numeric context:这可以使用 Bash 的数字上下文更方便地完成:
if (( $(echo "$num1 > $num2" |bc -l) )); then
…
fi
Piping through the basic calculator command bc
returns either 1 or 0.通过基本计算器命令
bc
管道返回 1 或 0。
The option -l
is equivalent to --mathlib
;选项
-l
等效于--mathlib
; it loads the standard math library.它加载标准数学库。
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
基本计算器包。
Caveat: Exponential notation should be written as *10^
;警告:指数符号应写为
*10^
; not E
, nor e
.不是
E
,也不是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 .此处讨论了克服此
bc
限制的策略。
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注意指数符号必须大写
It's better to use awk
for non integer mathematics.最好将
awk
用于非整数数学。 You can use this bash utility function:您可以使用此 bash 实用程序功能:
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
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).不会将浮点数与整数(不带点)进行比较。
You can use awk
combined with a bash if condition:如果条件满足,您可以将
awk
与 bash 结合使用:
if awk "BEGIN {exit !($d1 >= $d2)}"; then
echo "yes"
else
echo "no"
fi
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="$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
Of course, if you don't need really floating-point arithmetic, just arithmetic on eg 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.这显然要求您确保两个值具有相同的小数位数。
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. awk
和类似的工具(我在盯着你sed
...)应该被归入旧项目的垃圾箱,因为它的代码是用永不阅读的语言编写的,所以每个人都不敢碰它。
Or you're the relatively rare project that needs to prioritize CPU usage optimization over code maintenance optimization... in which case, carry on.或者您是需要优先考虑 CPU 使用优化而不是代码维护优化的相对罕见的项目……在这种情况下,继续。
If not, though, why not instead just use something readable and explicit, such as python
?如果没有,为什么不使用可读和明确的东西,比如
python
? Your fellow coders and future self will thank you.你的程序员伙伴和未来的自己会感谢你。 You can use
python
inline with bash just like all the others.您可以像所有其他人一样将
python
与 bash 内联使用。
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
A solution supporting all possible notations, including the scientific notation with both uppercase and lowercase exponents (eg, 12.00e4
):支持所有可能的符号的解决方案,包括具有大写和小写指数的科学记数法(例如,
12.00e4
):
if (( $(bc -l <<< "${value1/e/E} < ${value2/e/E}") ))
then
echo "$value1 is below $value2"
fi
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="$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:只需将函数保存在一个单独的
.sh
文件中,并像这样包含它:
. /path/to/the/new-file.sh
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.这很好用。
I was posting this as an answer to https://stackoverflow.com/a/56415379/1745001 when 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...
This script may help where I'm checking if installed grails
version is greater than minimum required.这个脚本可以帮助我检查安装的
grails
版本是否大于最低要求。 Hope it helps.希望能帮助到你。
#!/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
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
Use korn shell, in bash you may have to compare the decimal part separately使用 korn shell,在 bash 中,您可能需要分别比较小数部分
#!/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
How about this?这个怎么样? =D
=D
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
Using bashj ( https://sourceforge.net/projects/bashj/ ), a bash mutant with java support, you just write (and it IS easy to read):使用 bashj ( https://sourceforge.net/projects/bashj/ ),一个支持 java 的 bash 突变体,你只需编写(并且很容易阅读):
#!/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 bashj bash/java hybridation offers much more...当然 bashj bash/java 混合提供了更多......
只需用 printf 替换echo
(它理解浮点数):
st=$( printf '%50G < %50G\n' "$num1" "$num2" | bc -l )
There's one simple approach which is a bit faster than AWK and does not require bc
to be installed.有一种简单的方法,它比 AWK 快一点,并且不需要安装
bc
。 It leverages sort
's ability to sort float numbers:它利用
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
Of course, it does not work for numbers that are equal .当然,它不适用于相等的数字。
One liner solution一个班轮解决方案
Suppose you have two variables A
and B
假设你有两个变量
A
和B
echo "($A > $B) * $B + ($A < $B) * $A" | bc
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.