apfloat und CLN sind um Längen besser zu benutzen als GMP. Aber all diesen Libraries ist eines gemeinsam, es sind Bibliotheken die sehr stark an das Denkkonzept von C/C++ anlehenen und darauf aufbauen. Aus meiner Sicht also unmodern und kompleziert.
Zitat:
Kennt einer was besseres?
Oder eine Library, die schon in Delphi übersetzt wurde?
Ja ich. Da ich selber eine solche Library von Grund auf entwickelt habe, in Delphi, finde ich naürlich meine Library wesentlich besser
Ich kann aber auch Fakten sprechen lassen.
- automatische Referenze Counting der Zahlenobjecte
- automatische Garbarge Colllection
- Typsicherheit
- Copy on Write Demand, also so wie es bei LongStrings der Fall ist
- völlig transparent für den benutzer, nicht wie bei GMP wo man sich um jeden Kleinktram selber kümmern muß
- super schnell, in weiten Teilen schneller als GMP, apfloat, CLN usw. Meine Implementation zur Berechnung von Pi ist auf Rang 3 der Weltliste.
- das
GUI bleibt über interne Idle-Cacllbacks bedienbar und jede langandauerende Berechnung kann ohne Problem abgebrochen werden
- Speichermanagement ist vollständig Threadsafe und jeder Thread benutzt interen seine eigene Speicherverwaltung, dies bedeutet das mehrere Threads absolut voneineander abgespaltet sind bis runter zur Speicherverwaltung (also kein Blocking und Konsorten nötig)
- die Gesamtperformance aller Operationen ist über einen weiten Zahlenbereich optimiert. D.h. egal ob man mit Zahlen ca. 4096 Bit groß in der Kryptographie üblich arbeitet oder ob man Pi auf Millionen Stellen berechnen will, die Berechnung sind alle hoch optimiert weil die besten bekannten Verfahren benutzt wurden.
Und hier mal der komplette Pi Berechnungs-Source, einmal die Methode der Chudnovski Brüder und einmal nach dem Arithmetischen Mittel.
Delphi-Quellcode:
procedure NPi_Fast_Chudnovsky(var R: IInteger; Decimals: Cardinal);
// Chudnovsky's brothers Ramanujan with binary splitting
// this code is most only 2-3 Times slower as the fastests special PI-programs
// Some optimizations can be done, but here i wanted a readable code.
// One way to made it faster (~2 times) could be to avoid NBinarySplitting() and its
// callback.
{
1 12 inf (-1)^n (6n)! (A+nB)
-- = ------ SUM: -------------------
pi C^1.5 n=0 (3n)! (n!)^3 C^(3n)
A=13591409 B=545140134 C=640320
a(n) = (A+nB)
p(n) = -1(6n-5)(6n-4)(6n-3)(6n-2)(n6-1)(6n)
b(n) = 1
q(n) = (3n-2)(3n-1)(3n)(n^3)(C^3)
}
const
k_A = 163096908; // 12 * 13591409
k_B = 6541681608; // 12 * 545140134
k_C = 53360; // 640320 / 12
k_D = 1728; // 12^3 = 24 * 72
k_E = 262537412640768000; // 1727 * k_C^3
procedure DoPI(N: Integer; var D: TIIntegerSplitData); register;
// the callback for binary splitting
// max. n < ~306783379 then 6n << MaxInt
// B[1] = 1, P[0] = 1, Q[0] = 1
// don't touch B,P[0],Q[0] because NIL interfaces are here assumed to value +1
begin
if N > 0 then
begin
NSet(D.A, k_B); // a = k_A + n * k_B
NMul(D.A, N);
NAdd(D.A, k_A);
NSet(D.P, 2 * N -1 );
NMul(D.P, 6 * N -1 );
NMul(D.P, -(6 * N -5)); // p = - (6*n -5) * (6*n -1)* (2*n -1)
NSet(D.Q, k_C); // q = 72(n * k_C)^3 // 72 * n^3 * k_C^3
NMul(D.Q, N);
NPow(D.Q, 3);
NMul(D.Q, 72);
end else
NSet(D.A, k_A); // A[0] = k_A
end;
var
P,Q: IInteger;
S: Cardinal;
begin
S := NBinarySplitting(P, Q, Trunc(Decimals / 14.181) +2, @DoPI, False); // decimal approximation is very roughly !!
NPow(R, 100, Decimals);
NMul(R, NInt(k_E));
NSqrt(R); // R = (k_C^3 * 12^3 * 100^Decimals)^(1/2) * Q / P
NMul(R, Q);
NShl(R, S);
NDiv(R, P); // R = R * Q / P = R / S
end;
procedure NPi_AGM(var R: IInteger; Decimals: Cardinal);
{ computation of Pi with Arithmetic-Geometric Mean
AGM start with:
a = 1, b = 1/Sqrt(2), t = 1/2, k = 1
iteration:
s = (a + b) / 2
d = a - s
d = d^2
a = s
s = s^2
t = t - d * 2^k
b = Sqrt(s - d)
k = k +1
final:
pi ~ (a + b)^2 / 2t }
var
A,B,D,T: IInteger;
W: Integer;
begin
Inc(Decimals, 3); // +3 digits reserve
NPow(R, 5, Decimals); // R = 5^Decimals
NShl(A, R, Decimals); // A = 10^Decimals
NShl(D, R, Decimals -1); // D = 10^(Decimals -1)^2
NSqr(D);
NSqr(B, A); // B = (10^Decimals^2 * 2)^0.5 div 2
NShl(B, 1);
NSqrt(B);
NShr(B, 1);
W := 0;
repeat
NAdd(T, A, B); // T = (A + B) div 2, new A
NShr(T, 1);
NMul(B, A); // B = (B * A)^0.5
NSqrt(B);
NSub(A, T); // A = (A - T)^2 * 2^W
NSqr(A);
NShl(A, W);
Inc(W);
NSub(D, A); // D = D - A
NSwp(A, T);
until NCmp(B, A) = 0;
NShr(D, Decimals);
NDiv(D, R);
NMul(D, 1000);
NSqr(R, A);
NDiv(R, D);
end;
IInteger ist der große Ganzzahl Typ, keine Allozierungen oder Deallozierungen sind nötig. Man arbeitet also mit IInteger'n so als wären es normale Integer Datentypen, obwohl sie enorm große Speicherbereiche dynamisch verwalten.
Ein Manko gibt es allerdings, bisher habe ich nicht die Zeit gefunden auch Fließkommazahlen zu implementieren. Es gibt also Vorzeichenbehaftete Ganzzahlen -> IInteger, Gebrochene Zahlen -> IRational, Modulare Polynome -> IPoly und alle nötigen Berchnungen in Elliptischen Kurven.
Gruß Hagen