# Programmieren mit Perl unter Ubuntu



## _-=Dante=-_ (17. Oktober 2011)

Moin die Herrschaften

Wir müssen zu morgen eine, für einigermaßen Kenner leichte, aber für mich eher schwierige Aufgabe mit Perl programmieren.
Bevor ich genauer schildere um was es geht, würde sich jemand bereiterklären mir dabei zu helfen???
Es sei nur so viel gesagt, es geht um das Wurzelziehen...
Wäre echt hammer

Gruß
Flori


----------



## _-=Dante=-_ (22. Oktober 2011)

Hat denn niemand einen Plan davon (nicht vom Wurzelziehen, sondern allgemein von Perl) ???
Es kann doch nicht sein, dass es hier nur Spielenerds gibt 

Gruß Flori


----------



## Dragonix (22. Oktober 2011)

Vielleicht würde sich die Hilfsbereitschaft auch steigern, wenn du einfach mal zeigst, was du schon hast..


----------



## _-=Dante=-_ (22. Oktober 2011)

Ich habe das Problem mit dem Wurzelziehen, wie folgt gelöst:

#!/usr/bin/perl
use strict;
use warnings;
my $a= 0;
my $nk= 0;

print ("Geben Sie eine Zahl ein: ");
$a=<>; 
chomp ($a); 
print ("Wie viele Nachkommastellen soll das Ergebnis haben?");
$nk=<>; 
chomp ($nk);

my $x= $a;
my $pre= 0;


until ($a==$x*$x or $pre==$x)   
       {
       $pre=$x;
       $x=($x+($a/$x))/2;
       }
printf 
("%.".$nk."f\n", $x); 


Momentan versuche ich, dass er mir die Fibonacci Zahl berechnet, das Programm läuft aber nur halb durch (bis zur Eingabe einer Zahl) danach muss irgendwo ein Fehler sein...momentan suche ich noch^^
Aber hier auch mein bisheriger Quelltext:

#!/usr/bin/perl 
use strict; 
use warnings;
my $n=0;

print "Berechnen Sie die n-te Fibonacci-Zahl. Geben Sie n ein\n ";

chomp ($n=<STDIN>);

print "Die $n-Fibonacci-Zahl ist".fibonacci($n).".\n";


sub fibonacci 
              {
my $n=$_[0];   
if ($n<=2)
              {
return $n;  
              }
else
              {
Fibonacci ($n-1) + Fibonacci ($n-2);
              }
print Fibonacci ($n-1) + Fibonacci ($n-2);
              }


Gruß Flori


----------



## Dragonix (22. Oktober 2011)

Also, abgesehen davon dass dein Algorithmus bzgl n<=2 m.e. falsch ist (0. Fibzahl ist 0, 1. ist 1, 2. ist 1) und dieser Fehler sich somit durch's ganze Programm zieht, beachte folgende Dinge:
Perl ist case sensitiv (zumindest standardmäßig; hat er dir aber beim Ausführen gesagt, dass er "Fibonacci" nicht findet).

```
else
 {
 Fibonacci ($n-1) + Fibonacci ($n-2);
 }
 print Fibonacci ($n-1) + Fibonacci ($n-2);
 }
```
Passt nicht, wenn n nicht <=2 ist addierst du einfach die beiden vorangehenden Fib Zahlen (korrektes vorgehen!), speicherst das Ergebnis aber nirgendwo. Und dann, gleich danach, berechnest du nochmal das gleiche, lässt das ergebnis aber AUSGEBEN. Du willst das Ergebnis aber zurückgeben!
Denk mal drüber nach und meld dich nochmal!

Vielleicht sollt ich auch noch anmerken, dass ich kein Perl kann. Hab das Programm also primär auf den verwendeten Algorithmus untersucht. Allerdings hab ich's mit oben genannten Änderungen zum laufen gebracht


----------



## _-=Dante=-_ (22. Oktober 2011)

Genauso habe ich mir das vorgestellt, jemand der mir Tipps gibt, konstruktive Kritik übt, aber mir nicht gleich sagt, wie es richtig lauten muss.
Klar, dann speichere ich das Ergebis vorher nicht, sondern lasse es mir gleich ausgeben, das sollte doch dann funktionieren oder?
Also:

else 
{
print Fibonacci ($n-1) + Fibonacci ($n-2);
}

