web-dev-qa-db-ja.com

Bashで2つの浮動小数点数を比較するにはどうすればよいですか?

Bashスクリプト内の2つの浮動小数点数を比較しようとしています。変数が必要です。

let num1=3.17648e-22
let num2=1.5

ここで、これら2つの数値を簡単に比較したいだけです。

st=`echo "$num1 < $num2" | bc`
if [ $st -eq 1]; then
  echo -e "$num1 < $num2"
else
  echo -e "$num1 >= $num2"
fi

残念ながら、num1の正しい処理にはいくつかの問題があります。これは「eフォーマット」になります。 :(

どんな助け、ヒントも大歓迎です!

112
Jonas

より便利に

これは、Bashの数値コンテキストを使用してより便利に行うことができます。

if (( $(echo "$num1 > $num2" |bc -l) )); then
  …
fi

説明

基本的な電卓コマンドbcをパイピングすると、1または0が返されます。

オプション-l--mathlibと同等です。標準の数学ライブラリをロードします。

式全体を二重括弧(( ))で囲むと、これらの値がそれぞれtrueまたはfalseに変換されます。

bc基本計算機パッケージがインストールされていることを確認してください。

これは、大文字のEが使用されている場合、科学形式の浮動小数点数でも同様に機能します。 num1=3.44E6

117

bashは整数演算のみを処理しますが、次のようにbcコマンドを使用できます。

$ num1=3.17648E-22
$ num2=1.5
$ echo $num1'>'$num2 | bc -l
0
$ echo $num2'>'$num1 | bc -l
1

指数記号は大文字でなければならないことに注意してください

96
alrusdi

非整数数学にはawkを使用する方が良いでしょう。このbashユーティリティ関数を使用できます。

numCompare() {
   awk -v n1="$1" -v n2="$2" 'BEGIN {printf "%s " (n1<n2?"<":">=") " %s\n", n1, n2}'
}

そしてそれを次のように呼び出します:

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
23
anubhava

指数表記、先行ゼロまたは後続ゼロなしでフロートを比較するための純粋なbashソリューション:

if [ ${FOO%.*} -eq ${BAR%.*} ] && [ ${FOO#*.} \> ${BAR#*.} ] || [ ${FOO%.*} -gt ${BAR%.*} ]; then
  echo "${FOO} > ${BAR}";
else
  echo "${FOO} <= ${BAR}";
fi

論理演算子の順序 matters 。整数部分は数字として比較され、小数部分は意図的に文字列として比較されます。 この方法 を使用して、変数を整数部と小数部に分割します。

浮動小数点数と整数(ドットなし)を比較しません。

20
user

awkをbash if条件と組み合わせて使用​​できます。awkは1またはを出力し、これらはtrueまたは-のif句によって解釈されますfalse

if (( $(awk 'BEGIN {print ("'$d1'" >= "'$d2'")}') )); then
    echo "yes"
else 
    echo "no"
fi
10
ungalcrys

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

私はそのようなシェル/ 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
5
Elan Ruusamäe

もちろん、実際に浮動小数点演算が必要ない場合は、例えば、常に正確に2桁の10進数があるドル値の場合、ドットをドロップするだけで(事実上100倍)、結果の整数を比較できます。

if [[ $((10#${num1/.})) < $((10#${num2/.})) ]]; then
    ...

これには明らかに、両方の値の小数点以下の桁数が同じであることを確認する必要があります。

3
tripleee

ここからの回答を使用して関数に入れました。次のように使用できます。

is_first_floating_number_bigger 1.5 1.2
result="${__FUNCTION_RETURN}"

呼び出されると、echo $resultはこの場合は1になり、そうでない場合は0になります。

関数:

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}"
}

または、デバッグ出力付きのバージョン:

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}"
}

関数を別の.shファイルに保存し、次のように追加します。

. /path/to/the/new-file.sh
3
Thomas Kekeisen

このスクリプトは、インストールされている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
2
prayagupd

以下の編集されたコードを確認してください:-

#!/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

これはうまく機能します。

1
Gopika BG

Kornシェルを使用します。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
1
Alan Joseph

Bashj( https://sourceforge.net/projects/bashj/ )を使用して、Javaをサポートするbashミュータント、あなたはただ書く(そしてIS読みやすい):

#!/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

もちろん、bashj bash/Javaハイブリッド化は、さらに多くを提供します...

1
Fil

大文字と小文字の両方の指数を使用した科学表記法をサポートするソリューション(例:12.00e4):

if (( $(bc -l <<< "${value1/e/E} < ${value2/e/E}") ))
then
    echo "$value1 is less than $value2"
fi 
0
Danila Piatov

これはどう? = 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
0
Eduardo Lucio
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
0
rmil

私はこれを https://stackoverflow.com/a/56415379/1745001 への回答として投稿していましたが、この質問の重複として閉じられたので、ここにも適用されます:

シンプルでわかりやすいように、計算にはawkを使用してください。これは標準のUNIXツールであるため、bcと同じように存在し、構文的に操作するのがはるかに簡単です。

この質問について:

$ 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

そして、この質問の重複として閉じられた他の質問について:

$ 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...
0
Ed Morton

awkとそのようなツール(私はsedを凝視しています)は、古いプロジェクトのゴミ箱に追いやられるべきです。

または、CPU使用率の最適化をコードメンテナンスの最適化よりも優先する必要がある比較的まれなプロジェクトです。その場合は続けてください。

そうでない場合は、代わりにpythonなどの読み取り可能で明示的なものを使用しないのはなぜですか?あなたの仲間のコーダーと将来の自己はあなたに感謝します。他のすべてと同じように、bashでpythonをインラインで使用できます。

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
0
CivFan