Warum berechnet die Division in Bash-Arithmetik die meisten Prozentsätze als 0?


15

Der Versuch, eine Bash-Arithmetik für ein Skript durchzuführen, wird jedoch $eerst am Ende aktualisiert. Die Ausgabe spricht für sich.

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

Tl; DR: Zeigt 1..5 als Prozentsatz an.

Ausgabe :

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

Warum ist das?


1
Verwandte Themen: Bash gibt bei der Ausführung von Berechnungen nur eine Ganzzahl als Ausgabe aus, unabhängig von der Eingabe. (Im Gegensatz zu dem hier beschriebenen Problem kann dies jedoch nicht durch eine Neuordnung der Operationen gelöst werden.)
Eliah Kagan,

Antworten:


24

bashkann keine Nicht-Ganzzahl-Arithmetik verarbeiten. Es gibt Ihnen das richtige Ergebnis, solange alle Ausdrücke Ganzzahlen sind. Sie müssen also vermeiden, dass Ihre Berechnung irgendwo einen nicht ganzzahligen Wert enthält.

In Ihrem Fall, wenn Sie auswerten 1 / 5, 2 / 5usw. schafft es die ganze Zahl Null - Werte in bash correspondings auf einige nicht-ganzzahlige Werte und die Ergebnisse kommen aus Null entsprechend zu sein. Der Vorrang von Division und Multiplikation ist derselbe und derselbe Vorrang von Operatoren wird immer von links nach rechts ausgeführt, wenn sie in den Ausdruck eingefügt werden.

Eine Möglichkeit besteht darin, zuerst die Multiplikation und dann die Division durchzuführen, damit bash nie mit nicht ganzzahligen Werten umgehen muss. Der korrigierte Ausdruck lautet:

$ 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
Der Unterausdruck erstellt 1/5keinen nicht ganzzahligen Wert. Es wird der ganzzahlige Wert erstellt 0, da das Ergebnis der ganzzahligen Division von 1 durch 5 0 ist. Weitere Operationen verwenden den Wert von erfolgreich 0. Dies ist nicht das, was das OP beabsichtigt hat, aber keine Operation erzeugt einen nicht ganzzahligen Wert und keine Operation schlägt fehl.
Eliah Kagan,

@EliahKagan, danke, dass du auf den Fehler hingewiesen hast. Bearbeitet
Souravc

16

Bash kann diese Art von Arithmetik nicht besonders gut ... Hier ist Ihr Problem:

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

Wenn Sie nicht ganzzahlige Werte verarbeiten müssen, können Sie verwenden 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

(Dank an @Arronical für den Hinweis, wie die Ausgabe als Ganzzahl formatiert wird)


Ich werde es mir auf jeden Fall noch einmal ansehen, danke!
Cybex

1
Sie können .0die Ausgabe abschneiden, indem Sie ändern$percent${percent%.*}
abschneiden,

11

Im Gegensatz zu bash bietet awk eine Fließkomma-Arithmetik. Beispielsweise:

$ 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

Versuchen

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

:)

Siehe Abschnitt ARITHMETISCHE BEWERTUNG von:

man bash

Es werden nur Ganzzahlen unterstützt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.