シェルスクリプトで2つの浮動小数点数を比較します。次のコードは機能していません。
#!/bin/bash
min=12.45
val=10.35
if (( $val < $min )) ; then
min=$val
fi
echo $min
シェルスクリプトで2つの浮動小数点数を比較します。次のコードは機能していません。
#!/bin/bash
min=12.45
val=10.35
if (( $val < $min )) ; then
min=$val
fi
echo $min
回答:
整数部と小数部を別々に確認できます。
#!/bin/bash
min=12.45
val=12.35
if (( ${val%%.*} < ${min%%.*} || ( ${val%%.*} == ${min%%.*} && ${val##*.} < ${min##*.} ) )) ; then
min=$val
fi
echo $min
feredがコメントで述べているように、両方の数値に小数部があり、両方の小数部に同じ桁数がある場合にのみ機能します。整数または分数と任意のbash演算子で機能するバージョンを次に示します。
#!/bin/bash
shopt -s extglob
fcomp() {
local oldIFS="$IFS" op=$2 x y digitx digity
IFS='.' x=( ${1##+([0]|[-]|[+])}) y=( ${3##+([0]|[-]|[+])}) IFS="$oldIFS"
while [[ "${x[1]}${y[1]}" =~ [^0] ]]; do
digitx=${x[1]:0:1} digity=${y[1]:0:1}
(( x[0] = x[0] * 10 + ${digitx:-0} , y[0] = y[0] * 10 + ${digity:-0} ))
x[1]=${x[1]:1} y[1]=${y[1]:1}
done
[[ ${1:0:1} == '-' ]] && (( x[0] *= -1 ))
[[ ${3:0:1} == '-' ]] && (( y[0] *= -1 ))
(( ${x:-0} $op ${y:-0} ))
}
for op in '==' '!=' '>' '<' '<=' '>='; do
fcomp $1 $op $2 && echo "$1 $op $2"
done
1.00000000000000000000000001
はより大きいと言うことに注意してください2
。
Bashは浮動小数点演算を理解しません。小数点を含む数値を文字列として扱います。
代わりにawkまたはbcを使用してください。
#!/bin/bash
min=12.45
val=10.35
if [ 1 -eq "$(echo "${val} < ${min}" | bc)" ]
then
min=${val}
fi
echo "$min"
多くの数学演算を行うつもりであれば、おそらくpythonまたはperlに依存する方が良いでしょう。
あなたは 簡単な操作のためにパッケージnum-utilsを使用することができます...
より深刻な数学については、このリンクを...それは、例えば、いくつかのオプションについて説明します。
の例 numprocess
echo "123.456" | numprocess /+33.267,%2.33777/
# 67.0395291239087
A programs for dealing with numbers from the command line
The 'num-utils' are a set of programs for dealing with numbers from the
Unix command line. Much like the other Unix command line utilities like
grep, awk, sort, cut, etc. these utilities work on data from both
standard in and data from files.
Includes these programs:
* numaverage: A program for calculating the average of numbers.
* numbound: Finds the boundary numbers (min and max) of input.
* numinterval: Shows the numeric intervals between each number in a sequence.
* numnormalize: Normalizes a set of numbers between 0 and 1 by default.
* numgrep: Like normal grep, but for sets of numbers.
* numprocess: Do mathematical operations on numbers.
* numsum: Add up all the numbers.
* numrandom: Generate a random number from a given expression.
* numrange: Generate a set of numbers in a range expression.
* numround: Round each number according to its value.
ここにbash
ハックがあります...文字列の左から右への比較を意味のあるものにするために、先頭に0を整数に追加します。この特定のコードでは、minとvalの両方 に実際に小数点と少なくとも1つの10進数が必要です。
min=12.45
val=10.35
MIN=0; VAL=1 # named array indexes, for clarity
IFS=.; tmp=($min $val); unset IFS
tmp=($(printf -- "%09d.%s\n" ${tmp[@]}))
[[ ${tmp[VAL]} < ${tmp[MIN]} ]] && min=$val
echo min=$min
出力:
min=10.35
浮動小数点数の単純な計算(+-* /および比較)には、awkを使用できます。
min=$(echo 12.45 10.35 | awk '{if ($1 < $2) print $1; else print $2}')
または、ksh93またはzsh(bashではない)を使用している場合は、浮動小数点数をサポートするシェルの組み込みの算術演算を使用できます。
if ((min>val)); then ((val=min)); fi
より高度な浮動小数点計算については、bcを参照してください。実際には、任意精度の固定小数点数で機能します。
このコマンドsort
にはオプション-g
(--general-numeric-sort
)があり、最小値または最大値を見つけることで<
、「より小さい」または>
「より大きい」の比較に使用できます。
これらの例は最小値を見つけています:
$ printf '12.45\n10.35\n' | sort -g | head -1
10.35
E表記法のように、浮動小数点数のかなり一般的な表記法で動作します
$ printf '12.45E-10\n10.35\n' | sort -g | head -1
12.45E-10
E-10
最初の数字を作って0.000000001245
、本当により少ないことに注意してください10.35
。
浮動小数点標準IEEE754は、いくつかの特別な値を定義しています。これらの比較では、興味深いのはINF
無限大です。負の無限大もあります。両方とも、標準では明確に定義された値です。
$ printf 'INF\n10.35\n' | sort -g | head -1
10.35
$ printf '-INF\n10.35\n' | sort -g | head -1
-INF
のsort -gr
代わりに最大使用量を見つけるにはsort -g
、ソート順を逆にします。
$ printf '12.45\n10.35\n' | sort -gr | head -1
12.45
<
(「より小さい」)比較を実装して、if
などで使用できるようにするには、最小値をいずれかの値と比較します。最小値がtextと比較した値と等しい場合、他の値よりも小さくなります。
$ a=12.45; b=10.35
$ [ "$a" = "$(printf "$a\n$b\n" | sort -g | head -1)" ]
$ echo $?
1
$ a=12.45; b=100.35
$ [ "$a" = "$(printf "$a\n$b\n" | sort -g | head -1)" ]
$ echo $?
0
a == min(a, b)
はと同じであるというあなたの洞察が本当に好きa <= b
です。ただし、これは厳密に以下をチェックしないことに注意してください。それを行うには、a == min(a, b) && a != max(a, b)
他の言葉でa <= b and not a >= b
ksh
(ksh93
正確に)またはを使用するだけでzsh
、どちらもネイティブに浮動小数点演算をサポートします。
$ cat test.ksh
#!/bin/ksh
min=12.45
val=10.35
if (( $val < $min )) ; then
min=$val
fi
echo "$min"
$ ./test.ksh
10.35
編集:申し訳ありませんが、私ksh93
はすでに提案されていなかった。冒頭の質問に投稿されたスクリプトを明確にするためだけに私の答えを保持することは、シェルスイッチの外部で変更なしで使用できます。
Edit2:ksh93
変数の内容がロケールと一貫している必要があることに注意してください。つまり、フランス語ロケールでは、ドットの代わりにコンマを使用する必要があります。
...
min=12,45
val=10,35
...
より堅牢なソリューションは、スクリプトの先頭にロケールを設定して、ユーザーのロケールに関係なく動作することを確認することです。
...
export LC_ALL=C
min=12.45
val=10.35
...
.
(したがって、小数点記号が半分の世界では機能しません,
)。zsh
その問題はありません。
LC_ALL
。これは、ユーザーの好みの形式で数値が表示(または入力)されないことも意味します。より良いアプローチの可能性については、unix.stackexchange.com / questions / 87745 / what-does-lc-all-c-do /…を参照してください。
.
とにかく推測します。
min=$(echo "${min}sa ${val}d la <a p" | dc)
すなわち、使用dc
する計算をs
するための値を引き裂いた$min
レジスタ内a
とd
の値をuplicates $val
主実行スタックの上部に。次にl
、コンテンツをa
スタックの最上部にリストします。この時点で、次のようになります。
${min} ${val} ${val}
<
スタックから一番上の2つのエントリをポップし、それらを比較します。したがって、スタックは次のようになります。
${val}
上のエントリが上から2番目のエントリよりも小さかった場合、その内容はa
上にプッシュされるため、スタックは次のようになります。
${min} ${val}
それ以外は何もせず、スタックはまだ次のようになります。
${val}
次にp
、一番上のスタックエントリをリントします。
だからあなたの問題のために:
min=12.45
val=12.35
echo "${min}sa ${val}d la <a p" | dc
###OUTPUT
12.35
しかし:
min=12.45
val=12.55
echo "${min}sa ${val}d la <a p" | dc
###OUTPUT
12.45
古くて良いものを使わないのはなぜexpr
ですか?
構文例:
if expr 1.09 '>' 1.1 1>/dev/null; then
echo 'not greater'
fi
以下のために真の式、exprの終了コードは標準出力に送られた文字列「1」で、0です。偽式の場合は逆になります。
これをGNUおよびFreeBSD 8 exprで確認しました。
expr 1.09 '<' -1.1
印刷1
して0
(成功)で終了します。
2つの(おそらく小数の)数値が順番に並んでいるかどうかを確認するにsort
は、(合理的に)移植可能です。
min=12.45
val=12.55
if { echo $min ; echo $val ; } | sort -n -c 2>/dev/null
then
echo min is smallest
else
echo val is smallest
fi
ただし、実際に最小値を更新したい場合は、を必要としませんif
。番号を並べ替え、常に最初の(最も少ない)番号を使用します。
min=12.45
val=12.55
smallest=$({ echo $min ; echo $val ; } | sort -n | head -n 1)
echo $smallest
min=$smallest
通常、私は埋め込まれたPythonコードで同様のことをします:
#!/bin/sh
min=12.45
val=10.35
python - $min $val<<EOF
if ($min > $val):
print $min
else:
print $val
EOF
0.5
とを試してください0.06
)。すでに10進表記を理解しているツールを使用することをお勧めします。