Fakultätsschleife

D

donsimon1991

Ich hab in der SuFu nur einen Thread über Fakultät gefunden, aber der hat mir nicht weitergeholfen.

Was ich schon geschafft habe:
  • die Fakultät von EINER Zahl berechnen
  • Fehlermeldungen ausgeben, wenn Null oder mehr als zwei Argumente übergeben wurden

Was ich noch schaffen möchte:
  • eine Schleife erstellen, um die Fakultäten von $1 bis $2 zu berechnen und auszugeben

So, und jetzt das Shell-Script (Bash):
PHP:
#!/bin/bash
# Variablen initialisieren

declare -i zahl1=$1
declare -i zahl2=$2
declare -i fakultaet1=1
declare -i fakultaet2=1

# Wenn $1<$2, dann von=$1 und bis=$2
if [ $zahl1 -lt $zahl2 ]; then
	declare -i von=$zahl1
	declare -i bis=$zahl2
# Wenn $1<$2, dann von=$2 und bis=$1
elif [ $zahl1 -gt $zahl2 ]; then
	declare -i von=$zahl2
	declare -i bis=$zahl1
fi

# Ueberpruefen, wie viele Argumente uebergeben wurden
case $# in
	0)
		# Es gibt KEIN Argument ==> Fehlermeldung ausgeben
		echo "Bitte uebergeben Sie als Argumente EINE oder ZWEI Zahlen.";;
	1)
		# Es gibt EIN Argument ==> Fakultaet von $1 berechnen und ausgeben
		while [ $zahl1 -gt 1 ]; do
			fakultaet1=$fakultaet1*$zahl1
			zahl1=$zahl1-1
		done
		echo "Fakultaet von" $1 "=" $fakultaet1;;
	2)
		# Es gibt ZWEI Argumente ==> Schleife mit allen Fakultaeten von $1 bis $2 berechnen und ausgeben
		while [ $von -le $bis ]; do
			while [ $von -gt 1 ]; do
				fakultaet2=$fakultaet2*$von
				von=$von-1
			done
			echo $fakultaet2
			von=$von+1
		done;;
	*)
		echo "Sie duerfen nur eine oder zwei Zahlen als Parameter eingeben!";;
esac

Der entscheidende Teil ist also in dem "case-Block", wo die 2 steht. Ich hab den Code einfach PHP-Code eingebunden, ist doch ein befriedigendes Syntaxhighlighting. Darf ich das? :)
 
Zuletzt bearbeitet von einem Moderator:
Bist Du sicher, daß das Rechnen funktioniert? Schau mal:
Code:
$ var=3+4; echo $var
3+4
$ ((var=3+4)); echo $var
7
 
Code:
"Bitte uebergeben Sie als Argumente 2 oder 3 Zahlen.";; 
...
echo "Sie duerfen nur eine oder zwei Zahlen als Parameter eingeben!";;

ja was denn nun? :think:

und die fakultät ist doch durch
n!:= n*(n-1)*...*1 definiert, mit 1!:=1 0!:=1

also wieso brauchst du mehr als eine zahl?

das was du brechnen willst ist prod(i=a b)(i), wobei a die untere grenze und b die obere grenze und a, b aus N sind. das ist aber nicht die definition von fakultät.

bist du also sicher das du das richtig machst, was du da machst?

gruß tuxlover
 
ich meine natürlich eine oder zwei Zahlen!

die Fakultät an sich zu berechnen, kann ich ja schon. Da gebe ich dann zum Beispiel ./fakultaet 5 ein und dann wird Fakultaet = 120 ausgegeben. Wenn ich aber ./fakultaet 1 5 eingebe, dann soll folgendes bei rauskommen:
Code:
1
2
6
24
120
Also die Fakultäten von 1 bis 5. Was ich noch ändern muss ist der Teil bei der case-Abfrage, wo die 2 steht.
 
ich meine natürlich eine oder zwei Zahlen!

Also die Fakultäten von 1 bis 5. Was ich noch ändern muss ist der Teil bei der case-Abfrage, wo die 2 steht.

dann brauchst du ja nur eine schleife über deine fakultätsberechnung legen:

Pseudocode:
Code:
for i=anfangswert : endwert
    fakultätsberechnung(i)
 
Habs jetzt nochmal probiert, jetzt sieht der Code so aus:
PHP:
#!/bin/bash
# Variablen initialisieren

declare -i zahl1=$1
declare -i zahl2=$2
declare -i fakultaet1=1
declare -i fakultaet2=1

# Wenn $1<$2, dann von=$1 und bis=$2
if [ $zahl1 -lt $zahl2 ]; then
	declare -i von=$zahl1
	declare -i bis=$zahl2
# Wenn $1<$2, dann von=$2 und bis=$1
elif [ $zahl1 -gt $zahl2 ]; then
	declare -i von=$zahl2
	declare -i bis=$zahl1
fi

# Variable fuer die Schleife
declare -i count=$von

# Ueberpruefen, wie viele Argumente uebergeben wurden
case $# in
	0)
		# Es gibt KEIN Argument ==> Fehlermeldung ausgeben
		echo "Sie duerfen nur eine oder zwei Zahlen als Parameter eingeben!";;
	1)
		# Es gibt EIN Argument ==> Fakultaet von $1 berechnen und ausgeben
		while [ $zahl1 -gt 1 ]; do
			fakultaet1=$fakultaet1*$zahl1
			zahl1=$zahl1-1
		done
		echo "Fakultaet von" $1 "=" $fakultaet1;;
	2)
		# Es gibt ZWEI Argumente ==> Schleife mit allen Fakultaeten von $1 bis $2 berechnen und ausgeben
		while [ $count -le $bis ]; do
			while [ $von -gt 1 ]; do
				fakultaet2=$fakultaet2*$von
				von=$von-1
			done
			echo $fakultaet2
			count=$count+1
		done;;
	*)
		echo "Sie duerfen nur eine oder zwei Zahlen als Parameter eingeben!";;
esac

Und wenn ich dann
Code:
./fakultaet 5 8

eingebe, kommt das dabei raus:
Code:
120
120
120
120

Also die Fakultät von 5 und das ganze dann vier mal. Hm, 5, 6, 7 und 8 sind genau vier Zahlen, hat es damit was zu tun?

PS: Ich hasse logische Fehler! X(
 
Code:
   2) 
        until [ $bis -eq $von ]; do 
            fac=$(($fac*$bis))
             ((bis-=1))
         done

so müsste es gehen. viel spaß noch
 
Zuletzt bearbeitet:
Ich hab das jetzt so übernommen wie du geschrieben hast. Wenn ich da
Code:
./fakultaet 1 5
eingebe, dann wird eine Endlosschleife mit 120 ausgegeben. Wo ist diesmal der Fehler?
 
Hallo

Ich mag dein Script nicht debuggen.
Aber ein paar Hinweise zum Verständnis:
Ganzzahlige Rechenoperationen in der bash werden mit dem Buildin $(( OPERATIO)) ausgeführt.
Expire sollte nicht mehr verwendet werden, da es ein externer Prozess ist.
Dazu habe ich aber an anderer Stelle schon etwas gesagt.

Increment:
Code:
a=0;
while [ $a -lt 10 ]; do echo $a; ((a++));done
Decrement:
Code:
a=10;
while [ $a -gt 0 ]; do echo $a; ((a--));done

Mit Zuweisung:
Code:
a=10;b=0;
while [ $a -gt 0 ]; do b=$((a--));echo $b;done

Sowas funktioniert nicht wie du erwartest:
Code:
$ a=10;b=$a + 1; echo $b;
bash: +: command not found
0
Das hier auch nicht:
Code:
$ a=10;a=$((-=1)); echo $a;
bash: -=1: syntax error: operand expected (error token is "-=1")

Müsstest du aber eigentlich gemerkt haben.

Noch ein Tipp:
Strukturier deinen Code so, dass du die gleiche Funtion nur einmal erstellst.
Frage dann ab wie oft und womit sie verwendet werden soll.

