Autor Beitrag
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Do 19.10.06 18:15 
Hallo,

ich hab mal aus Spaß eine HugeNum-Klasse gebastelt. Ja, ich weiß, nix wirklich neues.. ich hab halt grad nix besseres zu tun. Außerdem, man könnte ja was lernen...

Die Daten werden in einem array aus Ziffern der Basis 255 gehalten. Sie kann Nachkommastellen(Fixkomma) und Umwandeln in/aus 'Standard'-Datentypen von Delphi(Int64,Double). Soweit, so gut, aber mit der Umwandlung in/aus String komm ich nicht klar.

Man muss doch aus der Basis 255 erstmal 10 machen, und daraus dann Zeichen, richtig?
Nur: wie mach ich das? Irgendwie komm ich mit den Überträgen nicht klar. Es kommt immer nur Quatsch raus....

Ich häng mal die Unit an. Falls das mal was weltbewegendes wird, kann ich sie ja hier mal 'richtig' veröffentlichen.

ausblenden volle Höhe 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:
unit DUHugeNumber;

interface

uses SysUtils,Math;

const
  hnBase = high(byte);

type
  TBase255 = array of byte;

  THugeNumber = class
    IntPart,
    FracPart:TBase255;
    Sign:TValueSign;
  private
    function GetInt64: Int64;
    procedure SetInt64(const Value: Int64);
    function GetDouble: Double;
    procedure SetDouble(const Value: Double);
    function GetString: string;
    procedure SetString(const Value: string);
  public
    constructor Create;
    destructor Destroy; override;
    property AsInt64:Int64 read GetInt64 Write SetInt64;
    property AsDouble:Double read GetDouble write SetDouble;
    property AsString:string read GetString write SetString;
  end;

function HugeNumberNew:THugeNumber;

implementation

const
  Epsilon = 1E-15 * 1000;

function HugeNumberNew:THugeNumber;
begin
  Result:= THugeNumber.Create;
end;

function Power(Base,Exp:integer):double;
begin
  Result:= Math.IntPower(Base,Exp);
end;

// IntPower should return Int
// Also make the Compiler Check for Exp<0 (use Power() for this)
function IntPower(Base:integer; Exp:Cardinal):integer;
begin
  Result:= trunc(Math.IntPower(Base,Exp));
end;

{ THugeNumber }

constructor THugeNumber.Create;
begin
  inherited;
  SetLength(IntPart,0);
  SetLength(FracPart,0);
  Sign:= +1;
end;

destructor THugeNumber.Destroy;
begin
  SetLength(IntPart,0);
  SetLength(FracPart,0);
  inherited;
end;

function THugeNumber.GetInt64: Int64;
var i:integer;
begin
  Result:= 0;
  for i:= 0 to high(IntPart) do
    inc(Result,IntPart[i]*IntPower(hnBase,i));
  Result:= Result*Sign;
end;

procedure THugeNumber.SetInt64(const Value: Int64);
var v:int64;
    i:integer;
begin
  SetLength(FracPart,0);
  Sign:= Math.Sign(Value);
  v:= value*Sign;
  i:= 0;
  while v>0 do begin
    SetLength(IntPart,i+1);
    IntPart[i]:= v mod hnBase;
    v:=v div hnBase;
    inc(i);
  end;
end;

function THugeNumber.GetDouble: Double;
var i:integer;
begin
  Result:= 0;
  for i:= 0 to high(IntPart) do
    Result:= Result+IntPart[i]*IntPower(hnBase,i);
  for i:= 0 to high(FracPart) do
    Result:= Result+FracPart[i]*Power(hnBase,-(i+1));
  Result:= Result*Sign;
end;

procedure THugeNumber.SetDouble(const Value: Double);
var v,f:double;
    i:integer;
begin
  Sign:= Math.Sign(Value);
  v:= value*Sign;
  f:= frac(V);
  SetInt64(Trunc(v));

  i:= 0;
  while (f>epsilon) and (i<15do begin //max 15 stellen, mehr hat Double nicht!
    SetLength(FracPart,i+1);
    f:= f*hnBase;
    FracPart[i]:= trunc(f);
    f:= f-FracPart[i];
    inc(i);
  end;
end;

function THugeNumber.GetString: string;
Var
    X: Integer;
    carry,p:byte;
begin
  Result:= '';
  Carry:= 0;
  For X := 0 To High(IntPart) Do begin
    //Und nun???
  end;
end;

procedure THugeNumber.SetString(const Value: string);
var p,i:integer;
begin
  p:= pos('.',Value);                //Punkt suchen
  if p<0 then p:= pos(',',Value);    //oder Komma
  if p<0 then p:= length(Value);     //Keine Dezimalzahl
  for i:= p downto 1 do begin
    //gleiches Problem. Was tun???
  end;
end;

end.


Was ich weiß, ist, dass die SetLength-Aufrufe in den Schleifen Müll sind. Die kommen auch noch weg, aber der Einfachheit halber sind sie noch drin.

Grüße,
Sebastian

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Do 19.10.06 21:10 
Hallo,

wähle eine große Basis (8 Stellen=10^8 ->integer(Tziffer =integer statt byte))und wandele diese dann nach byte um.
Siehe Basisumwandlung.

Gruss Horst
Martok Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Do 19.10.06 23:01 
Den Code hatte ich mir in der Tat schonmal angeguckt.
Nur - so richtig werd ich nicht draus schlau.
Wenn du mal in Worten beschreiben könntest, was du da genau tust?
Trotzdem frag ich mich, was die größe der Basis damit zu tun hat :gruebel:
Übrigens: bisher ist der Code ja so geschrieben, dass das einfach zu ändern wäre. Habs mal getestet, ich kann die Basis bis auf MAX_DWORD anheben. Davon kann ich aber immer noch nicht in Strings und zurück umwandeln.

Vielleicht haben wir uns auch missverstanden. Ich möchte einen String der Form s:= '1234.4578' in eine solche Hugenum 'einfüttern' können. Im Moment mache ich als Notlösung hn.AsDouble:= StrToFloat(S);, womit aber der HugeNum-Vorteil weg ist...

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Fr 20.10.06 07:59 
Hallo,

also prinzipiell:
aus rcswww.urz.tu-dresde...uff/Inf1/17Okt03.pdf
...
Umwandlung aus Darstellung mit Ausgangsbasis in Darstellung mit
Zielbasis
Zwei Varianten m¨oglich:
1. Jede Stelle der Zahl mit dem Stellenwert in Zieldarstellung multiplizieren.
Beispiele:
– bin ! dez: 100112 = 1  24 +1  21 +1  20 = 16+2+1 = 19
– dez ! hex: 32710 = 364H+2AH+7 = 12CH+14H+7 =
147H
– dez ! oct: 32710 = 3144O+212O+7 = 454O+24O+7O =
507O
2. Zweite M¨oglichkeit:
(a) Zahl durch Zielbasis dividieren
(b) Rest ist niederwertigste Stelle des Ergebnisses
(c) Quotienten wieder durch Zielbasis dividieren
(d) Rest ist n¨achste Stelle des Ergebnisses
(e) Solange bis c fortsetzen bis Quotient = 0
.....
Ich benutze die erste Variante, indem ich parallel den Stellenwert im Zielsystem erzeuge.
ausblenden Delphi-Quelltext
1:
2:
3:
            {Dasselbe um Bas2^j zu erzeugen} 
if (Bas1 AND Vergleich)<>0 then 
  ADD_Feld(Summ1Feld^,Summ2Feld^,Feld2_Index,Bas2)

Statt multiplizeren nutze ich addieren und schieben, da ich so immer leicht in der Zielbasis bleibe.

grosse Zahl als String:
Z='1234567890123456789012345678901234567890.1234567890123456789012345678901234567890'
Z aufteilen in Vorkomma Vz und Nachkommaanteil Nz.
Vorkommaanteil in eine verarbeitbare Basis, die der Komputer schon selbst umwandeln kann (StrToInt)
Also eine 1o-er Potenz von p=1 bis 8. Eine grosse Basis wird sehr viel schneller von meinem Progeramm verarbeitet wie in dem Beitrag zu lesen.
Also aus dem String Vz von hinten nach vorne in Gruppen der Laenge p zerteilen, eventuell führende Nullen ergänzen.
Bei Basis 10 ist p = 1 und jede Ziffer waere in einem Byte von ZahlBasis10 zu speichern.
Diese kann man jetzt durch
BasKonv(10,256,ZahlBasis10,ZahlBasis256);
in die Basis 256 umwandeln.

Die Nachkommastellen umzuwandeln ist doch eine schöne Aufgabe...(Wie geht denn dass???? Basis1Zahl multiplizieren mit Basis2 und die Stellen vor dem Komma abtrennen,umwandeln nach Basis2 und eintragen... )

Gruss Horst