GTA-Place - So 27.11.05 10:00
Titel: Wurzel einer Zahl auf X Stellen berechnen lassen.
Die folgende Funktion hab ich zur Berechnung einer Wurzel auf X Stellen genau geschrieben.
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;
X := 1; while (X < Number div 2) AND (sqr(X) < Number) do begin TempStr := IntToStr(X - 1) + ','; inc(X); end;
for X := 1 to Stellen do begin Y := 1; while (sqr(StrToFloat(TempStr + IntToStr(Y))) < Number) AND (Y < 10) do 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
BenBE - So 27.11.05 15: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.
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 |
GTA-Place - Di 29.11.05 17:01
Da meine Funktion falsch war bei z.B.
sqr(4); oder höher, hab ich se korregiert und optimiert:
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 + 1) do inc(X); TempStr := IntToStr(X) + ',';
for X := 1 to Stellen do begin Y := 9; while (sqr(StrToFloat(TempStr + IntToStr(Y))) > Number) AND (Y > 0) do dec(Y); TempStr := TempStr + IntToStr(Y);
if sqr(StrToFloat(TempStr)) = Number then Break; end;
Result := TempStr; end; |