Die Abfrage wieviel Argumente sollte am Beginn stehen.
Wenn nur ein Arg. da ist, ist die folgende Zuweisung schon sinnlos.
Code:
declare -i zahl2=$2

Dann fehlt dir eine Auswertung bei Gleichheit der Argumente.

Das nur so als Tipp.

Ach ja falls du nach diesem Tut vorgehst:
Klick
Das hat genau an diesen Stellen in der Bash (bis Ver 3.xx) einen Fehler!

Gruß Wolfgang
 
Code:
#!/bin/bash

declare -i von=$1
declare -i bis=$2

if [ $bis -lt $von ]
then
      unset bis
      declare -i bis=$1
      unset von
      declare -i von=$2
fi

until [ $bis -eq $von ]
do
        fac=$(($fac*$bis))
        ((bis-=1))
done
echo $fac

exit 0

probiere das mal in nem neuen shellscript aus, und berichte mal ob das funktioniert hat.

ach ja hier bietet sich an mit funktionen zu arbeiten.

oops wie peinlich hatte auch nen fehler drin
 
Zuletzt bearbeitet:
Da bekomme ich folgende Fehlermeldung:
Code:
line 16: *7: syntax error: operand expected (error token is "*7")

Wie du wahrscheinlich schon gesehen hast, rechne ich in der shell ein bisschen anders. Gibt ja mehrere Möglichkeiten. Deswegen kann ich den Fehler nicht finden.

:hilfe2:
 
keine ahnung muss jetzt los.

nee warte mal setze mal vorher fac=1, dann müsste es gehen. ich probiere das später mal aus und sag dir dann meine lösung.

allerdings ist shellscripting nicht gerade die beste methode um mathematische probleme zu lösen. wenn du das weiter machen willst solltest du auf C umsteigen.

Code:
#!/bin/bash

declare -i von=$1
declare -i bis=$2

if [ $bis -lt $von ]
then
      unset bis
      declare -i bis=$1
      unset von
      declare -i von=$2
fi

fac=1

until [ $bis -eq $von ]
do
        
        fac=$(($fac*$bis))
        ((bis-=1)) 
done
echo $fac

exit 0

du kannst ma deine shellscripte mit

Code:
sh -x ./name

starten. dann siehst du nämlich was da los ist.
 
Das ist schön, dass du das kannst, aber du hast keine frage gestellt, ich das ist eher unüblich, da du ja gar keine reaktion herausrufst.

Btw Wenn $1 und $2 gleich sind, was würde dein script machen?
 
Huch ich hab den thread länger offen gehabt und so auf den ersten blick hat das script ganz passabel ausgesehen, deswegen bin ich von einer art "hey schau mal was ich tolles kann" thread ausgegangen

sry
 
Code:
#!/bin/bash

declare -i von=$1
declare -i bis=$2

if [ $bis -lt $von ]
then
   #  [b]  unset bis
    #  declare -i bis=$1
    # unset von
    #  declare -i von=$2[/b] unnötig
    von=$2
    bis=$1
fi

fac=1

until [ $bis -eq $von ]
do
        
        fac=$(($fac*$bis))
  #      ((bis-=1))  #Fehler
   ((bis--));
done
echo $fac

exit 0

du kannst ma deine shellscripte mit

Code:
sh -x ./name

starten. dann siehst du nämlich was da los ist.

Für Fakultät reicht es, aber Syntax muss man in allen Sprachen beherrschen.
Aber dein Beispiel berechnet nicht Fakultät, sondern multipliziert nur bis zum 2. Argument.
 
Zuletzt bearbeitet:
hallo wolfgang,

ja das habe ich auch schon bemerkt. ich würde sowieso eher ne rekursive funktion dafür benutzen, weiß aber nicht ob das in bash geht.

wo der unterschied zwischen ((bis--)) und ((bis-=1)) ist mir unklar. denn in meinem shellscripten benutze ich auch immer diese version und da funktionert es. naja versuche das halt mal.

danke

grüße tuxlover
 
Code:
#!/bin/bash

faku_rec()
{
    local i=$1
    if [ $i -eq 0 ]; then
        fakul=1
    else
        i_minus_one=$((i - 1))
        faku_rec $i_minus_one
        fakul=$((i * $?))
    fi
    return $fakul
}

