Bir kabuk komut dosyasındaki iki kayan nokta sayısını karşılaştırmak istiyorum. Aşağıdaki kod çalışmıyor:
#!/bin/bash
min=12.45
val=10.35
if (( $val < $min )) ; then
min=$val
fi
echo $min
Bir kabuk komut dosyasındaki iki kayan nokta sayısını karşılaştırmak istiyorum. Aşağıdaki kod çalışmıyor:
#!/bin/bash
min=12.45
val=10.35
if (( $val < $min )) ; then
min=$val
fi
echo $min
Yanıtlar:
Tamsayılı ve kesirli kısımları ayrı ayrı kontrol edebilirsiniz:
#!/bin/bash
min=12.45
val=12.35
if (( ${val%%.*} < ${min%%.*} || ( ${val%%.*} == ${min%%.*} && ${val##*.} < ${min##*.} ) )) ; then
min=$val
fi
echo $min
Fered yorumlarda söylediği gibi, sadece her iki sayı da kesirli parçalara sahipse ve her iki kesimli parça aynı sayıdaki rakamlara sahipse çalışır. İşte tamsayı veya kesirli ve bash operatörü için çalışan bir sürüm:
#!/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
daha büyük olduğunu söylediğini unutmayın 2
.
Bash kayan nokta aritmetiğini anlamıyor. Ondalık nokta içeren sayıları, dizge olarak kabul eder.
Bunun yerine awk veya bc kullanın.
#!/bin/bash
min=12.45
val=10.35
if [ 1 -eq "$(echo "${val} < ${min}" | bc)" ]
then
min=${val}
fi
echo "$min"
Çok fazla matematik işlemi yapmak niyetindeyseniz, python veya perl'e güvenmek muhtemelen daha iyidir.
Basit manipülasyonlar için num-utils paketini kullanabilirsiniz ...
Daha ciddi matematik için, bu bağlantıya bakın ... Birkaç seçenek, örn.
Bir örnek 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.
İşte bir bash
kesmek ... Soldan sağa bir karşılaştırma anlamlı hale getirmek için tamsayıya lider 0 ekler. Bu kod, belirli parçası hem gerektirir dk ve val aslında bir ondalık noktası ve en az bir ondalık rakam var.
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
çıktı:
min=10.35
Kayan nokta sayıları ile ilgili basit hesaplamalar için (+ - * / ve karşılaştırmalar), awk kullanabilirsiniz.
min=$(echo 12.45 10.35 | awk '{if ($1 < $2) print $1; else print $2}')
Veya, ksh93 veya zsh (bash değil) varsa, kabuğunuzun kayan nokta sayılarını destekleyen yerleşik aritmetiğini kullanabilirsiniz.
if ((min>val)); then ((val=min)); fi
Daha gelişmiş kayan nokta hesaplamaları için, bc'ye bakınız . Aslında isteğe bağlı kesinti sayıları üzerinde çalışır.
Sayı tabloları üzerinde çalışmak için, R'ye ( örnek ) bakın.
Komut sort
bir seçenek vardır -g
( --general-numeric-sort
üzerinde karşılaştırmalar için kullanılabilir) <
"az" ya da, >
"daha büyük", minimum veya maksimum bularak.
Bu örnekler asgari buluyor:
$ printf '12.45\n10.35\n' | sort -g | head -1
10.35
E-Notasyonda olduğu gibi kayan nokta sayılarının oldukça genel gösterimi ile çalışır.
$ printf '12.45E-10\n10.35\n' | sort -g | head -1
12.45E-10
Not, E-10
ilk sayıyı yapan 0.000000001245
, aslında daha az 10.35
.
Kayan nokta standardı, IEEE754 , bazı özel değerleri tanımlar. Bu karşılaştırmalar için ilginç olanlar INF
sonsuzluk içindir. Negatif sonsuzluk da var; Her ikisi de standartta iyi tanımlanmış değerlerdir.
$ printf 'INF\n10.35\n' | sort -g | head -1
10.35
$ printf '-INF\n10.35\n' | sort -g | head -1
-INF
Bunun sort -gr
yerine maksimum kullanımı bulmak için sort -g
, sıralama düzenini tersine çevirerek:
$ printf '12.45\n10.35\n' | sort -gr | head -1
12.45
Uygulamak için <
onu kullanılabilir, böylece ( "az") karşılaştırma if
vb değerlerden birine minimum karşılaştırın. Asgari değere eşitse, metinle karşılaştırıldığında , diğer değerden azsa:
$ 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)
etmenin aynı olduğu görüşünü gerçekten beğendim a <= b
. Bunun olsa da kesinlikle daha azını kontrol etmediğini belirtmekte fayda var. Bunu yapmak istiyorsanız, için kontrol edilmesi gereken a == min(a, b) && a != max(a, b)
Başka bir deyişle,a <= b and not a >= b
Sadece ksh
( ksh93
kesin) veya zsh
doğal olarak kayan noktalı aritmetik özelliğini destekleyen kullanın:
$ cat test.ksh
#!/bin/ksh
min=12.45
val=10.35
if (( $val < $min )) ; then
min=$val
fi
echo "$min"
$ ./test.ksh
10.35
Düzenleme: Üzgünüm, kaçırdım ksh93
zaten önerildi. Cevabımı sadece açıklığa kavuşturmak için yazılan betiği açıklığa kavuşturmak için kabuk anahtarının dışında hiçbir değişiklik yapılmadan kullanılabilir.
Düzen2: ksh93
Değişken içeriğin yerel ayarınızla tutarlı olmasını gerektiren, yani bir Fransız yerel ayarıyla, nokta yerine virgül kullanılması gerektiğini unutmayın:
...
min=12,45
val=10,35
...
Kullanıcının yerel ayarından bağımsız olarak çalışacağından emin olmak için komut dosyasını başında yerel ayarı ayarlamak daha güçlü bir çözümdür:
...
export LC_ALL=C
min=12.45
val=10.35
...
.
(bu nedenle ondalık ayırıcının bulunduğu dünyanın yarısında değil ,
). zsh
Bu konuda bir sorun yok.
LC_ALL
, bu da kullanıcının tercih edilen biçimde sayıların gösterilmeyeceği (veya girileceği) anlamına gelmez. Potansiyel olarak daha iyi bir yaklaşım için unix.stackexchange.com/questions/87745/what-does-lc-all-c-do/… adresine bakın .
.
yine de olduğunu farz ediyorum .
min=$(echo "${min}sa ${val}d la <a p" | dc)
Kullandığı dc
için hesap s
değeri yırtıp $min
kayıttaki a
ve d
değerini uplicates $val
ana yürütme yığının üstüne. Daha sonra l
, içeriğini a
yığının üstüne, hangi noktada olduğu gibi gösterir:
${min} ${val} ${val}
<
Yığının kapalı üst iki giriş çıkar ve karşılaştırır. Böylece yığın şöyle görünür:
${val}
Üst giriş ikinci üstten küçükse içeriği üste doğru iter a
, böylece yığın şöyle görünür:
${min} ${val}
Başka hiçbir şey yapmaz ve yığın hala şöyle görünür:
${val}
Sonra sadece p
üst yığın girişini işaret eder.
Demek problemin için:
min=12.45
val=12.35
echo "${min}sa ${val}d la <a p" | dc
###OUTPUT
12.35
Fakat:
min=12.45
val=12.55
echo "${min}sa ${val}d la <a p" | dc
###OUTPUT
12.45
Neden eski, iyi kullanmıyorsun expr
?
Örnek sözdizimi:
if expr 1.09 '>' 1.1 1>/dev/null; then
echo 'not greater'
fi
İçin gerçek ifadeler, expr çıkış kodu Stdout'a gönderilen dize '1' ile, 0'dır. Yanlış ifadeler için ters .
Bunu GNU ve FreeBSD 8 expr ile kontrol ettim.
expr 1.09 '<' -1.1
basar 1
ve çıkar 0
(başarı ile).
İki (muhtemelen kesirli) sayının sıralı olup olmadığını kontrol etmek sort
için (makul şekilde) taşınabilir:
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
Ancak, asgari bir değeri güncel tutmak istiyorsanız, o zaman bir ihtiyacınız olmaz if
. Numaraları sıralayın ve daima ilk (en az) olanı kullanın:
min=12.45
val=12.55
smallest=$({ echo $min ; echo $val ; } | sort -n | head -n 1)
echo $smallest
min=$smallest
Genellikle ben gömülü python koduyla benzer şeyler yaparım:
#!/bin/sh
min=12.45
val=10.35
python - $min $val<<EOF
if ($min > $val):
print $min
else:
print $val
EOF
$ min=12.45
$ val=10.35
$ [ "$min" \< "$val" ] && echo $val || echo $min
$ 12.45
$ val=13
$ [ "$min" \< "$val" ] && echo $val || echo $min
$ 13
0.5
ve0.06
). Ondalık gösterimi zaten anlayan bir araç kullansanız iyi edersiniz.