Entwickler-Ecke

Sonstiges (Delphi) - Decimal Zahl zerlegen....


christoph - Mo 10.03.03 18:38
Titel: Decimal Zahl zerlegen....
Hi allerseits wie kann man eiine Dezimal Zahl zerlegen?? Also ich habe Zahl(Typ Single) vom wert 0,0 bis 200,0. Ich möchte das jetzt jeder einzel wert (in einen Integerwert gewandelt wird...

Also bei der Zahl 199,1 sollte das dann so aussehen
Integer1 =1
Integer2 =9
Integer3 =9
Integer4 =1

Wir kann man das in Dlphi verwirklichen ??

Vielen Dank für eure Hilfe schon mal im Vorraus.
Gruss Christoph


derDoc - Mo 10.03.03 18:53

Ich würde umständlich erst deine Zahl in eine String verwandeln und dann den String in ein array of String zerschneiden. Zum Schluss jeden Teil des Arrays wieder in einen Integer umwandeln.


Popov - Mo 10.03.03 20:29


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var
  i, k: Integer;
  s: String;
begin
  k := 199.1;
  s := IntToStr(Trunc(k));
  for i := 1 to Length(s) do ListBox1.Items.Add(s[i]);
end;


Ungeprüft

Ich hab die einzelnen Zahlen in eine ListBox eingefügt.

Moderiert von user profile iconKlabautermann: Code- durch Delphi-Tags ersetzt


Christian S. - Di 11.03.03 15:40

@Popov: Deinen Quelltext verstehe ich nicht. Mit Trunc verlierst Du aber doch Stellen, oder?

So könnte man es machen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
ziffern : ARRAY OF Integer;

implementation

{$R *.dfm}

procedure ziffern_suchen (zahl : Single);
VAR my_zahl : Integer;
begin
  while Trunc(zahl) <> zahl do zahl:=zahl*10;
  my_zahl :=Trunc(zahl);

  SetLength(ziffern,0);
  repeat
    SetLength(ziffern,Length(ziffern)+1);
    ziffern[High(ziffern)]:=(my_zahl mod 10);
    my_zahl:=my_zahl div 10;
  until my_zahl = 0;
end;


Du musst das Array dann nur noch einmal umkrempeln, damit Du die richtige Reihenfolge hast.

MfG,
Peter

Moderiert von user profile iconKlabautermann: Code- durch Delphi-Tags ersetzt


Udontknow - Di 11.03.03 16:13

Hier mal meine Variante (ohne Umkrempeln... :wink: ):


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
ziffern : ARRAY OF Integer; 

procedure ziffern_suchen (zahl : Single); 
VAR str:String
var i:integer;
begin 
  //Zahl in Str umwandeln
  Str:=FloatToStr(Zahl);

  //Komma herausnehmen
  Str:=StringReplace(Str,',','');

  //Grösse des Arrays festlegen
  SetLength(ziffern,Length(Str));

  //Array bestücken
  for i:=1 to Length(Str) do
    ziffern[i-1]:=StrToint(Str[i]);
end;

Cu, :)
Udontknow

Moderiert von user profile iconKlabautermann: Code- durch Delphi-Tags ersetzt


Christian S. - Di 11.03.03 16:35

Also, da das Array extrem klein bleiben wird, haben wir wohl kaum ein Speicher Problem. Die Geschwindigkeit habe ich mit diesem Quelltext getestet.


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:
procedure ziffern_suchen (zahl : Single);
VAR my_zahl,i : Integer;
    my_ziffern : Array of Integer;
begin
  while Trunc(zahl) <> zahl do zahl:=zahl*10;
  my_zahl :=Trunc(zahl);

  SetLength(my_ziffern,0);
  repeat
    SetLength(my_ziffern,Length(my_ziffern)+1);
    my_ziffern[High(my_ziffern)]:=(my_zahl mod 10);
    my_zahl:=my_zahl div 10;
  until my_zahl = 0;

  SetLength(ziffern,Length(my_ziffern));
  for i:=High(my_ziffern) TO 0 DO
  ziffern[High(ziffern)-i]:=my_ziffern[i];
end;


procedure ziffern_suchen_mit_str (zahl : Single);
VAR str:String;
var i:integer;
begin
  //Zahl in Str umwandeln
  Str:=FloatToStr(Zahl);

  //Komma herausnehmen
  Str:=StringReplace(Str,',','',[]);

  //Grösse des Arrays festlegen
  SetLength(ziffern,Length(Str));

  //Array bestücken
  for i:=1 to Length(Str) do
    ziffern[i-1]:=StrToint(Str[i]);
