For Schleife mit großen Werten

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

For Schleife mit großen Werten

Beitrag von siro »

Einen schönen guten Morgen,

beim experimentieren stellte sich mir grad die Frage, ob man bestimmte Ganzzahlwerte leserlicher darstellen kann.
Wenn ich eine Schleife mit 10 Millionen Durchläufen habe, dann erfordert es schon ein "genaues" Augenmaß und das Zählen der Nullen ist angesagt... :wink:

Code: Alles auswählen

for i:=0 to 10000000 do            // wieviel sind das jetzt ???
for i:=0 to 10e6 do                // sehr übersichtlich, aber so das geht nicht wegen Float
for i:=0 to Int64(10e6) do         // Typwandlung: so geht das auch nicht
for i:=0 to integer(10e6) do       // aber das funktioniert

for i:=0 to integer(3.2E3) do      // auch das geht
for i:=0 to integer(3.2125E3) do   // <======das geht erstaunlicherweise auch ???? das sind doch 3212,5 ???
for i:=0 to integer(3.2124E3) do   // geht nicht
for i:=0 to integer(3.2126E3) do   // geht nicht

verwundert hatte mich es aber, dass eine krumme Zahl ging
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: For Schleife mit großen Werten

Beitrag von theo »

Vielleicht verstehe ich nicht ganz, aber warum nicht einfach das gute alte "Trunc" benutzen?

Code: Alles auswählen

Trunc(10e6)
https://www.freepascal.org/docs-html/rt ... trunc.html

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: For Schleife mit großen Werten

Beitrag von siro »

Danke Theo,
auf die Idee mit TRUNC bin ich garnicht gekommen :P
und es funktioniert sogar bei einer Konstantenzuweisung:

Code: Alles auswählen

CONST count=Trunc(1e10);

procedure TForm1.FormCreate(Sender: TObject);
var i:int64;
begin
  for i:=0 to count do begin

  end;
end;  
damit ist mein Problemchen gelöst.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: For Schleife mit großen Werten

Beitrag von wp_xyz »

Der Type-Cast einer Float-Konstante to Integer erzeugt nicht den Integer, der der Floatzahl wertmäßig entspricht, sondern einen Integer, der dasselbe Bitmuster hat wie die Floatzahl, und weil diese die einzelnen Bits dort ganz anders bewertet (Vorzeichen, Exponent, Mantisse) wird das eine völlig andere Zahl als erwartet. Und darum wird auch die Konstante mit dem Dezimalanteil akzeptiert.

Code: Alles auswählen

program Project1;
var
  x: Single;
  n: Integer;
begin
  x := 3.2E3;
  n := Integer(x);
  WriteLn(x:0:2);   // ---> 3200.00
  WriteLn(n);       // ---> 1162346496

  ReadLn;
end.
Zuletzt geändert von wp_xyz am Sa 12. Jun 2021, 18:20, insgesamt 1-mal geändert.

martin_frb
Beiträge: 572
Registriert: Mi 25. Mär 2009, 21:12
OS, Lazarus, FPC: Laz trunk / fpc latest release / Win and other
CPU-Target: mostly 32 bit

Re: For Schleife mit großen Werten

Beitrag von martin_frb »

Code: Alles auswählen

const 
  _K = 1000;
  _M = _K * 1000; 
for i := 0 to 10*_M + 986 * _K +123 do

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: For Schleife mit großen Werten

Beitrag von siro »

:shock: Upps, da hat wp_xyz natürlich vollkommen recht:
Die Typwandlung Float nach Integer geht natürlich so nicht.....

Code: Alles auswählen

var x:Single;
begin
  x:=3.1415;
  caption:=IntToStr(Integer(x));
end;                        
Da kommt dann 1078529622 raus.

Das ist natürlich ganz böse.
Man sagt ja nur, dass die Bytes des Integers an Adresse x liegen,
da liegen aber die Bytes des Floats und das geht gehörig schief.

Danke Dir für den Hinweis.

@martin_frb:
Das habe ich heute morgen erst verstanden, wie Du das meinst. Na klar so kann man das auch machen. Der Compiler macht ja die
Vorausberechnung.

Code: Alles auswählen

  for i:=0 to 1000 * 1000 * 10 do  // das sind ja auch 10.000.000 
Manchmal hat man echt nen Brett vorm Kopf.... :P oder sieht den Wald vor Bäumen nicht...
Danke Dir.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Erwin
Beiträge: 286
Registriert: Mi 16. Sep 2009, 14:15
OS, Lazarus, FPC: Xubuntu 22.04 / x86_64_linux-gtk 2 / L 2.2.0 / FPC 3.2.2

Re: For Schleife mit großen Werten

Beitrag von Erwin »

Man kann sich auch eine eigene Funktion dafür schreiben.
z.B.:

Code: Alles auswählen

function FZahlGrupiert(FZahl:String):Integer;  //(Oben zu den anderen Prozeduren/Vorwärtsdeklarationen etc.)
// In meinen Fall ist es im Hauptformular. Deshalb dann weiter unten TForm1 und Form1 (2. Codeblock).
// Je nach Bedarf den Rückgabewert anpassen, und in der Funktion den passenden Umwandlungsbefehl nutzen.

function TForm1.FZahlGrupiert(FZahl:String):Integer;
var i: Integer;
var FZahlHelfer: String;
begin
  FZahlHelfer:='';
  for i:=1 to length(FZahl) do
    case Copy(FZahl,i,1) of
      '1': FZahlHelfer:=FZahlHelfer+'1';
      '2': FZahlHelfer:=FZahlHelfer+'2';
      '3': FZahlHelfer:=FZahlHelfer+'3';
      '4': FZahlHelfer:=FZahlHelfer+'4';
      '5': FZahlHelfer:=FZahlHelfer+'5';
      '6': FZahlHelfer:=FZahlHelfer+'6';
      '7': FZahlHelfer:=FZahlHelfer+'7';
      '8': FZahlHelfer:=FZahlHelfer+'8';
      '9': FZahlHelfer:=FZahlHelfer+'9';
      '0': FZahlHelfer:=FZahlHelfer+'0';
      else FZahlHelfer:=FZahlHelfer;
    end;
  FZahlGrupiert:=StrToInt(FZahlHelfer);
