Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Elementares in Pascal


Torsten - Di 01.10.02 19:48
Titel: Elementares in Pascal
Moinsen Leute!

Mal eine elementare Frage zu Pascal.
Ich habe den ganzen Sommer über keinen Rechner gesehen, also viel vergessen. Besonders, was reines Pascal angeht.

Also, ich will in einem kleinen Programm das Skalar-Produkt im n-dimensionalen Raum berechnen.
Die eigentliche Berechnung ist mir eigentlich klar, nur die Arrays gefallen mir nicht so recht.
Ich kann euch ja mal meinen Entwurf zeigen.

Zu beachten ist noch, dass das Skalarprodukt später mittels "s:=Skal_Prod(n, V, W)" aufgerufen werden soll.
n ist also die Dimension (2,3,4,...) und V bzw. W die Vektoren.


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
program skalar;


function Skal_Prod(n:Integer; x:array of Real; y:array of Real):Real;
 var
        i: Integer;

 begin
        i:=1;
        Skal_Prod:=0.0;

        repeat
         Skal_Prod:=Skal_Prod + (x[i]*y[i]);
         i:=i+1;
        until i > n;
 end;

begin
 // ab hier nun das Hauptprogramm
end.


Nun noch eine Fragen.
In Zeile "Skal_Prod:=Skal_Prod + (x[i]*y[i]);" bekomme ich einen Compiler-Fehler!
Wieso? Geht das so nicht?


Ach ja, hat jemand rein zufällig ein gutes Forum für reines Pascal in Verbindung mit Mathe?

Fragende Grüße

Torsten


Christian S. - Di 01.10.02 19:54

Hi!

Pascal ist bei mir jetzt schon 3 Jahre her, aber mit einer Function darfst Du in Pascal glaube ich keine solche Zuweisung machen. Definiere Dir doch eine lokale Variable vom Typ Real, mit der Du die gleichen Berechnungen machst, die Du aber erst ganz am Ende Skal_Prod zuweist.

Bei Delphi fangen Arrays, wie Du sie verwendest, mit dem Index 0 an, ist das bei Pascal anders?

MfG,
Peter


Torsten - Di 01.10.02 19:59

Hallo!

OK, das mit der Variablen habe ich mir auch überlegt. Ich war jedoch der Meinung, dass es auch so geht. aber man lernt ja immer dazu.

Tja, Arrays in Pascal. Ich denke mal auch, dass sie bei 0 beginnen. Also ähnlich C oder Delphi. Sicher bin ich mir jedoch auch nicht, daher die Frage.

Kann man den ganzen Kram nicht ohnehin irgendwie besser machen?

Grüße

Torsten


Christian S. - Di 01.10.02 20:07

Hi!

Ich glaube nicht, dass man das ganze noch verbessern kann. Die Laufzeit ist glaube ich mit einer linearen Abhängigkeit von n ganz in Ordnung. Man kann natürlich jetzt versuchen, herauszufinden, ob Inc(i) schneller ausgeführt wird als i:=i+1; aber ganz ehrlich halte ich das für maßlos übertrieben.

MfG,
Peter

P.S.: Definiere doch alle Winkel als 90°, dann ist das Skalarprodukt ganz einfach Null!


Klabautermann - Di 01.10.02 20:33
Titel: Re: Elementares in Pascal
Hallo,
Torsten hat folgendes geschrieben:


Quelltext
1:
         Skal_Prod:=Skal_Prod + (x[i]*y[i]);                    



Skal_Prod ist deine funktion, also ist der erste Teil der Zeile (Skal_Prod:=) Ok. Danch rufst du aber wieder Skal_Prod auf. Das währe generell auch kein Problem, nur müsstest du dann:
1. auch die benötigten Parameter übergeben.
2. Eine abbruchbedingung für die benötigte Rekursion schreiben.

Ich glaube aber nicht, das du überhaupt eine Rekursion machen willst.
Wenn du das ganze in Delphi Implementierst, kannst du Result verwenden (ich weis nicht mit welcher Verion das eingeführt wurde, vieleicht gab es das schon in neueren Turbo Pascal Versionen).
Dann sähe deine Funktion so aus:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
function Skal_Prod(n:Integer; x:array of Real; y:array of Real):Real;
var
    i: Integer;
begin
    i:=1;
    Result:=0.0;
    repeat
     Result:=Result + (x[i]*y[i]);
     i:=i+1;
    until i > n;
end;


Ansonsten musst du tatsächlich zu einer Hilfsvariable greifen.

Mit freundlichen Grüßen
Klabautermann


Torsten - Di 01.10.02 21:09

Moinsen!

Besten Dank für die Antworten.

Ja, result kenne ich von Delphi auch. Aber eben nicht unter Pascal. Und da bin ich schon seit bestimmt 10 Jahren raus (habe auch nicht viel mit gearbeitet).

