Как сравнить два значения плавающих точек в скрипте оболочки

StackOverflow https://stackoverflow.com/questions/2769671

Вопрос

Я должен был сделать разделение в сценарии 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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top