Как сравнить два значения плавающих точек в скрипте оболочки
-
03-10-2019 - |
Вопрос
Я должен был сделать разделение в сценарии Shell, и лучший способ был:
result1=`echo "scale=3; ($var1 / $total) * 100"| bc -l`
result2=`echo "scale=3; ($var2 / $total) * 100"| bc -l`
Но я хочу сравнить ценности $result1
а также $result2
С использованием if test $result1 -lt $result2
или if [ $result1 -gt $result2 ]
не работал :(
Любая идея, как это сделать?
Решение
Вы можете сравнить номера с плавающей точкой, используя expr(1)
:
: nr@yorkie 3724 ; expr 3.1 '<' 3.3
1
: nr@yorkie 3725 ; expr 3.1 '<' 3.09
0
Вы также можете иметь bc
Сделайте сравнение, а также расчеты:
if [ "$(echo $result1 '<' $result2 | bc -l)" -eq 1 ];then ... fi
Наконец, KSH93 может сделать арифметическую оценку $(($result1 < $result2))
с плавающими точками, хотя Bash не может.
Другие советы
Обратите внимание, что вы должны быть немного осторожны при работе с номерами с плавающей запятой, и если вы тестируете на равенство, вы действительно хотите определиться с какой-то точностью, а затем сравнить с этим. Что-то типа:
if (abs(x1-x2) < 0.0001) then equal # pseudo-code
Причина в том, что с компьютерами мы имеем дело с ограниченными точными двоичными фракциями, не настоящие математические реалии. Ограничение точности в до н.э. со шкалой = 3 будет иметь этот эффект.
Я также советую против попыток сделать это в сценарии Shell. Дело не в том, что вы не можете это сделать, но вам придется разлить много маленьких командных команд, чтобы сделать сложные биты, и это медленно, чтобы выполнить и вообще боли, чтобы написать - вы проводите большую часть своего времени, пытаясь получить оболочку делать то, что вы хотите, а не написать код, который вы действительно хотите. Вместо этого выйдите на более сложный язык сценариев; Мой язык выбора - Perl, но есть другие. так...
echo $var1 $var2 $total | perl -ne 'my ($var1, $var2, $tot) = split /\s+/; if ($var1/$tot == $var2/$tot) { print "equal\n"; }'
Также обратите внимание, что вы разделяете по той же стоимости ($ Total в вашем вопросе), поэтому все сравнение может быть сделано против чисел (var1 и var2), если сумма
Размещение нового ответа, так как я еще не могу комментировать ...
@Norman reamsey's ответ не совсем точен:
expr
будет выполнять целочисленное или строковое сравнение, а не сравнение с плавающей точкой.
Вот что говорит на странице человека:expr1 {=,>,> =, <, <=,! =} expr2
Вернуть результаты целочисленное сравнение Если оба аргумента являются целыми числами; в противном случае возвращает результаты Сравнение строки Использование последовательности сопоставления, специфичной локалью.
(просто попробуй
expr 8.9 '<' 10
и получить0
где это должно быть1
).bc
Работает отлично, но не всегда устанавливается.
Так что другая альтернатива использует perl -e
:
perl -e 'print expression'
будет печать1
Если выражение верно и ничего (пустая строка) в противном случае.например
perl -e 'print 8.9 < 10'
- Печать «1», в то время какperl -e 'print 2>4'
Отпечатает ничего.И при использовании в
if
утверждение:if [ $(perl -e "print $result1 < $result2") ];then ... fi