Einzelnen Beitrag anzeigen

Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#22

Re: Unbegrenzt viele Nachkommastellen

  Alt 11. Dez 2003, 13:40
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
  Mit Zitat antworten Zitat