Habe es aber eben getestet.
Ich arbeite mit GnuPascal unter Linux.
result scheint auch hier zu funktionieren.
Um es aber auch für andere Compiler zu schreiben, werde ich eine globale Variable verwenden.

Grüße

Torsten


Christian S. - Di 01.10.02 21:35

Eine globale Variable?


Torsten - Di 01.10.02 21:43

Sorry, falsch ausgedrückt.
Gilt natürlich nur für die Funktion.

Ich habe aber wieder ein anderes Problem.
Und zwar mit einem dynamischen Array.

So, mal eben das Programm:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
program skalar;
var
        i: Integer;
        n: Integer;
        v,w: array of Real;


{die eigentliche Funktion}
function Skal_Prod(n:Integer; x:array of Real; y:array of Real):Real;
 var
        i: Integer;
        result: Real;

 begin
        i:=1;
        result:=0.0;

        repeat
         result:=result + (x[i]*y[i]);
         i:=i+1;
        until i > n;
        return result;
 end;

{ eigentliches Hauptprogramm }
begin
 writeln('Das Skalarprodukt:');
// s:=Skal_Prod(......)
end.


Der Compiler meldet in der 5. Zeile bei
"v,w: array of Real;"
einen Fehler (parse error befor 'of')

Hö?
Wieso?
Dynamische Arrays gibt es doch bei Pascal.

Grüße

Torsten


Christian S. - Di 01.10.02 22:14

Hi!

Ich habe jetzt nochmal mein altes TP7 herausgekramt und bei dem Code, den Du verwendest, meckert er. Anscheinend kannst Du Arrays ohne Größenangabe nur als Parameter übergeben. Aber als ich TP programmiert habe, war ich noch nicht so weit, dass ich überhaupt auf die Idee von dynamischen Arrasy gekommen wäre; also kann es sein, dass es da irgendeinen Code gibt, wie man sie doch verwenden kann.

MfG,
Peter

P.S.: Die Fehlermeldung bei mir: "[" oder "(." erwartet


Torsten - Di 01.10.02 22:20

Moinsen!

Verdammte Axt.
Anscheinend gibt es doch keine dynamischen Arrays.
Eben doch nur als Parametrübergabe.

Naja, dann muss ich mir was einfallen lassen.

Dumm ist nur, dass ich die dort gebrauchen könnte.
Denn man weiss ja vorher nicht, in welcher Dimension das das Skalarprodukt gebildet werden soll.

Grüße

Torsten


Christian S. - Di 01.10.02 22:34

Hi!

Könntest Du das ganze nicht als Records in temporären Dateien speichern? Die kannst Du beliebig groß machen. Ist zwar ein Algorithmus mit der Brechstange aber es könnte funktionieren!

MfG,
Peter


CenBells - Di 01.10.02 22:39

Zitat:
Ich glaube nicht, dass man das ganze noch verbessern kann. Die Laufzeit ist glaube ich mit einer linearen Abhängigkeit von n ganz in Ordnung. Man kann natürlich jetzt versuchen, herauszufinden, ob Inc(i) schneller ausgeführt wird als i:=i+1; aber ganz ehrlich halte ich das für maßlos übertrieben.


Inc(i) wird schneller ausgeführt, als i := i+1;

Gruß
Ken


Torsten - Di 01.10.02 22:40

Hui, das wäre mir dann doch zu viel.

Es war eigentlich nur ein Test.
Ich habe nämlich gerade in einem alten Pascal-Buch gestöbert.
Dort stand die Aufgabe, dass man eine Funktion entwickeln soll, die das Skalarprodukt errechnet.
Diese Funktion sollte dann mit Wertübergabe aufgerufen werden. Aber das drumherum war weniger interessant.
Ich wollte es dennoch gerne probieren (ohne Erfolg).

Grüße

Torsten


Christian S. - Di 01.10.02 22:52

Ireniceus hat folgendes geschrieben:

Inc(i) wird schneller ausgeführt, als i := i+1;


Hatte ich schon vermutet, ansonsten würde es kaum Sinn machen, eine solche Funktion zu implementieren.

MfG,
Peter


Torsten - Di 01.10.02 23:00

Moinsen!

Nochmal zum dynamischen Array.
In C wüsste ich, wie zu implementieren (malloc).

Auch in Delphi.
Nur eben nicht in Pascal.

Aber: Man kann das auch als verkette Liste ausführen.
Doch ich will mal nicht übertreiben.

Außer jemand hat einen einfachen, genialen Vorschlag. ;)

Grüße

Torsten


Klabautermann - Di 01.10.02 23:11

Hallo!

Was ist an der Verketteten liste so schlim?


Torsten - Di 01.10.02 23:46

