Как сравнить два значения с плавающей точкой в ​​сценарии оболочки - PullRequest
4 голосов
/ 05 мая 2010

Я должен был сделать деление в сценарии оболочки, и лучший способ был:

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 ] не работало: (

Есть идеи, как это сделать?

Ответы [ 3 ]

6 голосов
/ 05 мая 2010

Вы можете сравнивать числа с плавающей запятой, используя 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 не может.

0 голосов
/ 29 марта 2016

Публикация нового ответа, так как я пока не могу комментировать ...

@ Ответ Нормана Рэмси не совсем точен:

  • expr выполнит сравнение целых чисел или строк, а не сравнение с плавающей запятой.
    Вот что написано на странице руководства:

    expr1 {=,>,> =, <, <=,! =} Expr2 </strong>

    Вернуть результаты сравнения целых чисел , если оба аргумента являются целыми числами; в противном случае возвращает результаты сравнения строк с использованием последовательности сопоставления для конкретного языка.

    (просто попробуйте 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

0 голосов
/ 05 мая 2010

обратите внимание, что вы должны быть немного осторожнее при работе с числами с плавающей запятой, и если вы проверяете равенство, вы действительно хотите определиться с некоторой точностью, а затем сравнить, используя это. Что-то вроде:

if (abs(x1-x2) < 0.0001) then equal # pseudo-code

причина в том, что с компьютерами мы имеем дело с бинарными дробями ограниченной точности, а не с математическими данными. Ограничение точности в bc по шкале = 3 даст этот эффект.

Я бы также советовал не пытаться делать это в сценарии оболочки. Дело не в том, что вы не можете этого сделать, но вам придется отключить множество маленьких подкоманд, чтобы выполнить сложные биты, а выполнение выполняется медленно, и, как правило, писать очень сложно - вы проводите большую часть своего времени, пытаясь получить оболочку делать то, что вы хотите, а не писать код, который вы действительно хотите. Вместо этого перейдите на более сложный язык сценариев; Мой язык выбора - Perl, но есть и другие. как это ...

echo $var1 $var2 $total | perl -ne 'my ($var1, $var2, $tot) = split /\s+/; if ($var1/$tot == $var2/$tot) { print "equal\n"; }'

также обратите внимание, что вы делите на одно и то же значение ($ total в вашем вопросе), поэтому можно провести полное сравнение с числителями (var1 и var2) при условии, что $ total положительно

...