Autor Beitrag
GTA-Place
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
EE-Regisseur
Beiträge: 5248
Erhaltene Danke: 2

WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
BeitragVerfasst: So 27.11.05 11:00 
Die folgende Funktion hab ich zur Berechnung einer Wurzel auf X Stellen genau geschrieben.
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:
function GetSqrt(Number, Stellen: Integer): String;
var
  TempInt: Extended;
  EndZahl: Integer;
  TempStr: String;
  X, Y:    Integer;
begin
  TempStr := '1,';
  EndZahl := 0;

  // Vor Komma //
  X := 1;
  while (X < Number div 2AND (sqr(X) < Number) do
  begin
    TempStr := IntToStr(X - 1) + ',';
    inc(X);
  end;

  // Nach Komma //
  for X := 1 to Stellen do
  begin
    Y := 1;
    while (sqr(StrToFloat(TempStr + IntToStr(Y))) < Number) AND (Y < 10do
      inc(Y);
    EndZahl := Y - 1;

    TempStr := TempStr + IntToStr(EndZahl);
  end;

  Result := TempStr;
end;

Es werden 1000 Nachkommastellen in 31 Millisekunden (vor Optimierung: 47 Millisekunden).

Es gibt hier 2 Probleme:
1. Ich kann maximal 23 Stellen ausgeben (Extended) und die letzten Stellen sind nicht mehr korrekt.
2. Durch IntToStr und StrToInt geht eine Menge Zeit verloren.

Lösungen:
1. Hier werde ich mir die Unit von BenBe mal anschauen.
2. Das wollte ich euch jetzt Fragen, wie ich das ohne String löse.

Und bitte kommt mir nicht wieder mit irgendwelchen anderen Funktionen.
Ich möchte diese hier optimieren und nicht eine ganz anderen Funktion.

Danke
Gruß
GTA-Place

_________________
"Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 27.11.05 16:24 
Mit meiner Unit müsstest Du für beliebig viele Stellen der Wurzel BM_SquareRoot(BM_Multiply(BM_Power(10, AnzahlDerStellen*2), DeineZahl)) ausführen. Der Nenner zur Ausgabe wäre dann BM_Power(10, AnzahlDerStellen)

Zum optimieren deiner Funktion:
Ich hab da mal nen QB-Source. Den sollte man relativ einfach auf Großzahl-Arithmetik optimiert bekommen ...

Ist in QB programmiert, sollte aber ohne Probleme auf Delphi zu porten gehen.

ausblenden volle Höhe SQROOT.BAS
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:
Size = 100
DIM Orig(0 TO Size) AS INTEGER
DIM Res(0 TO Size) AS INTEGER
DIM Res2(0 TO Size) AS INTEGER
DIM Stat AS DOUBLE
DIM CurrRoot AS DOUBLE
DIM CorrectBy AS DOUBLE
DIM Power AS DOUBLE
DIM Delta AS DOUBLE

CLS
Comma = Size / 2 - 2
Orig(4 + 2 * Comma) = 2
Orig(3 + 2 * Comma) = 0
Orig(2 + 2 * Comma) = 0
Orig(1 + 2 * Comma) = 0
Orig(0 + 2 * Comma) = 0

FOR X = Size TO 0 STEP -1
    PRINT LTRIM$(STR$(Orig(X)));
    IF X = 2 * Comma THEN PRINT ".";
NEXT
PRINT

NR = INT(Size / 2)
NO = 2 * NR

DO
    Stat = 0
    FOR X = Size TO NO STEP -1
        Stat = 10 * Stat + Orig(X) - Res2(X)
    NEXT
    CurrRoot = 0
    FOR X = Size TO NR STEP -1
        CurrRoot = 10 * CurrRoot + Res(X)
    NEXT

    CurrRoot = CurrRoot + CurrRoot  'Verdoppeln

    CurrDigit = 0
    CurrDigit2 = 0
    CurrDigit2Diff = -1
    CorrectBy = 0
    IF Stat <> 0 THEN
        Delta = CurrRoot + 1
        DO WHILE (CurrDigit < 10)
            IF Stat < Delta THEN
                EXIT DO
            END IF

            Stat = Stat - Delta
            CorrectBy = CorrectBy + Delta
           
            CurrDigit = CurrDigit + 1
            CurrDigit2Diff = CurrDigit2Diff + 2
            CurrDigit2 = CurrDigit2 + CurrDigit2Diff
            Delta = CurrRoot + CurrDigit2Diff + 2
        LOOP
    END IF

    Res(NR) = CurrDigit

    FOR X = Size TO NR * 2 STEP -1
        Power = X - 2 * NR
        Power = 10 ^ Power
        DigitAdd = INT(CorrectBy / Power)
        CorrectBy = CorrectBy - DigitAdd * Power

        Res2(X) = Res2(X) + DigitAdd
        Y = X
        DO WHILE Res2(Y) > 9
            Res2(Y + 1) = Res2(Y + 1) + INT(Res2(Y) / 10)
            Res2(Y) = Res2(Y) MOD 10
            Y = Y + 1
        LOOP
    NEXT

    NR = NR - 1
    NO = NO - 2

    Stat = Stat - CurrDigit * CurrDigit
LOOP UNTIL NO < 0

FOR X = Size TO 0 STEP -1
    PRINT LTRIM$(STR$(Res(X)));
    IF X = Comma THEN PRINT ".";
NEXT
PRINT

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
GTA-Place Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
EE-Regisseur
Beiträge: 5248
Erhaltene Danke: 2

WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
BeitragVerfasst: Di 29.11.05 18:01 
Da meine Funktion falsch war bei z.B. sqr(4); oder höher, hab ich se korregiert und optimiert:

ausblenden 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:
function GetSqrt(Number: Extended; Stellen: Integer): String;
var
  TempStr: String;
  X, Y:    Integer;
begin
  X := 0;
  while (X < (Number / 2)) AND (sqr(X + 1) < Number + 1do
    inc(X);
  TempStr := IntToStr(X) + ',';

  for X := 1 to Stellen do
  begin
    Y := 9;
    while (sqr(StrToFloat(TempStr + IntToStr(Y))) > Number) AND (Y > 0do
      dec(Y);
    TempStr := TempStr + IntToStr(Y);

    if sqr(StrToFloat(TempStr)) = Number then
      Break;
  end;

  Result := TempStr;
end;

_________________
"Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)