Das Problem mit Werten, die kleiner als zwei sind, könnte ich lösen, in dem ich sage, dass er bei Eingabe einer Null, eine Null ausgeben soll und bei Eingabe einer Eins eine Eins ausgeben soll und bei Eingabe einer Zwei eine Eins ausgeben soll oder?
Das wäre wohl ziemlich umständlich, was bedeutet, dass es viel Quelltext wäre, aber mir fehlt einfach das Wissen, die Erfahrung und das Verständnis, um das schneller, effizienter und versierter zu schreiben.

Also ich habs jetzt, nur noch ein ganz kleiner Fehler^^ aber ich glaube, das ist jetzt nicht mehr rekursiv...

Gruß Flori


----------



## Dragonix (22. Oktober 2011)

Ich denke ihr behandelt gerade das Thema Rekursion? Aufjedenfall schreibst du gerade ein rekursives Programm. Das funktioniert so: Du nimmst ein großes Problem (Berechnung der 5. Fibonacci Zahl) und führst das "große" Problem auf "kleinere" (Berechnung der 4. und 3. Fib. Zahl) zurück. Das geht solange (rekursiv, d.h. das Programm/die Funktion ruft sich selber wieder auf), bis der sog. Basisfall eintritt. Dann findet kein rekursiver Aufruf mehr statt (d.h. bei uns im Fall n=0 und n=1).
Wir berechnen mal die 5. Fib Zahl. Das würde dann so ausschauen: Fibonacci(5) = Fibonacci(4) + Fibonacci(3) = Fibonacci(3) + Fibonacci(2) + Fibonacci(2) + Fibonacci(1) etc.
Damit das aber klappt, darfst du die "auf dem Weg berechneten" Fibonacci zahlen nicht ausgeben (du kannst natürlich, der Sinn sei aber mal dahingestellt), sondern musst sie an die "aufrufende" Funktion zurückgeben. In Code:

```
*beliebige Variable* = Fibonacci($n-1) + Fibonacci($n-2);
return *beliebige Variable*;
```
oder einfach nur

```
return Fib($n-1) + Fib($n-2);
```
Damit es hier aber überhaupt was zu berechnen gibt, muss "Fibonacci($n-1)" (bzw $n-2) etwas zurückgeben, weil sonst weiß die Funktion ja nicht, was sie addieren soll. Das ist wichtig, sollte dir also definitv klar sein! Frag im Zweifel lieber nochmal nach.
Wie gibt eine Funktion nun etwas zurück? Im (falschen!) Fall "$n <= 2" hast du das ja schon richtig gemacht, nämlich mit "return". "print" ist etwas ganz was anderes, damit gibst du nur etwas auf dem Bildschirm aus, aber du gibst keinen Wert zurück! Die "aufrufende" Funktion weiß dann garnicht, was sie berechnen soll.

Und nochmal zu dem "else" Teil: Den kannst du dir sparen! Bzw. alternativ kannst du dir auch das was danach kommt sparen (was, wenn im "else" Teil ein return stehen würde, eh niemals ausgeführt werden würde. Denk da mal drüber nach!).
Das macht dein Programm zur Zeit in Pseudocode formuliert:
Falls n<=2: Gebe n zurück UND BEENDE HIER. Code der in dieser Funktion danach kommt, wird nicht mehr angeschaut.
Ansonsten: Berechne Fib(n-1) und Fib(n-2) und schmeiß das Ergebnis in den Müll.
"Danach" (wird nur ausgeführt, wenn n>2, s.o.): Berechne Fib(n-1) und Fib(n-2) und GEB DAS ERGEBNIS AUS! Du müsstest es aber ZURÜCK geben!

Hoffe das hilft dir!

Zu deiner if-Abfrage: Wenn n = 0 ist musst du 0 zurückgeben, wenn n=1 ist musst du 1 zurückgeben. Alles andere kannst du berechnen. Realisieren kannst du das, wie du schon richtig erkannt hast, mit if Abfragen.

Und noch ein kleiner Tipp: Über Effizienz mach dir mal keine Gedanken. Gerade wenn du noch lernst achte lieber auf ordentlichen und hübschen Code (Kommentare! Früh übt sich!) der einfach nur das macht, was er soll.

Viel Erfolg!
Matthias


----------



## _-=Dante=-_ (22. Oktober 2011)

Ich bin zu blöd dafür...ein Variable namens x, dann ergebe sich:
n sei 5.
x= Fib(5-1) + Fib(5-2)
x=7

7 sind alle Zahlen der Fib-Folge bis einschließlich der 4. Stelle addiert.
Was soll ich jetzt mit der 7 machen?
Warum soll ich sie zurückgeben?
7 ist nicht die 5. Stelle der Fib Folge somit wäre das Ergebnis ausgegeben falsch.

Gruß Flori


----------



## Dragonix (22. Oktober 2011)

Quatsch, dafür is keiner zu blöd, das kriegen wir schon hin  Mit Rekursion tuen sich viele anfangs schwer!

Die 7 ist, wie du bereits vollkommen richtig erkannt hast, falsch. Allerdings ist mir grad auch nicht klar, wie dein Programm darauf komt.
Das rekursive Berechnen der Fibonacci Zahlen ist dir klar geworden/war dir schon immer klar?!


Kannst du nochmal den aktuellen Code zeigen und eventuelle Unklarheiten beschreiben?


----------



## _-=Dante=-_ (22. Oktober 2011)

Das Problem ist, dass ich sowas noch nie hatte und unsere Dozenten der Meinung sind, man müsse sich das mit viel Eifer aneignen, aber ich denke, dass Programmieren viel mehr verstehen ist, als irgendwas auswendig lernen.
Ich geb mir echt Mühe, male nen Flowchart auf, schreibe nen Pseudocode und versuche zu verstehen, worum es geht. Die Dozenten dürfen wir nur fragen, wenn wir vorher google benutzt haben.
Außerdem müssen wir noch ein Programm, ebenfalls rekursiv, zur Primfaktorzerlegung schreiben...das kostet viel Zeit, wenn man noch nie programmiert hat. Du bräuchtest vielleicht eine halbe Stunde dafür, ich aber 20h z.B. .

*beliebige Variable* = Fibonacci($n-1) + Fibonacci($n-2);
return *beliebige Variable*;

Ich habe darauf Bezug genommen und habe das einfach mathematisch durchgerechnet, ohne Programm, in dem ich x als Variable bestimmt habe und dann gesagt habe, dass n=5 sei...$n=die Zahl, die ich eingebe.
Das ist mir klar geworden ich habe das nochmal an meiner Tafel veranschaulicht. Fib(5)= 3+2=2+1+1+1 und die Fib Zahl von 5 ist ja 5.
Wenn ich das richtig verstanden habe, mathematisch ergibt es jedenfalls Sinn.


----------



## Dragonix (22. Oktober 2011)

Also, wenn du's mathematisch verstanden hast (und danach schauts aus!), dann haben wir schon fast gewonnen. Jetzt müssen wir's blos noch dem PC beibringen.
Und das tolle bei rekursiven Algorithmen ist, dass die sich, wenn man sie einmal verstanden hat, hübsch programmieren lassen.
Deine Funktion muss eigentlich nur folgendes tun (und das tut sie doch auch schon fast!)
1. Prüfen ob X < als 2 ist. Wieso? Dann kennen wir die Fibonacci Zahl nämlich schon!
2. Ansonsten einfach die Summe aus den beiden vorangehenden Fibonaccizahlen zurückgeben.

Wieso zurückgeben? Das ist Quasi das Einsetzen was du an der Tafel machst, sonst geht das Ergebnis ja verloren! Und ein print gibt das eben nicht zurück sondern gibt's auf dem Bildschirm aus.

Ansonsten nochmal nachdrücklich: Schreib den Code, stell ihn hier rein damit wir sehen können wo dein Denkfehler liegt!


----------



## _-=Dante=-_ (22. Oktober 2011)

#!/usr/bin/perl

use strict;
use warnings;

my $n=0;
my $fib=0;

print "Geben Sie eine Zahl ein, von der Sie die dazugehörige Fibonacci-Zahl erhalten möchten\n";

chomp($n=<STDIN>);

if  ($n=0)  { 
print "$n"; }

if ($n=1)  {
print "$n"; }

if ($n=>2) 

{
$fib= ($n-1) + ($n-2);
return $fib;
}

So, ab hier komme ich nicht mehr weiter...falls das bis hier hin überhaupt stimmen kann.
Wenn das nicht stimmt, wo ist mein Denkfehler?


----------



## Dragonix (22. Oktober 2011)

Also: Das ist jetzt ein Rückschritt gegenüber dem ersten Code:
Du hast die Funktion (bzw bei Pearl: Subroutine, Perl-Programmierung: Subroutinen anschauen!) entfernt, die brauchst du aber unbedingt! Sonst kannst du ja nicht rekursiv aufrufen!
Ansonsten: Subroutine wieder einbauen, die beiden "prints" bei den beiden if Abfragen durch returns ersetzen! Und das kleiner-gleich Zeichen solltest auch nochmal genau anschauen!

Ich skizzier dir nochmal den Ablauf:
1. Hallo, von welcher Zahl soll Fib berechnet werden etc.
2. Zahl einlesen, bis dahin passts.
3. Fibonacci(Zahl) aufrufen und speichern (oder direkt ausgeben)

Fibonacci-Subroutine soll so ausschauen:
1. Prüfen ob wir die Fibonacci Zahl "direkt" (0, 1) berechnen können
2. Wenn nicht, die vorangehenden berechnen und deren Summe zurückgeben

Les dir mal das bei wikibooks bzgl Subroutinen durch! Glaub das könnte hilfreich sein!

Edit, falls jemand über Google drüberstolpert: Ist wichtig:


> Das in C, C++ und anderen Programmiersprachen verwendete return zur Rückgabe eines einzelnen Wertes ist in Perl am Ende einer Subroutine nicht zwingend nötig. Von der Subroutine wird immer der Rückgabewert des letzten Befehls zurück gegeben. Die folgende Subroutine test liefert zum Beispiel den Wert 1, da dieser bei erfolgreicher Ausführung der festgelegte Rückgabewert von print ist.


Sagt wikibooks!


----------



## _-=Dante=-_ (22. Oktober 2011)

Okay, danke dir...
Ich werde mich belesen, weiter daran arbeiten und vielleicht läuft es irgendwann fehlerfrei...was das angeht, bin ich aber eher pessimistisch.
Ich will deine Zeit nicht weiter in Anspruch nehmen und dir sowas zumuten.
Entweder ich pack das ab hier alleine, weil du mir schon viel geholfen hast, oder ich habe eben Pech.
Also vielen Dank und einen angenehmen Abend noch,


Gruß Flori


----------



## Dragonix (22. Oktober 2011)

Quatsch, wir ziehen das hier durch.
Du liest dier erstmal das zu Routinen durch, dann arbeitest das neue Wissen in den Code ein, und dann postetst den Code nochmal!

Nicht unterkriegen lassen


----------



## _-=Dante=-_ (22. Oktober 2011)

lol, wer den Thread hier von Anfang an mitverfolgt hat, der erlebt hier auch eine Geschichte mit Höhen und Tiefen, ob Happy End oder nicht wissen die Protagonisten noch nicht mal selbst 
Gut, mache ich...den Code, den ich dir ganz am Anfang geschickt habe, ist von nem Kumpel und genauso läuft er bei ihm aufn Mac unter vim.
Er hat ihn in fünf Minuten geschrieben. Ob ich da eines Tages auch mal hinkomme, naja.
Ich meld mich später wieder, könnte noch etwas dauern...


----------



## _-=Dante=-_ (22. Oktober 2011)

#!/usr/bin/perl

use strict;
use warnings;

my$n=0;
my$fib=0;

print "Geben Sie eine Zahl ein, von der Sie die dazugehörige Fibonacci-Zahl erhalten möchten\n";
$n=<STDIN>;


sub Fibonacci
             {
my $n=$_[0];
$n=<STDIN>;

if ($n==0)   {
return $n;
             }

if  ($n==1)  { 
return $n;   }

return Fibonacci ($n - 1) + Fibonacci ($n - 2);
                } 


Es ist falsch, aber ich es geht jetzt nicht besser...Mit diesem Programmieren geht ein ganzes We flöten, nur weil die uns nichts beibringen und ich habe noch 5 andere Fächer in denen ich im Januar geprüft werde-.-
Keine Ahnung, was daran jetzt wieder falsch ist, Fakt ist, dass ich kein Bock mehr habe, weil seit gestern nichts funktioniert


----------



## Dragonix (22. Oktober 2011)

Na etz hammers doch fast.
2 Fehler:
1.: Du musst deine Subroutine noch irgendwo aufrufen! Du hast sie jetzt zwar geschrieben, aber du rufst sie nie auf! Außerdem musst du auch noch die berechnete Zahl ausgeben.

2.: In der Subroutine lässt du jedesmal ein neues n einlesen. Warum? Raus damit, denk mal drüber nach.

Und mein "Fehler": Bei Pearl brauchst du das return nicht unbedingt (zumindest nicht am Ende, dann wird einfach das Ergebnis der letzten Anweisung zurückgegeben). Steht in Wiki, ich würds aber stehen lassen.