faku_rec $1

echo $fakul

das ist aber hart unelegant (und hab ich auch nicht selber geschrieben sondern ergooglet. das einzige was mir klar war, war das ich irgendwie 'local' benutzen musste. dass das ganze aber so gestelzt enden würde hätte ich nicht gedacht). bash und rekursive funktionen sind irgendwie unwitzig. und wie man das nicht-rekursiv in eine funktion verpacken kann sollte der threadersteller alleine hinkriegen.
syntax ist immer dieselbe:
Code:
name_der_funktion()
{
    #eigentlicher code
}
die funktion wird dann wie ein shellskript aufgerufen und man kann auf die argumente ebenfalls wie beim shellskript einfach per $1, $2.... $n zugreifen.
 
hallo wolfgang,

ja das habe ich auch schon bemerkt. ich würde sowieso eher ne rekursive funktion dafür benutzen, weiß aber nicht ob das in bash geht.

wo der unterschied zwischen ((bis--)) und ((bis-=1)) ist mir unklar. denn in meinem shellscripten benutze ich auch immer diese version und da funktionert es. naja versuche das halt mal.

danke

grüße tuxlover

Dann nutzt du nicht die bash!
Gut, die verwendete Shell wurde auch hier nicht angegeben, ist aber aus der Shebang ersichtlich.
Eine simple Fakultätfunktion wäre:
Code:
function fak() {
        if [ $1 -eq 1 ];
        then echo 1;
        else 
        echo $(($1 * $(fak $(($1 - 1)))))
        fi
    }
Näheres zu Funktionen
Die nun über alle Zahlen zwischen von bis aufgerufen, löst das Problem.

Gruß Wolfgang
 
Danke Wolfgang! Jetzt funktioniert es!

Wahrscheinlich bin ich nicht darauf gekommen, weil ich erstens noch nie mit Funktionen in der Bash gearbeitet hab und zweitens ungern mit so vielen Klammern wie in Zeile 24 rechne :D

Zum besseren Verständnis hier nochmal das komplette Skript:

PHP:
#!/bin/bash
# Variablen initialisieren

declare -i zahl1=$1
declare -i zahl2=$2
declare -i fakultaet1=1
declare -i fakultaet2=1

# Wenn $1<$2, dann von=$1 und bis=$2
if [ $zahl1 -lt $zahl2 ]; then
	declare -i von=$zahl1
	declare -i bis=$zahl2
# Wenn $1<$2, dann von=$2 und bis=$1
elif [ $zahl1 -gt $zahl2 ]; then
	declare -i von=$zahl2
	declare -i bis=$zahl1
fi

# Funktion fuer Fakultaet definieren:
function fak() {
	if [ $1 -eq 1 ]; then
		echo 1;
	else
		echo $(($1 * $(fak $(($1 - 1)))))
	fi
}

# Ueberpruefen, wie viele Argumente uebergeben wurden
case $# in
	0)
		# Es gibt KEIN Argument ==> Fehlermeldung ausgeben
		echo "Sie duerfen nur eine oder zwei Zahlen als Parameter eingeben!";;
	1)
		# Es gibt EIN Argument ==> Fakultaet von $1 berechnen und ausgeben
		while [ $zahl1 -gt 1 ]; do
			fakultaet1=$fakultaet1*$zahl1
			zahl1=$zahl1-1
		done
		echo "Fakultaet von" $1 "=" $fakultaet1;;
	2)
		# Es gibt ZWEI Argumente ==> Schleife mit allen Fakultaeten von $1 bis $2 berechnen und ausgeben
		while [ $von -le $bis ]; do
			fak $von
			von=$von+1
		done;;
	*)
		echo "Sie duerfen nur eine oder zwei Zahlen als Parameter eingeben!";;
esac
 

Ähnliche Themen

Switche abfragen über Script

Skript soll nicht doppelt laufen... kill pkill pid cron

script sshpass

Verschlüsseltes Backup-Script mit rsync

Grafische Anzeige der Temperatur

Zurück
Oben