Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Eigenen Variablentyp


Frolo - Mo 01.04.13 23:24
Titel: Eigenen Variablentyp
Hey,

mir ist, als ich nach dem Typ TColor folgende Seite aufgefallen: http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Graphics_TColor.html

Da wird der Typ ganz lapidar so definiert:

Delphi-Quelltext
1:
TColor = -$7FFFFFFF-1..$7FFFFFFF;                    


Jetzt kamen mir ein paar Fragen auf:

1. Kann ich jetzt einen Typen TVeryLongInt = -$FFFFFFFFFFFFFFFFFFFFFFF..$FFFFFFFFFFFFFFFFFFFFFFF definieren?
2. Ich hab mir das immer so vorgestellt, dass ich einfach nur die Größe des Typs angebe, also zB. Char = $FF. Ich verstehe das - und .. nicht. Da wird irgendein Zahlenbereich angegeben oder? Nur was macht eine negative Zahl bei TColor für einen Sinn?
3. Warum 7F? Warum nicht einfach FF?
4. Was macht das -1 am Ende des ersten Elements?

Danke für eure Antworten :)


OlafSt - Di 02.04.13 00:07

Zu 1.) Ja, solange sich dein TVeryLongInt in irgendeinen bereits vordefinierten Variablentyp paßt. Der TColor paßt übrigens in einen integer.
Zu 2.) Korrekt erkannt, das ist ein Zahlenbereich. Betrachte die Zahlen mal Binär, dann wird das mit dem $7FFFFFFF schlagartig klar ;)
Zu 3.) Siehe 2a)
Zu 4.) Eins abziehen.


Frolo - Di 02.04.13 10:23

Ja okay, aber mir erschließt sich noch immer nicht, wieso man bei TColor nen negativen wert hat.. o: Vllt wäre es hilfreich, wenn ihr mir bei Integer zB zeigen könntet, wie zB -1 Hexadezimal bzw Binär aussieht :)

Außerdem ist es dann überhaupt möglich einen komplett neuen Zahlentyp mit sagen wir mal 16 Bytes zu "schaffen"?


knittel - Di 02.04.13 11:23

Also du wirst es nicht schaffen können zum Beispiel einen Int128 einzubauen, da dieser nicht in einen bekannten Variablentyp passt (Int64 ist der größte in Delphi).

Um das mit den -1 zu erklären:
Wir nehmen dafür als einfaches Beispiel einfach mal einen ShortInt (selbe größe wie ein Byte)

Der sieht dann binär so aus:
00000000

Dieser besteht aus 8 Bits. Folglich gibt es 2^8 verschiedene Einstellungsmöglichkeiten. Das wären ausgrechnet 256.
Bei einem unsigned Byte (nur positive Zahlen) wäre das 0..255 in Dezimal oder in Hexadezimal $0..$FF.
Da wir aber einen signed Byte haben, haben wir sowohl positive als auch negative Zahlen.
Folglich würde man erst annehmen das es dann folgende Zahlen gibt -127..127 oder in Hexadezimal $-7F..$7F
Wenn wir jetzt aber genau aufpassen, werden wir merken, dass wir nur 255 Möglichkeiten ausnutzen (2 * 127 + 1(Die Null)) obwohl wir 256 haben. Deswegen macht
man bei dem ersten Teil noch ein -1 davor, damit man dann die Zahlen von -128..127 hat.

Intern wird das nämlich meist (eigentlich immer) über einen Bias geregt. Der Bias wäre hier zum Beispiel -128. Daher wäre folgender Wert 01000000 -> umgerechnet 64 -> Bias dazurechnen (64 - 128) -> -64.


FaTaLGuiLLoTiNe - Di 02.04.13 11:42

user profile iconFrolo hat folgendes geschrieben Zum zitierten Posting springen:
Ja okay, aber mir erschließt sich noch immer nicht, wieso man bei TColor nen negativen wert hat..


Soweit ich weiss ist der negative Wertebereich von TColor für die Windows-Systemfarben reserviert.


Frolo - Di 02.04.13 12:52

Bleiben noch 2 Fragen offen:

die erste wäre:

1. Wie stellt man negative Zahlen in hexadezimaler oder binärer Form da? 1 wäre ja 01 bzw $01 nur was wäre dann -1?

2. Wenn ich jetzt nen Int128 unbedingt bräuchte (ist ja kein Variablentyp vorhanden). Kann ich mir so einen nicht einfach selbst schreiben? Im Endeffekt ist es doch "nur" ein größerer Speicherbereich im Arbeitsspeicher oder?


bummi - Di 02.04.13 13:21


Delphi-Quelltext
1:
2:
3:
4:
5:
var
 i:Integer;
begin
  For i := -5 to 5 do Memo1.Lines.Add (IntToHex(i,8) +'  -  ' + IntToStr(i));
end;


Wenn Du Dich an einem neuen Typen versuchen willst, kannst Du Dich ja mal da reinlesen http://docwiki.embarcadero.com/RADStudio/XE3/en/Operator_Overloading_(Delphi)


Blup - Di 02.04.13 13:48

1.)
Wird das erste Zeichen als Vorzeichen betrachtet, wird die Binär ohne Vorzeichen darstellbare größte Zahl zur -1 (alle Bits sind gesetzt):

Quelltext
1:
2:
3:
4:
Hexadezimal:                   $80 -      $FF,      $00 -      $7F
Binär:                    10000000 - 11111111, 00000000 - 01111111 
vorzeichenlos Dezimal:         128 -      255,        0 -      127 
vorzeichenbehaftete Dez.:     -128 -       -1,        0 -      127


2.)
Der Compiler kennt keine Operationen mit denen er solche Zahlen verarbeiten kann.
Aktuelle Compilerversionen erlauben aber die Definition eigener Operatoren für Records.

Kleines Beispiel zur Summierung sehr langer Zahlen:

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:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
unit BigNum;

interface

type
  TBigNum = record
    Count: Integer;
    Data: array of Longword;
    class operator Add(v1, v2: TBigNum): TBigNum;
    class operator Equal(v1, v2: TBigNum): Boolean;
    class operator Implicit(const v1: TBigNum): AnsiString;
    class operator Implicit(const v1: AnsiString): TBigNum;
    procedure Add(const v1: TBigNum);
  end;

implementation

uses
  SysUtils;

class operator TBigNum.Implicit(const v1: TBigNum): AnsiString;
var
  n: Integer;
  p: PByte;
  pc: PChar;
  b: Byte;
begin
  n := v1.Count;
  if n = 0 then
    Result := '0'
  else
  begin
    p := @(v1.Data[n div 8]);
    Inc(p, (n mod 8div 2);
    SetLength(Result, n);
    pc := @(Result[1]);

    if Odd(n) then
    begin
      b := p^;
      Dec(p);
      pc^ := Char(b + Ord('0'));
      Inc(pc);
      Dec(n);
    end;
    while n > 0 do
    begin
      b := p^;
      Dec(p);
      pc^ := Char((b div 10) + Ord('0'));
      Inc(pc);
      pc^ := Char((b mod 10) + Ord('0'));
      Inc(pc);
      Dec(n, 2);
    end;
  end;
end;

class operator TBigNum.Implicit(const v1: AnsiString): TBigNum;
var
  n1, n2, i: Integer;
  s: AnsiString;
  b: Byte;
  pb: PByte;
  pc: PChar;
{---}
  function NextCharValue: Byte;
  begin
    if n1 <= 0 then
      Result := 0
    else
    begin
      Result := Ord(pc^) - Ord('0');
      if not (Result in [0..9]) then
         raise Exception.Create('Ungültige Zeichenfolge');
      Dec(pc);
      Dec(n1);
    end
  end;
{---}
begin
  s := Trim(v1);
  n1 := Length(s);
  Result.Count := n1;
  try
    n2 := (n1 + 7div 8;
    if Length(Result.Data) < n2 then
      SetLength(Result.Data, n2);

    pc := @(s[n1]);
    pb := @(Result.Data[0]);
    for i := 0 to (n2 * 4) - 1 do
    begin
      b := NextCharValue;
      b := NextCharValue * 10 + b;
      pb^ := b;
      Inc(pb);
    end;
  except
    Result.Count := 0;
    raise;
  end;
end;

procedure TBigNum.Add(const v1: TBigNum);
{---}
  function GetValue(p: PByte; var n: Integer): Byte; inline;
  begin
    if n = 0 then
      Result := 0
    else
    begin
      Result := p^;
      Dec(n);
    end;
  end;
{---}
var
  p1, p2: PByte;
  n1, n2, n, i: Integer;
  b1, b2, c: Byte;
begin
  n1 := Count;
  n2 := v1.Count;
  if n1 > n2 then
    n := n1
  else
    n := n2;
  if n > Length(Data) then
    SetLength(Data, n);

  p1 := PByte(Data);
  p2 := PByte(v1.Data);
  c := 0;
  for i := 0 to n - 1 do
  begin
    b1 := GetValue(p1, n1);
    b2 := GetValue(p2, n2);
    b1 := b1 + b2 + c;
    c  := b1 div 100;
    b1 := b1 mod 100;
    p1^ := b1;
    Inc(p1);
    Inc(p2);
  end;
  {Übertrag neue Stelle}
  if c <> 0 then
  begin
    Inc(n);
    if n > Length(Data) then
      SetLength(Data, n);
    Data[n - 1] := c;
  end;
  Count := n;
end;

class operator TBigNum.Add(v1, v2: TBigNum): TBigNum;
begin
  Result.Data  := Copy(v1.Data);
  Result.Count := v1.Count;
  Result.Add(v2);
end;

class operator TBigNum.Equal(v1, v2: TBigNum): Boolean;
begin
  Result := (v1.Count = v2.Count) and
    CompareMem(Pointer(v1.Data), Pointer(v2.Data),
               v1.Count * SizeOf(v1.Data[0]));
end;



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
uses
  BigNum;

var
  a, b: TBigNum;
  c: string;
begin
  a := '1234567890123456789012345678901234567890123456789012345678901234567890';
  b := '0987654321098765432109876543210987654321098765432109876543210987654321';
  c := a + b;
  writeln(c);
end;


Frolo - Di 02.04.13 20:30

Vielen Dank für die Antworten. Ich hab nur die binäre Darstellung von negativen Zahlen nicht verstanden. Nehmen wir mal ein Byte und sagen es soll von -128 bis 127 gehen (ka ob das unsigned oder so heißt :D ) Wie sehen da zB -128, 0, -1, 1, 127 und 64 oder -64 aus? Ich brauch anscheinend Beispiele.

Bei positiven Werten ist das ja klar: Also Byte (0..255)

0 -> 0000 0000
1 -> 0000 0001
255 -> 1111 1111

Aber bei negativen :D


FinnO - Di 02.04.13 20:31

Moin,

schau mal hier:

http://de.wikipedia.org/wiki/Zweierkomplement

Gruß