Moinsen!

Och naja, irgendwie sträube ich mich immer etwas dagegen.

Hast Du etwa eine Lösung für meine Aufgabe?

Grüße

Torsten


Klabautermann - Mi 02.10.02 01:00

Hallo,

da verlangst du was zu dieser späten Stunde. Aber gut, dann werde ich mal schnell was hintippen.
Aber eins vorweg: Aufgrund der vortgeschrittenden Zeit habe ich das nicht getestet oder nochmal genauer überprüft. Wenn es ein Problem gibt können wir Morgen nochmal drüber reden:

Also hier die Datentypen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
TYPE
    pRealList = ^tRealList;
    tRealList = PACKED RECORD
      Value : Real;
      Next : pRealList;
    END// tRealList


Die Variablendeklaration:

Delphi-Quelltext
1:
2:
VAR
    v, w : pRealList;


Vergiss die Initialisierung nicht:

Delphi-Quelltext
1:
2:
  v := NIL;
  w := NIL;


Und das Werkzeug:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
  procedure Appent2RealList(Value : Real; aList : pRealList);
    VAR
      Runner, NewEle : pRealList;
  BEGIN
    NEW(NewEle);
    NewEle^.Value := Value;
    NewEle.Next := NIL;
    Runner := aList;
    IF (Runner = NILTHEN // Sonderfall Liste ist leer
      aList := NewEle
    ELSE BEGIN // Eintrag anhängen
      WHILE (Runner^.Next <> NILDO
        Runner := Runner^.Next;
      Runner^.Next := NewEle;
    END// Eintrag anhängen
  END// Appent To RealList

  function RealListLength(aList : pRealList) : LongInt;
    VAR
      Runner : pRealList;
  BEGIN
    Result := 0;
    Runner := aList;
    WHILE (Runner <> NILDO BEGIN
      INC(Result);
      Runner := Runner^.Next;
    END;
  END// RealListLength

  function GetRealValue(aIndex : LongInt; aList : pRealList) : Real;
    VAR
      Runner : pRealList;
      i : LongInt;
  BEGIN
    Result := 0;
    IF (aIndex < RealListLength(aList)) THEN BEGIN // Legitimer Index
      Runner := aList;
      FOR i := 1 TO aIndex DO
        Runner := Runner^.Next;
      Result := Runner^.Value;
    END// LEgitimer Index
  END// Get Real Value

  procedure RemoveRealValue(aIndex : LongInt; aList : pRealList);
    VAR
      Runner, tmp : pRealList;
      i : LongInt;
  BEGIN
    IF (aIndex < RealListLength(aList)) THEN BEGIN // Legitimer Index
      Runner := aList;
      IF (aIndex = 1THEN BEGIN // Sonderfall das erste Element löschen
        tmp := Runner;
        aList := aList^.Next;
      END // Sonderfall das erste Element löschen
      ELSE BEGIN // anderes Element löschen
        FOR i := 1 TO aIndex - 1 DO
          Runner := Runner^.Next;
        tmp := Runner^.Next;
        Runner^.Next := Runner^.Next^.Next;
      END// Belibiges Element außer das erste löschen
      Dispose(tmp);
    END// Legitimer Index
  END// Remove Value

  procedure ClearRealList(aList : pRealList);
    VAR
      tmp : pRealList;
  BEGIN
    WHILE (aList <> NILDO BEGIN
      tmp := aList;
      aList := aList.Next;
      Dispose(tmp);
    END// Mit allen Einträgen
  END// ClearRealList


Und jetzt mach' was draus ;).

Gruß
Klabautermann


Torsten - Mi 02.10.02 09:12

Moinsen!

Na hossa, das schaut ja wirklich gut aus.
Dennoch mag ich keine Listen, geschweige denn verkette Listen.
Aber bei Deinem Code sehe ich gut durch. Ist auch alles wunderbar enthalten (insert, remove, Länge,..)

Eigentlich wollte ich ja nicht so weit mit meinem Problem gehen, doch eventuell findet sich etwas Zeit.

Besten Dank dafür.

Grüße

Torsten


Klabautermann - Mi 02.10.02 16:00

Hallo,
Torsten hat folgendes geschrieben:
Dennoch mag ich keine Listen, geschweige denn verkette Listen.

das ist schade, sie sind sehr Praktisch und im Klassischen Pascal der Standard-Weg für Dynamische Speicherverwaltung. Mann muss sich nur einmal richtig damit auseinander setzen, dann verlieren sie ihren Schrecken. :mahn:

Torsten hat folgendes geschrieben:
Aber bei Deinem Code sehe ich gut durch. Ist auch alles wunderbar enthalten (insert, remove, Länge,..)

Ja, wenn man sich am Anfang ein wenig Arbeit macht, kann man später sehr konfortabel Arbeiten und hat auch keine sorgen mehr mit den Verketteten listen ;).

Torsten hat folgendes geschrieben:
Eigentlich wollte ich ja nicht so weit mit meinem Problem gehen, doch eventuell findet sich etwas Zeit.

Ich zwinge dich ja nicht. Wie gesagt, wenn es dir hilft, dann viel Spass damit. Wenn nicht, vieleicht lernt ein mitleser was draus :think:.

Torsten hat folgendes geschrieben:
Besten Dank dafür.

Bitteschön, ich hatte Spaß dabei, denn heutzutage kommt man ja nicht mehr so oft dazu (denn Dynamische Arrays oder tList finde ich auch schnuckelig und verwende sie daher).

Gruß
Klabautermann


Torsten - Mi 02.10.02 17:16

Moinsen!

OK, die Geschichte mit dem Spass kann ich wohl nachvollziehen.
Ich finde Zeiger und doppelt referenzierte Zeiger in C auch unheimlich interessant. Ist zwar etwas pervers, macht aber irgendwie Laune.
Nun muss ich den Spass nur noch auf Pascal übertragen.

Sehe ich übrigens ebenso. Am Anfang etwas Arbeit, danach komfortabel Klotzen.
Für die kleine Aufgabe war es aber nicht wirklich angebracht. Wollte eben nur mal ein wenig testen (was nicht heissen soll, dass Deine Lösung mich nicht freut).

Grüße

Torsten


Indeterminatus - Fr 04.10.02 12:39

Zitat:

Inc(i) wird schneller ausgeführt, als i := i+1;


Obwohl es bei einer TP-Compilerversion ab 6.0 auch schon egal ist, weil eine Erhöhung einer Variable um einen konstanten ganzzahligen Wert mittels Wertzuweisung (i := i+x, wobei x Element aus N) durch die Funktion Inc ersetzt wird, vorausgesetzt, die Optimierung für den Compilerdurchlauf wurde eingeschaltet...


Torsten - Fr 11.10.02 00:37

Moinsen!

Noch mal eine Frage zu mehrdimensionalen Arrays.

Also, ein gutes Beispiel sind mal wieder Vektoren. Jene können ja nun im n-dimensionalen Raum bestehen.

Nehmen wir mal, wir arbeiten im 3-dimensionalen Raum und haben zwei Vektoren.
Dann dürfte doch folgendes laufen:

Quelltext
1:
type TMyArray = array [0..2] of array [0..2] of Integer;                    


Oder sehe ich das irgendwie falsch?

Aber:
Wie kann man nun realisieren, dass man beispielsweise eine beliebige Anzahl von Vektoren nutzen kann?

Fragende Grüße

Torsten


Udontknow - Fr 11.10.02 08:00

Hi!

Nun, beliebig viele kannst du in einem dynamischen Array unterbringen. Noch schöner ist aber natürlich die Benutzung eines TList-Objekts, und bei Vektoren ist sowieso angebrachter, eine Klasse TVektor zu entwerfen, um in dieser dann auch benötigte Methoden unterzubringen (Anwendung einer Matrix auf einen Vektor z.B.).

Cu, :D
Udontknow


Torsten - Fr 11.10.02 08:37

@UdontKnow

Eigentlich war ich der Meinung, dass ich über Pascal sprach.

Grüße

Torsten


Udontknow - Fr 11.10.02 08:43

Naja gut, dann belassen wir es bei dynamischen Arrays.


Torsten - Fr 11.10.02 08:53

Moinsen!

Danke für die Antwort.
So wie es Klabautermann mir schilderte, will ich die Arrays aber nicht machen. Es gibt definitiv noch einen anderen Weg.
Mein Prof will aber einfach nicht damit rausrücken.
Er meinte, man könne das auch über type realisieren.

Grüße

Torsten


Udontknow - Fr 11.10.02 10:25

Hallo, ich nochmal! :)

Brutal gehts natürlich auch:

Reservierung von Speicher per Getmem für folgenden Record:

Quelltext
1:
2:
3:
4:
5:
6:
7:
type 
  PVektor=^TVektor;

  TVektor=record
    Data:Array[0..2] of integer;
    NextVektor:PVektor;
  end;

Du erzeugst dann weitere Elemente, indem du

Quelltext
1:
GetMem(NextVektor,SizeOf(TVektor));                    

aufrufst.

Du verkettest sozusagen die einzelnen Elemente in eine Richtung. Um auf einzelne Elemente zuzugreifen, solltest du dann am besten dir eine rekursive Routine basteln, die dir dann z.B. einen Pointer auf das Nte Element liefert.

Cu,
Udontknow

PS: So im nachhinein überlegt, braucht man für die Ermittlung des nten Elements keine Rekursion... :roll: