Funktion und Ascii

Hallo.

Ich möchte eine Funktion haben, die die eingegebene Zahl prüft, ob es sich dabei um eine Primzahl handelt. Ich lasse also i von 2 bis zur Zahl hochlaufen.
Wenn sie eine Zahl findet, die ohne Rest durch die Zahl teilbar ist, soll sie die Funktion als false zurückgeben die Schleife beenden.

function pruefen (zahl: Integer):Boolean;
VAR i, test: Integer;
begin
i := 1;
pruefen := true;
repeat
i := i+1;
test := zahl mod i;
if test = 0 then pruefen := false;
//die Schleife wird so lange durchlaufen, bis i gleich zahl ist,
//oder ein Teiler gefunden wurde
until ((i = zahl-1) or (pruefen = false));
end;

Wo ist der Fehler?

Ohne den fettgedruckten Teil funktioniert alles perfekt. Nur läuft die Funktion dann immer bis zum Schluss durch, was bei großen Zahlen lange dauert.

Des weiteren ist diese Funktion Teil eines Verschlüsselungsprogrammes. Da es nur mit Zahlen arbeitet, der Text aber Buchstaben beinhaltet, wollte ich mit den dazugehörigen Ascii-Zeichen rechnen. Wie heißt die Funktion, die das dazugehörige Ascii-Zeichen ausgibt?

Danke schonmal im Voraus

und Gruß

Claudia.

Hallo!

chr() heißt die Funktion, die zu einem gegebenen ASCII-Code das entsprechende Zeichen zurückliefert. ord() leistet die entgegengerichtete Umwandlung.

Falk

Hallo.

Ich möchte eine Funktion haben, die die eingegebene Zahl
prüft, ob es sich dabei um eine Primzahl handelt. Ich lasse
also i von 2 bis zur Zahl hochlaufen.
Wenn sie eine Zahl findet, die ohne Rest durch die Zahl
teilbar ist, soll sie die Funktion als false zurückgeben die
Schleife beenden.

function pruefen (zahl: Integer):Boolean;
VAR i, test: Integer;
begin
i := 1;
pruefen := true;
repeat
i := i+1;
test := zahl mod i;
if test = 0 then pruefen := false;
//die Schleife wird so lange durchlaufen, bis i gleich zahl
ist,
//oder ein Teiler gefunden wurde
until ((i = zahl-1) or (pruefen = false));
end;

Wo ist der Fehler?

Hallo Claudia,

du verwendest die Funktion in der until-Abfrage - das ruft aber die Funktion rekursiv auf! Kein Wunder, dass es lange dauert.

Entweder nimmst du die variable Result (Delphi only), oder für uralt-strict Pascal eine eigene logische Variable (am sichersten), etwa so:

function prim (zahl : integer) : boolean;
var i,tmax : integer;
 teilbar : boolean;
begin
i := 2; 
teilbar := false; { eigentlich nicht notwendig }
tmax := int (sqrt(zahl)) + 1;
repeat
 teilbar := (Zahl mod i) = 0;
 i := i + 1;
until teilbar oder (i \> tmax);
prim := not teilbar;
end;

Merke: der Funktionsname darf im Funktionsrumpf nur links von := stehen, sonst ist es ein rekursiver Aufruf der Funktion.

Gruss Reinhard

Hallo Claudia,

function pruefen (zahl: Integer):Boolean;
VAR i, test: Integer;
begin
i := 1;
pruefen := true;
repeat
i := i+1;
test := zahl mod i;
if test = 0 then pruefen := false;
//die Schleife wird so lange durchlaufen, bis i gleich zahl
ist,
//oder ein Teiler gefunden wurde
until ((i = zahl-1) or (pruefen = false));
end;

das „pruefen“ in der „until“-Zeile ist doppeldeutig. Bedeutung 1: Die Speicherstelle, in der das Ergebnis der Funktion abgelegt wird (wäre beim Delphi-Compiler äquivalent zu „Result“); Bedeutung 2: Der Bezeichner der von Dir geschriebenen Funktion „pruefen“. Hängt vom Compiler ab, wie derselbe das interpretiert. Von einem guten Compiler würde ich fast erwarten, dass er diese Zeile anmeckert. Aber egal – wegen dieser Doppeldeutigkeit ist die Zeile in jedem Fall faul. So programmiert man einfach nicht.

Mein Vorschlag:

function ZahlIstPrim (zahl: Integer): Boolean;

VAR 
 i: Integer;
 teilergefunden: Boolean;

begin
 i := 1;
 teilergefunden := false;

 repeat
 i := i+1;
 teilergefunden := ((zahl mod i) = 0);
 until (i = zahl-1) or teilergefunden;

 ZahlIstPrim := not teilergefunden
end;

Den Kommentar hab ich gelöscht, weil die „until“-Zeile hier m. E. nach keinen mehr benötigt. In der letzten Zeile findet die „Ergebniszuweisung“ statt. Um Bugs von vornherein zu vermeiden, empfiehlt es sich, das immer so zu machen. Falls Du mit Delphi programmierst, kannst Du das „ZahlIstPrim“ auch noch durch „Result“ ersetzen.

Und noch ein Hinweis: Die Funktion liefert für das Argument 2 ein falsches Ergebnis zurück, nämlich false, obwohl 2 eine Primzahl ist.

Außerdem ist diese Funktion sehr ineffizient. Es reicht, i in Zweierschritten hochzuzählen, denn wenn man weiß, dass eine Zahl nicht durch 2 teilbar ist, dann ist es unsinnig, sie noch auf Teilbarkeit durch 8 oder 56 oder 292 oder irgendeine andere gerade Zahl zu testen. Außerdem muss i nicht bis zahl - 1 laufen, sondern nur bis zur Quadratwurzel von zahl (Funktion „sqrt“). Denn wenn die Zahl einen Teiler größer als √zahl hat, dann wäre der zugehörige andere Teiler kleiner als √zahl und wäre schon gefunden worden.

Gruß
Martin

Hallo.

Ich möchte eine Funktion haben, die die eingegebene Zahl
prüft, ob es sich dabei um eine Primzahl handelt. Ich lasse
also i von 2 bis zur Zahl hochlaufen.
Wenn sie eine Zahl findet, die ohne Rest durch die Zahl
teilbar ist, soll sie die Funktion als false zurückgeben die
Schleife beenden.

until ((i = zahl-1) or (pruefen = false));
end;

Wo ist der Fehler?

Hallo Claudia,

du verwendest die Funktion in der until-Abfrage - das ruft
aber die Funktion rekursiv auf! Kein Wunder, dass es lange
dauert.

Entweder nimmst du die variable Result (Delphi only),

Ich hab Delphi (6.0), aber mein Compiler und ich sehen zwischen Result und dem Funktionsnamen keinen Unterschied. Dazu habe ich die Delphi-Hilfe genommen und da drin stand, dass innerhalb der Funktion der Name wie eine normale Variable behandelt wird.

oder für
uralt-strict Pascal eine eigene logische Variable (am
sichersten), etwa so:

function prim (zahl : integer) : boolean;
var i,tmax : integer;
teilbar : boolean;
begin
i := 2;
teilbar := false; { eigentlich nicht notwendig }
tmax := int (sqrt(zahl)) + 1;
repeat
teilbar := (Zahl mod i) = 0;
i := i + 1;
until teilbar oder (i > tmax);
prim := not teilbar;
end;

Merke: der Funktionsname darf im Funktionsrumpf nur links von
:= stehen, sonst ist es ein rekursiver Aufruf der Funktion.

Wieder was gelernt. Is lange her, seit ich das letzte Mal mit Delphi programmiert habe.

Danke und Gruß Claudia.

Gruss Reinhard

Hallo Martin,

doppeldeutig ist die Sache nicht, auch in Delphi gilt: Funktionsname rechts in einer Zuweisung -> rekursiver Aufruf der Funktion. Bei Pascal nach Jensen/Wirth sowieso.

Eigentlich müsste der Compiler also fehlende Parameter beim Funktionsaufruf melden.

Gruss Reinhard

Hallo Claudia,

function pruefen (zahl: Integer):Boolean;
VAR i, test: Integer;
begin
i := 1;
pruefen := true;
repeat
i := i+1;
test := zahl mod i;
if test = 0 then pruefen := false;
//die Schleife wird so lange durchlaufen, bis i gleich zahl
ist,
//oder ein Teiler gefunden wurde
until ((i = zahl-1) or (pruefen = false));
end;

das „pruefen“ in der „until“-Zeile ist doppeldeutig.
Bedeutung 1: Die Speicherstelle, in der das Ergebnis der
Funktion abgelegt wird (wäre beim Delphi-Compiler äquivalent
zu „Result“); Bedeutung 2: Der Bezeichner der von Dir
geschriebenen Funktion „pruefen“. Hängt vom Compiler ab, wie
derselbe das interpretiert.

Also in der Hilfe hab ich gelesen, dass er das innerhalb der Funktion als normale Variable nutzt und erst außerhalb als Funktionsaufruf.

Von einem guten Compiler würde
ich fast erwarten, dass er diese Zeile anmeckert. Aber egal –
wegen dieser Doppeldeutigkeit ist die Zeile in jedem Fall
faul. So programmiert man einfach nicht.

Mein Vorschlag:

function ZahlIstPrim (zahl: Integer): Boolean;

VAR
i: Integer;
teilergefunden: Boolean;

begin
i := 1;
teilergefunden := false;

repeat
i := i+1;
teilergefunden := ((zahl mod i) = 0);
until (i = zahl-1) or teilergefunden;

ZahlIstPrim := not teilergefunden
end;

Den Kommentar hab ich gelöscht, weil die „until“-Zeile hier m.
E. nach keinen mehr benötigt. In der letzten Zeile findet die
„Ergebniszuweisung“ statt. Um Bugs von vornherein zu
vermeiden, empfiehlt es sich, das immer so zu machen.

Ok, ich merk es mir und ändere die anderen Funktionen.

Falls
Du mit Delphi programmierst, kannst Du das „ZahlIstPrim“ auch
noch durch „Result“ ersetzen.

wo ist der Unterschied zwischen Result und Funktionsname?

Und noch ein Hinweis: Die Funktion liefert für das Argument 2
ein falsches Ergebnis zurück, nämlich false, obwohl 2 eine
Primzahl ist.

Danke für den Hinweis. Ich schau mal, was ich da machen kann.

Außerdem ist diese Funktion sehr ineffizient. Es reicht, i in
Zweierschritten hochzuzählen, denn wenn man weiß, dass
eine Zahl nicht durch 2 teilbar ist, dann ist es unsinnig, sie
noch auf Teilbarkeit durch 8 oder 56 oder 292 oder irgendeine
andere gerade Zahl zu testen.

Tolle Idee. Dann prüf ich erst, ob sie gerade ist, dann fang ich ab 3 an in 2-er Schritten zu zählen, und zum Schluss prüfe ich, ob es sich um die Drei handelt, weil er dann bei der drei false zurückgeben würde.

Außerdem muss i nicht bis zahl

  • 1 laufen, sondern nur bis zur Quadratwurzel von zahl
    (Funktion „sqrt“). Denn wenn die Zahl einen Teiler größer als
    √zahl hat, dann wäre der zugehörige andere Teiler
    kleiner als √zahl und wäre schon gefunden worden.

Auf die Idee bin ich gar nicht gekommen. Danke auch dir.

Gruß
Martin

Gruß Claudia.

Also in der Hilfe hab ich gelesen, dass er das innerhalb der
Funktion als normale Variable nutzt und erst außerhalb als
Funktionsaufruf.

wo ist der Unterschied zwischen Result und Funktionsname?

Hallo Claudia,

das mit der Delphi-Hilfe kann so nicht stimmen. Zitat daraus:

Result ist jedoch nicht mit dem Funktionsnamen identisch. Wenn der Funktionsname auf der linken Seite einer Zuweisungsanweisung verwendet wird, verwaltet der Compiler den Funktionsnamen als Variable (wie Result) zur Aufzeichnung des Rückgabewerts. Taucht der Funktionsname dagegen an einer anderen Stelle im Anweisungsblock auf, wird der Funktionsname vom Compiler als rekursiver Aufruf der Funktion interpretiert. Result kann dagegen als Variable in Operationen eingesetzt werden, beispielsweise bei Typkonvertierungen, in Konstruktoren, Indizes und in Aufrufen anderer Routinen.
Zitat Ende.

Wäre es nämlich so, wie du sagst, gäbe es ja keine Rekursion mehr. Ob das ein grosser Verlust wäre, steht auf einem anderen Blatt.

Gruss Reinhard

Hallo Claudia
Ich habe vor Zeiten eine DELPHI-Function für Primzahlen geschrieben, welche die Anregungen von Martin betr. „Zweierschritt“ und „bis zur Wurzel“ enthält, aber auch die „2“ richtig erkennt.
Ein leider verstorbener Freund hat sich intensiv mit Kryptographie befasst und von ihm weiss ich, dass so ein Algorithmus immer noch viel zu primitiv (=langsam) ist, für ensthafte Anwendungen. Immerhin läuft er:

Function IsPrim(zahl : integer): boolean;
var
i: integer;
begin
Result := false;
// 0 und 1 und alle negativen sind nicht prim
if (zahl 2
if (zahl > 2) AND( trunc(zahl) mod 2 = 0) then exit;
Result:= true;
If (zahl = 2) OR (zahl=3) then exit; // sind Prim, 2 „kommt bis hier durch“
i := 3; // erster Divisor
Repeat
If ((trunc(zahl) mod i) = 0) then // aufgegangen = kein Prim
begin
Result := false;
exit;
end;
INC(i,2);
until i > Trunc(Sqrt(zahl));
end;

Nachdem ich die Arbeiten des erwähnten Freundes studiert habe muss ich sagen, ich würde niemals versuchen, selbst so ein Programm zu „stricken“. Dies nur als leise Warnung, bevor du dich in ein Abenteuer begibst!
Viel Glück
Erich

Hallo Claudia
Ich habe vor Zeiten eine DELPHI-Function für Primzahlen
geschrieben, welche die Anregungen von Martin betr.
„Zweierschritt“ und „bis zur Wurzel“ enthält, aber auch die
„2“ richtig erkennt.
Ein leider verstorbener Freund hat sich intensiv mit
Kryptographie befasst und von ihm weiss ich, dass so ein
Algorithmus immer noch viel zu primitiv (=langsam) ist, für
ensthafte Anwendungen.

  1. Mein Beileid.
  2. Keine Angst, es ist keine „ernsthafte“ Anwendung, sondern „nur“ für die Schule. Wir sollen Cäsar und RSA programmieren. Damit wir das Prinzip verstehen.

Immerhin läuft er:

Function IsPrim(zahl : integer): boolean;
var
i: integer;
begin
Result := false;
// 0 und 1 und alle negativen sind nicht prim
if (zahl 2
if (zahl > 2) AND( trunc(zahl) mod 2 = 0) then exit;
Result:= true;
If (zahl = 2) OR (zahl=3) then exit; // sind Prim, 2 „kommt
bis hier durch“
i := 3; // erster Divisor
Repeat
If ((trunc(zahl) mod i) = 0) then // aufgegangen = kein
Prim
begin
Result := false;
exit;
end;
INC(i,2);
until i > Trunc(Sqrt(zahl));
end;

Nachdem ich die Arbeiten des erwähnten Freundes studiert habe
muss ich sagen, ich würde niemals versuchen, selbst so ein
Programm zu „stricken“. Dies nur als leise Warnung, bevor du
dich in ein Abenteuer begibst!

Es geht wie gesagt nur ums Prinzip.um zu schauen, ob es funtioniert.

Viel Glück
Erich

Hallo,

Function IsPrim(zahl : integer): boolean;
var
i: integer;
begin
Result := false;
// 0 und 1 und alle negativen sind nicht prim
if (zahl 2
if (zahl > 2) AND( trunc(zahl) mod 2 = 0) then exit;
Result:= true;
If (zahl = 2) OR (zahl=3) then exit; // sind Prim, 2 „kommt
bis hier durch“
i := 3; // erster Divisor
Repeat
If ((trunc(zahl) mod i) = 0) then // aufgegangen = kein
Prim
begin
Result := false;
exit;
end;
INC(i,2);
until i > Trunc(Sqrt(zahl));
end;

Nachdem ich die Arbeiten des erwähnten Freundes studiert habe
muss ich sagen, ich würde niemals versuchen, selbst so ein
Programm zu „stricken“.

die Arbeit deines Freundes in Ehren, aber wieso benutzt er die Funktion Trunc in Zusammenhang mit einem Integer? Trunc dient dazu, aus einem Dezimalbruch einen Integer zu machen. Ich weiß nicht, ob Delphi schlau genug ist, diesen Patzer zu erkennen. Benutzt er sie zusammen mit einem Integer, so wird aus dem Integer zunächst ein
Float-Wert gemacht (implizit) und anschließend wieder ein Integer. Und das ganze auch noch in einer Schleife. Nicht sehr effizient.
Ein weiterer Bremsklotz ist die „until“-Zeile. Hier wird bei jedem Durchlauf „Trunc(Sqrt(zahl))“ berechnet. Da sich „zahl“ innerhalb der Funktion nicht ändert, macht man das einmal am Beginn der Funktion und speichert das Ergebnis in einer Variablen. Denn sonst führt man die exakt gleich Berechnung unnötigerweise immer und immer wieder aus.

Gruß, Niels

Hallo Niels
Vielen Dank für die Informationen.
Meinen Freund habe ich erwähnt, um zu sagen „ich selbst verstehe fast nichts von Kryptographie“, kann also dort nicht helfen.
Die Primzahlen-Function jedoch habe ich selbst verbrochen! Du hast nun gesehen, dass ich auch in DELPHI kein so kapitaler Hirsch bin!
Ich werde deine Anregungen zum Anlass nehmen, etwas dazu zu lernen.
Gruss
Erich

Hallo Niels
Jetz habe ich meine Primzahlenfunktion entsprechend umgebaut und möchte prüfen, um wieviel schneller sie ist.
Dazu hilft mir DELPHI nicht viel weiter mit der Funktion time():

zeit := time();
prim := isPrim(zahl);
form1.LabelEnde.Caption := timeToStr(time()-zeit);

Das liefert einfach Null, da unter 1 Sekunde auch bei grosser Zahl wie 2’147’483’647! Kann man da die API irgendwie aufrufen, ich brauche doch Millisekunden? Wie sieht dann der Code aus?
Gruss
Erich

Hallo,

schau mal die Funktion GetTickCount() an.

Gruß, Niels

Hallo,
Ich habe eine (elegante?) Lösung erstellt mit:
QueryPerformanceFrequency©;
QueryPerformanceCounter(n1);
abgeguckt im Buch DELPHI5 Doberenz/Kowalski.
Mit deinen Aenderungen läuft das Ding rund 6 Mal schneller!
Gruss
Erich

Da die Übergabe „Zahl“ ist ein Integer ist, kann man doch die Function TRUNC() komplett sparen.

Gruß
Khanh

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]