end;

procedure TForm1.Button1Click(Sender: TObject);
VAR zahl : Real;
    zeit1,zeit2,zeit,i : Integer;
begin
  zahl:=2.147483647;
  zeit1:=GetTickCount;
  for i:=0 TO 999999 DO ziffern_suchen(zahl);
  zeit2:=GetTickCount;
  ShowMessage(IntToStr(zeit2-zeit1));
  zeit1:=GetTickCount;
  for i:=0 TO 999999 DO ziffern_suchen_mit_str(zahl);
  zeit2:=GetTickCount;
  ShowMessage(IntToStr(zeit2-zeit1));
end;


Und da ist meiner schneller! Ätsch! :wink:

Aber mal ehrlich: ich würde Deinen Algorithmus nehmen, denn die paar paar Millisekunden, die meiner schneller ist, tausche ich gerne gegen die Übersichtlichkeit Deines Algorithmus' ein!

MfG,
Peter

<edit>Du hast editiert! Das ist gemein! </edit>

Moderiert von user profile iconKlabautermann: Code- durch Delphi-Tags ersetzt


Popov - Di 11.03.03 17:04

Peter Lustig hat folgendes geschrieben:
@Popov: Deinen Quelltext verstehe ich nicht. Mit Trunc verlierst Du aber doch Stellen, oder?


Jo. Ich hab wieder mal falsch gelesen und verstanden, daß der Wert vorher in einen Integer gewandelt wird.

Dann sieht mein Code so aus:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var 
  i: Integer;
  s: String;
begin
  s := FloatToStr(199.1);
  for i := 1 to Length(s) do if s[i] in ['0'..'9'then ListBox1.Items.Add(s[i]);
end;


Da ich D3 habe kenne ich mich nicht mit dynamische Arrays kaum aus, deshalb ListBox1. Aber ich versuch es mal:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
var
  i: Integer;
  s: String;
  x: array of Integer;
begin
  s := FloatToStr(199.1);
  for i := 1 to Length(s) do if not(s[i] in ['0'..'9']) then Delete(s, i, 1);

  SetLength(x, Length(s)-1);
  for i := 1 to Length(s) do x[i-1] := StrToInt(s[i]);
end;


In x[0] ist der erste Wert.

Alternativ könnte man in x[0] die MaxLänge reinschreinen. Der Vorteil wäre, daß man weiß welche Werte echt sind. Das würde dann so aussehen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
var
  i: Integer;
  s: String;
  x: array of Integer;
begin
  s := FloatToStr(199.1);
  for i := 1 to Length(s) do if not(s[i] in ['0'..'9']) then Delete(s, i, 1);

  SetLength(x, Length(s)+1);
  x[0] := Length(s);

  for i := 1 to Length(s) do x[i] := StrToInt(s[i]);
end;


Jetzt ist in x[1] ist der erste Wert.

Moderiert von user profile iconKlabautermann: Code- durch Delphi-Tags ersetzt


Udontknow - Di 11.03.03 17:30

@Peter Lustig:

Menno! :? :mrgreen: Dafür funzt mein Algo auch mit Zahlentypen, die nicht zu Integer zuweisungskompatibel sind. :) HCSTÄ!

Ich hatte mal irgendwo gelesen, daß, wenn man oft dynamischen Arrays neue Grössen gibt, es zu einer unnötigen Speicherreservierung kommt.

In diesem Falle reservierst du erst 4 Byte für einen Integerwert. Danach änderst du aber die Grösse auf 2 Integerwerte. Delphi muss nun fü den Array erneut vom Betriebssystem Speicher anfordern (und zwar für 8 Byte). Nun befindet sich der Array also an einem anderen Speicherbereich. Das ist aber noch lange kein Grund für Delphi, den vorigen Speicherbereich (der 4Byte groß war) an das Betriebssystem zurückzugeben. Stattdessen verweilt es in der Obhut eines Speicher-Managers, der im späteren Verlauf des Programmes diese 4 Byte für irgendetwas anderes zuteilen kann.
Delphi nimmt sich im Falle einer 5-Ziffer-Zahl also nicht 5*4 Byte an Speicher, sondern 1*4+2*4+3*4+4*4+5*4=(1+2+3+4+5)*4=60 Byte.