----------



## _-=Dante=-_ (22. Oktober 2011)

Ich würde gern mal wissen, was du beruflich machst und wie alt du bist, aber dazu später mehr 

#!/usr/bin/perl

use strict;
use warnings;

my$n=0;
my$fib=0;

print "Geben Sie eine Zahl ein, von der Sie die dazugehörige Fibonacci-Zahl erhalten möchten\n";

$n=<STDIN>;


sub Fibonacci
             {
my $n=$_[0];

if ($n==0)   {
return $n;
             }

if  ($n==1)  { 
return $n;   }

return Fibonacci ($n - 1) + Fibonacci ($n - 2);
             } 
print Fibonacci ( $ARGV[0] )."\n";


Ich weiß nicht, wie ich der Sub sage, dass sie anfangen soll, was zu machen...ich finde nur sub dann den Namen und in geschweifte Klammern kommt die Anweisung.
Was macht eigentlich my$fib, das habe ich vorher deklariert, es kommt aber nie wieder vor


----------



## Dragonix (22. Oktober 2011)

Also, warum du my $fib machst: Musst schon du selber wissen, du verwendest sie aber nicht mehr, das stimmt.

Also, dein

```
Sub Fibonacci
{
...
}
```
definiert/deklariert (kp ob/wie's da bei Pearl Unterschiede gibt) die Funktion Fibonacci. Damit machst du die Funktion erst verfügbar. Wie du die Funktion aufrufst (ihr sagst, dass sie anfangen soll) steht in dem Wiki Link: Zum Beispiel aber ein einfaches "Fibonacci(ZAHL)" tut's auch. Du musst das Ergebnis aber entweder speichern ("VARIABLE_BLUBB = Fibonacci...") oder es ausgeben (print Fibonacci(ZAHL)), sonst landet's im Nirvana.
Aber im Prinzip tust du das schon (wo auch immer du die Zeile wieder her hast O):

```
print Fibonacci ( $ARGV[0] )."\n";
```
Ruft die Funktion mit dem Ersten Argument auf, mit dem du dein Programm aufrufst (pearl meinfibonaccipearlprogramm.pl 11).
Ruf das Programm mal so auf: pearl PROGRAMMNAME 11, gib dann nach der Frage irgendeine Zahl ein (ist egal), und dann siehst du die 11te Fibonacci Zahl.
Du musst eigentlich einfach nur die Zeile so ändern, dass die eingegebene Fibonacci-Zahl berechnet wird.
Aus kosmetischen Gründen würde ich die Zeile auch über die Definition der Fibonacci Funktion stellen.

Also, auf auf, gleich haben wirs


----------



## _-=Dante=-_ (22. Oktober 2011)

#!/usr/bin/perl

use strict;
use warnings;

my$n=0;

print "Geben Sie eine Zahl ein, von der Sie die dazugehörige Fibonacci-Zahl erhalten möchten\n";

$n=<STDIN>;


sub &Fibonacci
             {
my $n=$_[0];

VARIABLE_$n=Fibonacci;

if ($n==0)   {
return $n;
             }

if  ($n==1)  { 
return $n;   }

return Fibonacci ($n - 1) + Fibonacci ($n - 2);
             } 

print Fibonacci ( $ARGV[0] )."\n";


Ich kriegs nicht hin...ich sitze seit heut morgen dran ohne Pause, ich kann nicht mehr denken...kannste nicht einfach sagen, wie der richtig heißen muss, damit dieses scheiß Programm, was nie ein Mensch brauchen wird, läuft?
Er sagt mir immer, wenn ich das Prog so starten soll, wie du gesagt hast, dass die sub nicht richtig deklariert wurde.


----------



## Dragonix (23. Oktober 2011)

Schade, dabei warst du so nah dran.

```
#!/usr/bin/perl

 use strict;
 use warnings;

 my $n=0;


 print "Geben Sie eine Zahl ein, von der Sie die dazugehörige Fibonacci-Zahl erhalten möchten\n";

 $n=<STDIN>;

 print Fibonacci( $n )."\n";

 sub Fibonacci
 {
 my $n=$_[0];

 if ($n==0) {
 return $n;
 }

 if ($n==1) {
 return $n; }

 return Fibonacci ($n - 1) + Fibonacci ($n - 2);
 }
```
So läuft's bei mir. Ohne Garantie auf Perl'sche Feinheiten/Eigenheiten.

Allgemein: google --> perl fibonacci --> Rekursion


----------