end;
Diese Funktion kann man dann auch direkt verwenden in der For-Schleife:

Code: Alles auswählen

for i:=0 to Form1.FZahlGruppiert(10.000.000) do // Was auch immer .... 
Man kann in dem Fall neben Leer auch mit Punkten, oder per Trennstrich trennen, oder mit was auch immer.
Kann aber vielleicht sein, dass die direkte Verwendung in der For-Schleife den Durchlauf etwas verlangsamt. In so weit habe ich es nämlich noch nicht getestet.

Aber ansonsten, so hoffe ich, sollte es keine Probleme geben.
Hm... ich hätte aber vielleicht die eine Variable statt FZahl2, lieber FZahlHelfer nennen sollen?

Edit: Nach dem ich es bei mir geändert und getestet habe, habe ich es auch hier im Code-Block die Variable FZahl2 in FZahlHelfer umgeändert ... .
Lazarus 2.2.0 / FP 3.2.4

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: For Schleife mit großen Werten

Beitrag von wp_xyz »

Damit kannst du dann auch schreiben

Code: Alles auswählen

for i := 0 to ZahlGruppiert('5 Tausend 2 Hundert 99')
Aber statt des "Copy(FZahl, i, 1)" würde ich einfach "FZahl[ i]" nehmen, und auch die Case-Anweisung kann man vereinfachen:

Code: Alles auswählen

function ZahlGruppiert(Zahl:String):Integer;
var 
  i: Integer;
  ZahlHelfer: String;
begin
  ZahlHelfer := '';
  for i:=1 to length(Zahl) do
    if Zahl[i] in ['0'..'9'] then ZahlHelfer := ZahlHelfer + Zahl[i];
  Result :=StrToInt(ZahlHelfer);
end;

Erwin
Beiträge: 286
Registriert: Mi 16. Sep 2009, 14:15
OS, Lazarus, FPC: Xubuntu 22.04 / x86_64_linux-gtk 2 / L 2.2.0 / FPC 3.2.2

Re: For Schleife mit großen Werten

Beitrag von Erwin »

wp_xyz hat geschrieben:
Di 15. Jun 2021, 00:53
Aber statt des "Copy(FZahl, i, 1)" würde ich einfach "FZahl[ i]" nehmen, und auch die Case-Anweisung kann man vereinfachen:
Stimmt, dann würde der Case-Block (noch mit Copy) so aussehen:

Code: Alles auswählen

    case Copy(FZahl,i,1) of // Als Notiz auch ohne den Copy ...
      '0'..'9': FZahlHelfer:=FZahlHelfer+Copy(FZahl,i,1); // '0'..'9': FZahlHelfer:=FZahlHelfer+FZahl[i]; 
      else FZahlHelfer:=FZahlHelfer;
    end;
Wollte mir nicht so recht einfallen, vermutlich weil ich es extrem (Übertrieben) Ausführlich machen wollte. Wobei in dem Fall Case nicht mehr nötig ist. Glaube, Dein if ist in dem Fall auch schneller, oder?

Und dass man im String direkt auf die Stelle hinweisen/kopieren kann (String:=String[Stelle-im-String-Variable]), hatte ich total vergessen. Und traurigerweise von über halben Dutzend Bücher über Delphi, nur in einem gelesen.

Code: Alles auswählen

  WortS:='Wortlang'; 
  WortI:=WortS[3]; 
Besonders interessant ist aber dabei, dass es nicht bei 0, sondern bei 1 anfängt zu zählen. Also heraus kam dann bei WortI dann 'r';

Danke für die Tipps und Auffrischung, was der Handhabung von String betrifft.

Habe daraufhin folgendes naheliegendes getestet:

Code: Alles auswählen

  WortS:='Wortlang';
  WortIx:=WortS[2..6];
Auch das geht. Heraus kam dann 'ortla'.
Eigentlich eine generelle interessante Alternative zu Copy, ... oder?
Lazarus 2.2.0 / FP 3.2.4

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: For Schleife mit großen Werten

Beitrag von siro »

Ihr habt ja Ideen... :wink:
aber durch das rumprobiern kommen ja immer wieder neue Erkentnisse:

so kannte ich das auch noch nicht:

Code: Alles auswählen

  s:='Das ist mir auch neu';
  s:=s[5..11];     // ist mir
Ich danke euch für die Kreativen Ideen.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: For Schleife mit großen Werten

Beitrag von Winni »

Hi!

Mit diesem Bereichstrick kann man sich ganz simple eine einfache Laufschrift bauen, ohne immer mit copy oder delete arbeiten zu müssen.

Man braucht einen Timer und ein Label:

Code: Alles auswählen

var
Lauf : String;
len : Integer; 


procedure TForm1.FormCreate(Sender: TObject);
begin
   Lauf := 'Dies ist eine lange Lauftschrift ';
   len := length(lauf);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
lauf := lauf[2..len]+Lauf[1];
//lauf := lauf[len] + lauf[1..len-1];  // rückwärts
Label1.Caption := lauf;
end;



Der Bereichstrick arbeitet mit allen arrays.
Z.B. wenn man nur einen Teil einer PolyLine zeichnen möchte:

Code: Alles auswählen

canvas.Polyline(PointArray[20..40]);
Winni

Antworten