Für so kleine Dimensionen ist es natürlich irrelevant, ich habe aber schon Konstellationen gesehen, wo sich Programme über 300 MB Speicher zogen, nur weil die dynamische Größe von Arrays (oder auch TList-Instanzen, siehe Capacity) nicht einmal am Anfang, sondern immer wieder gestückelt erhöht wurde.

Das mit dem Speicher konnte ich nun leider nicht reproduzieren, aber die Leistung (Geschwindigkeit) einer Anwendung ist natürlich um einiges besser, wenn nur weniger Speicherzuweisungen erfolgen.

Cu, :)
Udontknow


Christian S. - Di 11.03.03 17:52

@Udontknow:
Hm, ich sehe, dass das sehr schnell zu einem Problem werden kann. Ich habe eine Art Hybrid aus Deinem und meinem Algorithmus gemacht. Er ist jetzt schneller als mein Erster und müllt den Speicher nicht mehr zu:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
procedure ziffern_suchen_hybrid (zahl : Single);
VAR my_zahl,i : Integer;
    my_ziffern : Array of Integer;
begin
  while Trunc(zahl) <> zahl do zahl:=zahl*10;
  my_zahl :=Trunc(zahl);

  SetLength(my_ziffern,Length(IntToStr(my_zahl))); //<-- da ist die Änderung
  repeat
    my_ziffern[High(my_ziffern)]:=(my_zahl mod 10);
    my_zahl:=my_zahl div 10;
  until my_zahl = 0;

  SetLength(ziffern,Length(my_ziffern));
  for i:=High(my_ziffern) TO 0 DO
  ziffern[High(ziffern)-i]:=my_ziffern[i];
end;


Folgendes ist jetzt die Rangliste der Geschwindigkeit:
die Mischung von udontknow's und meinem
mein erster
popovs
udontknow's

MfG,
Peter

MfG,
Peter

Moderiert von user profile iconKlabautermann: Code- durch Delphi-Tags ersetzt


Udontknow - Di 11.03.03 18:28

Na gut, da muss ich wohl nachziehen: :wink:


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:
procedure ziffern_suchen_mit_str2 (zahl : Single);
VAR str:String;
var i,j:integer;
var Laenge:Integer;
begin
  //Zahl in Str umwandeln
  Str:=FloatToStr(Zahl);

  //Laenge bestimmen
  Laenge:=Length(Str);
  if Pos(',',Str)>0 then
    Dec(Laenge);

  //Array-Laenge festlegen
  SetLength(Ziffern,Laenge);

  //Array bestücken
  j:=0;
  for i:=1 to Laenge do
  begin
    if Str[i]=',' then
      Continue;
    Ziffern[j]:=Ord((Str[i]))-48;
    Inc(j);
  end;
end;


BTW: Interessant ist, daß die zweite Prozedur langsamer ist, als wenn sie alleine läuft... :?:

Cu,
Udontknow

Moderiert von user profile iconKlabautermann: Code- durch Delphi-Tags ersetzt


christoph - Di 11.03.03 22:49

Himmel da hab ich aber ne Flut von Antworten bekommen..
Also erstmal ein riesen Dank für die Ganzen Antworten Hammer!!!!!
Hier nun mal mein Code.....
Wie gesagt zur erinnerung ich wollte ja jeweils dei einzelen Zahlen haben
nur ob das jetzt länger oder schneller geht wie euer Code müsste man testen....


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
procedure TForm1.Button1Click(Sender: TObject);
var
i1,i2,i3,i4,i5:word;
i             :Integer;
Zahl          :single;
begin
Zahl :=(strtofloat(Nummer.Text)*10);
i    :=trunc(zahl); 
divmod(i,10000,i1,i2);
Nr1.Value := i2;
 divmod(i,1000,i2,i3);
Nr2.Value := i3;
 divmod(i,100,i3,i4);
Nr3.Value := i4;
 divmod(i,10,i4,i5);
Nr4.Value := i5;
 end;


Grüsse Chris

Moderiert von user profile iconKlabautermann: Code- durch Delphi-Tags ersetzt


derDoc - Do 13.03.03 10:10

Ich glaube die Geschwindigkeitsunterschiede sind im geringen Bereich, dein Code sollte da aber ganz gut abschneiden. Wenn er läuft kannst du ihn doch benutzen. Die Millisekunden machen die Sau nicht fett.