Neden bash aritmetiğindeki bölünme çoğu yüzdeyi 0 olarak hesaplar?


15

Bir komut dosyası için bash aritemisi denenir, ancak $esonuna kadar güncellenmez. Çıktı kendisi için konuşur.

max=5
for e in $(seq 1 1 $max); do 
    percent=$(( $e/$max*100 ))
    echo "echo $e / $max : = $percent"
done

Tl; DR: Yüzde olarak 1..5 değerini görüntüler.

Çıktı :

echo 1 / 5 : = 0
echo 2 / 5 : = 0
echo 3 / 5 : = 0
echo 4 / 5 : = 0
echo 5 / 5 : = 100

Bu neden?


1
İlgili: Bash , hesaplama yaparken girdiden bağımsız olarak tamsayı çıktı olarak verir (Yine de, burada açıklanan sorunun aksine, işlemleri yeniden
sıralayarak

Yanıtlar:


24

bashtamsayı olmayan aritmetiği işleyemez. Tüm ifadeler tamsayı olduğu sürece size doğru sonucu verecektir. Bu nedenle, hesaplamanızda bir yerde tamsayı olmayan bir değer elde etmekten kaçınmanız gerekir.

Sizin durumunuzda, vb. Değerlendirirken 1 / 5, 2 / 5bazı tamsayı olmayan değerlere bash karşılık gelen tamsayı sıfır değerleri oluşturur ve sonuçlar buna göre sıfır olur. Öncelik bölünerek çoğalan onlar ifadesi yerleştirilir aynı ve aynı emsal operatörleri hep soldan sağa yürütülür vardır.

Etrafta bir çalışma ilk önce çarpma ve sonra bash asla tamsayı olmayan değeri işlemek zorunda değilsiniz. Düzeltilen ifade,

$ max=5; for e in $(seq 1 1 $max); do percent=$(( $e*100/$max )); echo "echo $e / $max : = $percent"; done
echo 1 / 5 : = 20
echo 2 / 5 : = 40
echo 3 / 5 : = 60
echo 4 / 5 : = 80
echo 5 / 5 : = 100

1
Alt ifade 1/5, tamsayı olmayan bir değer oluşturmaz . Tamsayı değeri oluşturur 0, çünkü 1'den 5'e tamsayı bölünmesinin sonucu 0'dır. Diğer işlemler bu değerini başarıyla kullanır 0. OP'nin amacı bu değildir, ancak hiçbir işlem tamsayı olmayan bir değer oluşturmaz ve hiçbir işlem başarısız olmaz.
Eliah Kagan

@EliahKagan kusuru işaret ettiğiniz için teşekkür ederim. Düzenlenen.
souravc

16

Bash bu tür aritmetikte pek başarılı değil ... İşte sorun:

$ echo $((1/5))
0
$ echo $((2/5))
0
$ echo $((4/5))
0
$ echo $((4/5))
0

Tamsayı olmayan değerleri işlemeniz gerekiyorsa, bc

$ max=5; for e in $(seq 1 1 "$max"); do percent=$(bc <<< "scale=1 ; $e/$max*100") ; echo "echo $e / $max : = ${percent%.*}"; done
echo 1 / 5 : = 20
echo 2 / 5 : = 40
echo 3 / 5 : = 60
echo 4 / 5 : = 80
echo 5 / 5 : = 100

(çıktının tamsayı olarak nasıl biçimlendirileceğini işaret eden @Arronical sayesinde)


Kesinlikle buna bir göz atacağım, bir kez daha teşekkürler!
Cybex

1
Sen kırpabilirsiniz .0değiştirerek çıkışından $percent için yankı içinde ${percent%.*}:)
Arronical

11

Bash'in aksine, awk tam kayan nokta aritmetiği sunar. Örneğin:

$ awk -v max=5 'BEGIN{for (e=1;e<=max;e++) print "echo " e " / " max " : = " 100*e/max}' 
echo 1 / 5 : = 20
echo 2 / 5 : = 40
echo 3 / 5 : = 60
echo 4 / 5 : = 80
echo 5 / 5 : = 100

5

Deneyin

percent=$(( $e*100/$max ))

:)

Bkz. Bölüm ARİTMETİK DEĞERLENDİRME:

man bash

Yalnızca tamsayıyı destekler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.