Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   qwertz543221 kleine String-Math-Lib (https://www.delphipraxis.net/135492-qwertz543221-kleine-string-math-lib.html)

qwertz543221 11. Jun 2009 18:54


Re: Langzahlen
 
Liste der Anhänge anzeigen (Anzahl: 1)
hier mal eine langzahl unit für + - * schnelle potenzen vergleiche und wurzeln

wer noch einen verschlag für die division hat, dem wäre ich sehr dankbar

gammatester 11. Jun 2009 21:01

Re: Langzahlen
 
Zitat:

Zitat von qwertz543221
hier mal eine langzahl unit für + - * schnelle potenzen vergleiche und wurzeln

wer noch einen verschlag für die division hat, dem wäre ich sehr dankbar

Normalerweise kritisiere ich solche Beiträge nicht so drastisch, aber das ist doch wohl ein programmierter Witz oder was? Was ist denn daran schnell, und was lang, und wieso steht das in diesem Thread? Beispiele:

schnelle potenzen: Odd/even-Entscheidung über modul(...,'2'), modul als Differenz mit Quotient*divisor, quotient über wiederholte Differenzen! Quotient liefert extended und keine Pseudolangzahl, etc ...

Und dann noch der übliche schlechte Programmierstil: Dialoge in solchen Units, Operationen als Methoden einer Form etc.

qwertz543221 11. Jun 2009 21:14

Re: Langzahlen
 
ich habe es hier hineingestellt, um anregungen für verbesserungen zu bekommen
das ganze soll nicht sonderlich kompliziert werden, nur funktionieren soll es.

die eingestellte version ist nur vorab, nachbesserungen am design werden getätigt, sobald alles so funktioniert wie es soll.

im moment fehlen mir noch ein effizienter quotient (hat mein vorredner schon angemerkt, dass das sehr schlecht ist bisher) und eine sqrt funktion...

himitsu 11. Jun 2009 21:17

Re: Langzahlen
 
Wenn er das mit der Bei Google suchenschriftlichen Division hinbekommt und alles auf Strings umbaut, wäre von meiner Seite aus die Geschwindigkeit zweitrangig,

da es so dann zumindestens mal eine für Anfänger leichter verständliche Version sein würde.
(wer es schnell mag, der kann ja DEC und Co. verwenden)

Aber erstmal wäre es hier gut, wenn alles konsequent auf Strings (bzw. auf ein einheitliches Zahlenformat) umgestellt
- die Extended-Parameter zwischendurch machen sich nicht so gut.
und in eine eigene Klasse in einer eigenen Unit ausgelagert würde,
zusammen mit einer "schönen" Codeformatierung.

qwertz543221 11. Jun 2009 21:22

Re: Langzahlen
 
ich habe bereits versucht, alles auf strings zu ändern, dann funktioniert das ganze jedoch nicht mehr
dies ist auch der grund wieso ich hier nach vorschlägen suche.


zur "normalen" schriftlichen division: hatte ich schon probiert, ist jedoch fehlgeschlagen, daher auch der umweg über das wenig elegante string / extended - gemisch.

himitsu 11. Jun 2009 21:43

Re: Langzahlen
 
Das einfachste ist erstmal alles das, was geht und schon einem einheitlichem Stil entspricht auszulagen und als eigene Klasse zusammennzufassen.

Dann die Grundfuntionen zum Laufen zu bekommen
und sich danach um Optimierungen und Erweiterunen zu kümmern.


Delphi-Quellcode:
function tform1.isOdd(const a: AnsiString): AnsiString; // modul(b, '2') <> '0'
begin
  Result := (a <> '') and (a[Length(a)] in ['1', '3', '5', '7', '9']);
end;

function tform1.isEven(const a: AnsiString): AnsiString; // modul(b, '2') = '0'
begin
  Result := (a = '') or (a[Length(a)] in ['0', '2', '4', '6', '8']);
end;



Delphi-Quellcode:
type TMathe = class
  function summe   (      a, b: AnsiString): AnsiString;
  function differenz(      a, b: AnsiString): AnsiString;
  procedure inc     (var  a:   AnsiString);
  procedure dec     (var  a:   AnsiString);

  function produkt (      a, b: AnsiString): AnsiString;
  function quotient (const a, b: AnsiString): AnsiString;
  function modul   (      a, b: AnsiString): AnsiString;

  function vergleich(      a, b: AnsiString): TValueRelationship;
  function ungerade (const a:   AnsiString): Boolean;
  function gerade  (const a:   AnsiString): Boolean;
end;
da wo intern der String nicht verändert wird, macht sich const besser
(hab es jetzt nicht bei allem gesetzt, da ich nicht weiß, ob es möglich ist)
siehe VAR CONST OUT und Co. ... warum?

Delphi-Quellcode:
var mathe: TMathe;
  a, b, c: AnsiString;

mathe := TMathe.Create;

a := '123';
b := '456';
c := mathe.summe(a, b);
if mathe.vergleich(c, '56088') = 0 then ...;

mathe.Free;

Ja, das mit der Division ist wirklich nicht leicht,
wenn ich bedenke, wie ich mich bei meiner Lib da abgequält hab :wall:

Im Prinzip kannst kannst du dich auch von hinten rum annähern
und dich von der anderen Seite aus, über Additionen oder Multiplikationen schrittweise annähern.

der Einachste und leider auch lagsamste Weg wäre
Delphi-Quellcode:
function TMathe.quotient(a, b: AnsiString): AnsiString;
begin
  result := '0';
  while vergleich(a, b) >= 0 do
  begin
    result := summe(result, '1');
    a := differenz(a, b);
  end;
end;

function TMathe.modul(const a, b: AnsiString): AnsiString;
begin
  result := a;
  while vergleich(result, b) >= 0 do
    result := differenz(result, b);
end;
also das sollte erstmal funktionieren
und über eine Multiplication sollte sich da noch was optimieren lassen.

gammatester 11. Jun 2009 21:50

Re: Langzahlen
 
Also verständlicher wird es auch mit komplett auf Strings umgestellten Code nicht. Es bleiben immer noch für solche Aufgaben katastrophale Mängel. Weitere Beispiele:

Verwendung von globalen Variablen für Zwischenergebnisse, application.ProcessMessages bei der Divission (wahrscheinlich weil sie sonst zu schnell wäre:), sonstige Bugs '00' > '1' weil length('00') > length('1') etc.

Meine Empfehlung an den OP: Versuch's erstmal mit der korrigierten Unit LZahl80, wenn die dann irgendwann nicht mehr ausreicht, zB Knuth's Seminumerical Algorithms (DAS ist verständlich) lesen und die Algorithmen programmieren.

mkinzler 11. Jun 2009 22:12

Re: qwertz543221 kleine String-Math-Lib
 
Ich habe diesen Thraed vom Thread http://www.delphipraxis.net/internal...t.php?t=158392 abgetrennt. dae er nur bedingt etwas mit dem ursprünglichen zu tun hat.

qwertz543221 11. Jun 2009 22:16

Re: qwertz543221 kleine String-Math-Lib
 
zur divisions-idee von himitsu:

den einfachen weg hatte ich schon versucht, leider waren die ergebnisse falsch oder er befand sich in einer endlosschleife.
geht das nicht auch anders?

himitsu 12. Jun 2009 10:02

Re: qwertz543221 kleine String-Math-Lib
 
Also nach der einfachen Methode sollte das Ergebnis aber zumindestens richtig sein und dem Ergebnis des DIV-Operators entsprechen.
Und Endlosschleife dürfte auch nicht ganz stimmen ... nur halt langsam, da womöglich viele Schleifendurchläufe nötig sind

z.B. 1000000 div 2 bzw. mathe.differenz('1000000', '2') benötigt so immerhin schon 500000 Durchläufe

Aber es ist einfacher wirklich erstmal aufzuräumen.
Es wird später sonst immer schwieriger, da es ja immer mehr und unübersichtlicher wird.

Der Vorteil der Klasse bzw. daran daß es in einer eigenen Unit liegt:
man kann es später auch mal in anderen Projekten wiederverwenden ... ist es direkt eingebaut, ist es nur da nutzbar, wo es eingebaut wurde.


Und ist dir schonmal aufgefallen, daß deine Funktionen nur positive ganze Zahlen mögen?


Wie schon von wem erwähnt:
Die beiden globalen Strings xa und xb haben da auch nix zu suchen, sie werden nur in der Funktion vergleich verwendet.
Ein sehr wichtiger Grund gegen soetwas sind z.B. mehrere Threads ... also wenn z.B. diese Funktion zweimal gleichzeitig in unterschiedlichen Threads verwendet wird, dann wollen beide Funktionen diese Variablen verwenden und "ärgern" sich gegenseitig. :twisted:

hier mal ein Vorschlag, für eine Basisklasse:
Delphi-Quellcode:
unit StringMathLib;

interface
  uses Types, SysUtils;

  type
    TMathe = class
      procedure normalisieren(var  a:   AnsiString);
      procedure formatieren (var  a:   AnsiString; tausenderPunkte, immerVorzeichen: Boolean; mindestlaenge: Integer = 0);

      function summe       (const a, b: AnsiString): AnsiString;
      function differenz   (const a, b: AnsiString): AnsiString;
      procedure plus1        (var  a:   AnsiString);
      procedure minus1       (var  a:   AnsiString);
      procedure negieren    (var  a:   AnsiString);

      function produkt     (const a, b: AnsiString): AnsiString;
      function quotient    (const a, b: AnsiString): AnsiString;
      function modul       (const a, b: AnsiString): AnsiString;
      procedure quotientModul(const a, b: AnsiString; var q, m: AnsiString);

      function vergleich   (const a, b: AnsiString): TValueRelationship;
      function istPositiv  (const a:   AnsiString): Boolean;
      function istNegativ  (const a:   AnsiString): Boolean;
      function istGerade   (const a:   AnsiString): Boolean;
      function istUngerade (const a:   AnsiString): Boolean;
    end;

implementation
  procedure TMathe.normalisieren(var a: AnsiString);
  var
    i: Integer;
    v: Boolean;
  begin
    a := Trim(a);
    for i := Length(a) downto 1 do
      if not (a[i] in ['0'..'9', ',', '-']) then
        Delete(a, i, 1);
    v := False;
    while (a <> '') and (a[1] = '-') do
    begin
      v := not v;
      Delete(a, 1, 1);
    end;
    for i := Length(a) downto 1 do
      if a[i] = '-' then
        Delete(a, i, 1);
    while (a <> '') and (a[1] = '0') do
      Delete(a, 1, 1);
    if a = '' then a := '0';
    if v then a := '-' + a;
  end;

  procedure TMathe.formatieren(var a: AnsiString;
    tausenderPunkte, immerVorzeichen: Boolean; mindestlaenge: Integer = 0);
  var
    i, i2: Integer;
  begin
    normalisieren(a);
    if (a <> '') and (a[1] = '-') then i2 := 2 else i2 := 1;
    i := Length(a) - 2;
    while i > i2 do begin
      Insert('.', a, i);
      Dec(i, 3);
    end;
    if i2 = 1 then
    begin
      Insert('+', a, 1);
      i2 := 2;
    end;
    while Length(a) < mindestlaenge do
      Insert('0', a, i2)
  end;

  procedure TMathe.angleichen(var a, b: AnsiString);
  begin

  end;

  function TMathe.summe(const a, b: AnsiString): AnsiString;
  begin

  end;

  function TMathe.differenz(const a, b: AnsiString): AnsiString;
  begin

  end;

  procedure TMathe.plus1(var a: AnsiString);
  begin

  end;

  procedure TMathe.minus1(var a: AnsiString);
  begin

  end;

  procedure TMathe.negieren(var a: AnsiString);
  begin
    normalisieren(a);
    if a[1] = '-' then
      Delete(a, 1, 1)
    else
      Insert('-', a, 1);
  end;

  function TMathe.produkt(const a, b: AnsiString): AnsiString;
  begin

  end;

  function TMathe.quotient(const a, b: AnsiString): AnsiString;
  var
    m: AnsiString;
  begin
    quotientModul(a, b, Result, m);
  end;

  function TMathe.modul(const a, b: AnsiString): AnsiString;
  var
    q: AnsiString;
  begin
    quotientModul(a, b, q, Result);
  end;

  procedure TMathe.quotientModul(const a, b: AnsiString; var q, m: AnsiString);
  begin

  end;

  function TMathe.vergleich(const a, b: AnsiString): TValueRelationship;
  begin

  end;

  function TMathe.istPositiv(const a: AnsiString): Boolean;
  begin
    normalisieren(a);
    Result := a[1] <> '-';
  end;

  function TMathe.istNegativ(const a: AnsiString): Boolean;
  begin
    normalisieren(a);
    Result := a[1] = '-';
  end;

  function TMathe.istGerade(const a: AnsiString): Boolean;
  begin
    normalisieren(a);
    Result := a[Length(a)] in ['0', '2', '4', '6', '8'];
  end;

  function TMathe.istUngerade(const a: AnsiString): Boolean;
  begin
    normalisieren(a);
    Result := a[Length(a)] in ['1', '3', '5', '7', '9'];
  end;

end.
und zur Verwendung: eine Instanz der Klasse anlegen und schon kann's losgehn
Delphi-Quellcode:
uses StringMathLib;

var
  mathe:  TMathe;
  a, b, c: AnsiString;

begin
  mathe := TMathe.Create;

  a := '123';
  b := '456';
  c := mathe.summe(a, b);
  if mathe.vergleich(c, '56088') = 0 then ;

  mathe.Free;
end;

himitsu 12. Jun 2009 10:38

Re: qwertz543221 kleine String-Math-Lib
 
kleines Beispiel:
Delphi-Quellcode:
function TMathe.summe(a, b: AnsiString): AnsiString;
var
  i, i2, ueberlauf, x: Integer;

begin
  normalisieren(a);
  normalisieren(b);
  if (a[1] = '-') <> (b[1] = '-') then
  begin
    negieren(b);
    Result := differenz(a, b);
    Exit;
  end;
  i2 := Max(Length(a), Length(b)) + 2; // +2 für Überlauf und Vorzeichen
  formatieren(a, False, True, i2);
  formatieren(b, False, True, i2);
  formatieren(Result, False, True, i2);
  ueberlauf := 0;
  for i := i2 downto 2 do
  begin
    x := (Ord(a[i]) - Ord('0')) + (Ord(b[i]) - Ord('0')) + ueberlauf;
    Result[i] := Chr(x mod 10 + Ord('0'));
    ueberlauf := x div 10;
  end;
  Result[1] := a[1]; // Vorzeichen
  normalisieren(Result);
end;
Hab mal das ganze ORD, CHR und sonstiges Umgerechne einfach durch diese Konstanten ersetzt.
Delphi-Quellcode:
const
  ZeichenZuZahl: Array['0'..'9'] of Byte = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
  ZahlZuZeichen: Array[0..9] of AnsiChar = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
Und nun sieht man, daß man mit einer etwas durchdachten und aufgeräumten Klassenstruktur sehr schön übersichtliche Codes entstehen lassen kann
Delphi-Quellcode:
function TMathe.summe(a, b: AnsiString): AnsiString;
var
  i, i2, ueberlauf, x: Integer;

begin
  normalisieren(a);
  normalisieren(b);
  if istNegativ(a[1]) <> istNegativ(b[1]) then
  begin
    negieren(b);
    Result := differenz(a, b);
    Exit;
  end;
  i2 := Max(Length(a), Length(b)) + 2; // +2 für Überlauf und Vorzeichen
  formatieren(a, False, True, i2);
  formatieren(b, False, True, i2);
  formatieren(Result, False, True, i2);
  ueberlauf := 0;
  for i := i2 downto 2 do
  begin
    x := ZeichenZuZahl[a[i]] + ZeichenZuZahl[b[i]] + ueberlauf;
    Result[i] := ZahlZuZeichen[x mod 10];
    ueberlauf := x div 10;
  end;
  Result[1] := a[1]; // Vorzeichen
  normalisieren(Result);
end;

qwertz543221 12. Jun 2009 11:07

Re: qwertz543221 kleine String-Math-Lib
 
vielen dank für die anmerkungen - ich werde es, sobald ich dazu komme, umsetzen.

=>bisher hat für mich nur gezählt, dass es die richtigen ergebnisse erzeugt.(Optimierungen sollten später kommen, sobald alles läuft) Da ich das ganze für RSA brauche, habe ich die Negation vernachlässigt.


Wie könnte ich denn die division darstellen, vlt schriftlich??, ohne durchprobieren zu müssen?

himitsu 12. Jun 2009 16:28

Re: qwertz543221 kleine String-Math-Lib
 
Zitat:

Zitat von qwertz543221
Wie könnte ich denn die division darstellen, vlt schriftlich??, ohne durchprobieren zu müssen?

na "fast" genauso, wie du es schriftlich auch machst


z.B.

456789 div 123


Zitat:

erstmal den Divisor auf die Stellenanzahl des Dividenden bringen
und gleichzeitig die Stellen zu merken

also

456789
123000
=3 verschobeneStellen

den Quotient mit 0 initialisieren

Schleife:

* * dann so oft wie möglich den neuen Divisor vom Dividend abziehen
* * * * (ohne mit dem Dividend in den negativen Bereich zu kommen)
* * * * parallel dazu das den Quotient um 10^verschobeneStellen erhöhen (dazuaddieren)

* * nun Dividend durch 10 (eine Stelle wieder entfernen)
* * verschobeneStellen minus 1

wenn verschobeneStellen größer 0, dann wiederhole die Schleife


Wenn die Zahlen noch Vorzeichen haben, dann diese am Anfang entferen
und wenn beide Zahlen unterschiedliche Vorzeichen hatten, dann das Ergebnis negieren.


Aber für "aufwändigere" cryptografische Dinge ist soeine Lib dann nicht unbedingt gut geeignet,
da sie halt "recht" langsam arbeitet.

Wenn du dir mal die andere Lib vom Dipl. Ernst Winter ansiehst, dann arbeitet diese bei jedem internem Rechenschritt 6 Dezimalstellen gleichzeitig ab und hier ist es jeweils nur Eine.
Bei meiner Lib sind es noch ein paar mehr, da ich direkt binär rechne und jedes Bit ausnutze
(siehe Hier im Forum suchenTBigInt)

Wenn du wirklich stark in Richtung Cryptography arbeiten willst, dann empfehle ich dir das DEC, denn diese Lib ist speziell für soetwas entwickelt wurden.


Was soeine String-Lib aber aus macht:
- sie ist sehr gut zu debuggen und vorallem von "Laien" dürfte verstanden werden, was da intern abläuft
- nja und die Zahlenlänge ist nahezu unbegrenzt ... eine "normale" Win32-Anwendung bekommt man locker eine Zahl mit einer Milliade Stellen :angel:
(ok, die verbraucht dann zwar auch fast 1 GB an Arbeitsspeicher, aber es paßt rein)

qwertz543221 12. Jun 2009 17:53

Re: qwertz543221 kleine String-Math-Lib
 
Danke für deine erläuterungen. ich werde das gleich mal testen.

die einfachheit ist gut, denn zu hochtrabend sollte das ganze ja nicht sein. das DEC schaue ich mir trotzdem einmal an, vlt finde ich dort etwas, das ich gebrauchen kann ( - und verstehe, was notwendig ist, um es auch ordnungsgemäß einzubinden;))

qwertz543221 12. Jun 2009 18:02

Re: qwertz543221 kleine String-Math-Lib
 
noch eine frage:
was meintest du hiermit

"parallel dazu das den Quotient um 10^verschobeneStellen erhöhen (dazuaddieren) "

qwertz543221 12. Jun 2009 18:16

Re: qwertz543221 kleine String-Math-Lib
 
meintest du das so??:

Delphi-Quellcode:
function tform1.quotient(a,b:ansistring):ansistring;
var
    stellen:longint;
begin
    result := '0';
    stellen:=0;
    while length(b)<length(a) do
    begin
        b:=b+'0';
        stellen:=stellen+1;
    end;

    while (vergleich(a,b)=0)and(stellen>0)do //divident >divisor
    begin
        result:=summe(result,floattostr(trunc(power(10,stellen))));
        a:=differenz(a,b);
    end;
    delete(a,length(a)-1,length(a));
    stellen:=stellen-1;
end;
[edit=mkinzler]Delphi-Tag eingefügt; Code eingerückt Mfg, mkinzler[/edit]

himitsu 12. Jun 2009 18:37

Re: qwertz543221 kleine String-Math-Lib
 
die innere Schleife etwas anders geordnet:
Zitat:

erstmal den Divisor auf die Stellenanzahl des Dividenden bringen
und gleichzeitig die Stellen zu merken

also

456789
123000
=3 verschobeneStellen

den Quotient mit 0 initialisieren

Schleife:

* * wenn neuer Divisor größer-gleich Dividend dann wiederhole Schleife2
* * * * (ohne mit dem Dividend in den negativen Bereich zu kommen)
* * * * den Quotient um 10^verschobeneStellen erhöhen (dazuaddieren)
* * ende Schleife2

* * nun Dividend durch 10 (eine Stelle wieder entfernen)
* * verschobeneStellen minus 1

wenn verschobeneStellen größer 0, dann wiederhole die Schleife
also im Prinzip das
Delphi-Quellcode:
Quotient := summe(Quotient, potenz(10, verschobeneStellen));

qwertz543221 12. Jun 2009 19:14

Re: qwertz543221 kleine String-Math-Lib
 
ich hab das einmal als qt erstellt, aber ich denke, ich habe deine anweisungen misverstanden. (ergo: es funktioniert nicht;))


Delphi-Quellcode:
function tform1.quotient(a,b:ansistring):ansistring;
var stellen:longint;

begin
  result := '0';
  stellen:=0;

  while length(b)<length(a) do
  begin
    b:=b+'0';
    stellen:=stellen+1;
  end;

  while stellen>0 do
  begin
    while vergleich(b,a)=0 do //b>a?
    result:=result+floattostr(trunc(power(10,stellen)));
    delete(a,length(a)-1,1);
    stellen:=stellen-1;
  end;

end;
[edit=mkinzler]Delphi-Tag eingefügt. Das nächste Mal bitte selber machen! Mfg, mkinzler[/edit]

himitsu 12. Jun 2009 19:51

Re: qwertz543221 kleine String-Math-Lib
 
Zitat:

Zitat von qwertz543221
Delphi-Quellcode:
result:=result+floattostr(trunc(power(10,stellen)));

keine String-Operation (das +), sondern deiner summe-Funktion ;)

Delphi-Quellcode:
// c = Stellen

function tform1.Quotient(a, b: AnsiString): AnsiString;
var
  c: Int64;
begin
  if b = '0' then System.Error(reDivByZero);
  Result := '0';
  c     := 0;
  while Length(b) < Length(a) do
  begin
    c := c + 1;
    b := b + '0'; // b := produkt(b, '10');
  end;
  while c >= 0 do
  begin
    while vergleich(b, a) <= 0 do
    begin
      Result := summe(Result, inttostr(trunc(power(10, c))));
      a := differenz(a, b);
    end;
    c := c div 10;           // a := quotient(a, '10');
    Delete(b, Length(b), 1); // b := quotient(b, '10');
  end;
end;
Aber durch deine wiederholte Vermischung mit Extended begrenzt du die maximale Rechengröße auf 19 Stellen.
In diesem Fall ist es zum Glück nur die Differenz zwischen Stellen von a und b,
aber über die ganze Lib gesehen, wird somit der die maximale Zahlengröße in (abgesehn von der Addition und Subtraktion) auf 19 Dezimalstellen begrenzt und man könnte genausogut mit direkt Int64 arbeiten.

Extended hat zwar einen sehr großen Wertebereich, aber nur 19-20 signifikante Stellen.
heißt: es sind nur die erst 19 bis 20 Stellen gepspeichert und alle nachfolgenden Stellen snd Aufgrund der internen Struktur undefiniert und von Rundungsfehlern überschattet.


Darum mußt du aufpassen, daß du wärend der Berechnungen bei deinem Zahlentyp bleibst und keine der "kleinen" Standardtypen verwendest:
Delphi-Quellcode:
// c = 10^Stellen

function tform1.Quotient(a, b: AnsiString): AnsiString;
var
  c: AnsiString;
begin
  if b = '0' then System.Error(reDivByZero);
  Result := '0';
  c     := '1';
  while Length(b) < Length(a) do
  begin
    c := c + '0'; // c := produkt(c, '10');
    b := b + '0'; // b := produkt(b, '10');
  end;
  while c <> '' do
  begin
    while vergleich(b, a) <= 0 do
    begin
      Result := summe(Result, c);
      a := differenz(a, b);
    end;
    Delete(c, Length(c), 1); // a := quotient(a, '10');
    Delete(b, Length(b), 1); // b := quotient(b, '10');
  end;
end;

qwertz543221 12. Jun 2009 21:49

Re: qwertz543221 kleine String-Math-Lib
 
ich habe deinen vorschlag ausprobiert. anscheinend sind meine anderen funktionen nicht dafür geeignet. - das ergebnis stimmt fast nie.

ich gebe mal die weiteren fkts mit, vlt versteckt sich dort ein fehler ( ich konnte keinen finden, da die fkts an sich ihren dienst ordnungsgemäß erfüllen)

-----------------------------------------------------------------------------------------------------
Delphi-Quellcode:
function summe(a,b:ansistring):ansistring;

var i,l:longint;
u:longint;

begin
//mit Nullen auffüllen:

l:=length(a);
while l<length(b) do
begin
a:='0'+a;
l:=l+1;
end;

l:=length(b);
if length(a)>length(b)
  then
while length(a)>length(b) do
begin
b:='0'+b;
l:=l+1;
end
 else
  if length(b)>length(a)
   then
   while length(b)>length(a) do
   begin
   a:='0'+a;
   l:=l+1;
   end;
u:=0;
//Maximallänge festlegen
if length(a)>=length(b)
  then i:=length(a)
    else i:=length(b);

while i>=1 do
begin
//addition a+b+u
result:=inttostr((strtoint(a[i])+strtoint(b[i])+u)mod 10)+result;
//berechnung u
u:=(u+strtoint(a[i])+strtoint(b[i]) )div 10;
i:=i-1;
end;

i:=1;
result:=inttostr(u)+result;
a:=result;
//führende '0' löschen
while a[1]='0' do
delete(a,1,1);
result:=a;
end;

function differenz(a,b:ansistring):ansistring;
var u,i,j,la,lb:longint;
c:ansistring;
  begin
  //zwei gleiche Zahlen:
  if a=b
  then result:='0'
  else
  //a>b?
if (vergleich(a,b)<>0 )and(a<>b)
  then
  begin
 showmessage('Subtraktion nicht möglich.');
  exit;
  end
    else
    begin
    //initialisieren
    result:='';
    la:=length(a);
    lb:=length(b);
    //anfangsübertrag setzen
    u:=0;
    j:=1;
    //mit nullen füllen
    if la<lb
      then
      while la<lb do
      begin
      a:='0'+a;
      la:=la+1;
      end
        else if lb<la
              then
              while length(a)>length(b) do
              begin
              b:='0'+b;
              lb:=lb+1;
              end;

//subtraktion beginnen - vgl. schriftliches rechnen
i:=length(b);
//von vorne nach hinten
while i>=1 do
begin
//übertrag?
if u=0
  then
  begin
  //neuen übertrag setzen
  if strtoint(a[i])<strtoint(b[i])
    then  u:=10
      else u:=0;
  // nächste stelle des ergebnisses berechnen
  result:=inttostr((strtoint(a[i])+u-strtoint(b[i]))mod 10)+result;
  end
    else
    begin
    //wenn übertrag vorhanden:
    if strtoint(a[i])<strtoint(b[i])+1
      then  u:=10
        else u:=0;
      //bei der nächten stelle eines subtrahieren,da übertrag; einerstelle zum ergebnis
      //hinzufügen
    result:=inttostr((strtoint(a[i])+u-1-strtoint(b[i])mod 10))+result
    end;
  i:=i-1;
  end;
//führende nullen löschen
c:=result;
while c[1]='0' do
delete(c,1,1);
result:=c
end;
end;
[edit=mkinzler]Delphi-Tag eingefügt Mfg, mkinzler[/edit]

mkinzler 12. Jun 2009 21:56

Re: qwertz543221 kleine String-Math-Lib
 
@qwertz543221: Die Aufforderung Delphi-Tags zu verwenden und den Code richtig einzurücken war ernst gemeint. Bitte mache dies in der Zukunft! :warn:

himitsu 13. Jun 2009 12:57

Re: qwertz543221 kleine String-Math-Lib
 
Die das letzte Quotient-Funktion entspricht etwa meiner ... nur etwas gekürzt

summe scheint schonmal richtig zu laufen
Und kann es sein, daß zugfällig diese Meldung angezeigt wird?
Denn dieses sollte immer "wahr" / True melden und auslösen, da hier A immer <> B ist.
Delphi-Quellcode:
  //zwei gleiche Zahlen:
  if a=b
  then result:='0'
  else
  //a>b?
if (vergleich(a,b)<>0 )and(a<>b)
  then
  begin
  showmessage('Subtraktion nicht möglich.');
  exit;
  end
//a>b? <> (vergleich(a,b)<>0 )and(a<>b)
Ich vermute mal du wolltes da ein > und nicht <> verwenden.
obwohl es bei dir eigentlich < sein müßte ... a<b, da dann ein negatives Ergebnis rauskommen täte.

Und warum einmal Stringvergleich und zusätzlich per Funktion?

Mein Tipp: einen Breakpoint setzen und dann intensive Nutzung der Taste F7 :angel:

himitsu 14. Jun 2009 06:09

Re: qwertz543221 kleine String-Math-Lib
 
Zitat:

Zitat von qwertz543221
Hallo himitsu,
leider habe ich deinen letzten beitrag nicht ganz nachvollziehen können.
Bei der Verwendung der subtr. fkt zur durchführung einer division befindet sich das programm in einer endlosschleife.

lad dochj mal ein komplettest Testprojekt hoch, damit man das Schleifchen auch mal sehen kann ... eigentlich sollte da ja keines sein :angel2:
Zitat:

Delphi-Quellcode:
//zwei gleiche Zahlen:
  if a=b
  then result:='0'
  else
  //a>b?
if (vergleich(a,b)<>0 )and(a<>b)
  then
  begin
  showmessage('Subtraktion nicht möglich.');
  exit;
  end

if a=b » brich ab, wenn gleich ... vergleich(a,b)<>0 bzw. a<>b » brich ab, wenn ungleich

also alles danach wird niemal abgearbeitet
Delphi-Quellcode:
if vergleich(a,b)<0
  then
Zitat:

Zitat von himitsu
Mein Tipp: einen Breakpoint setzen und dann intensive Nutzung der Taste F7 :angel:

auf die erste Zeile der Quotient-Funktion gehen F5 drücken,
dann mit F7 in Ruhe die Funktion abarbeiten
und dabei schauen was mit den ganzen Variablen passiert
dafür gibt es unter Strg+Alt+W ein Fenster, wo man Variablennamen eintragen kann
oder man höllt die Maus mal ein paar Sekündchen über eine Variable im Code und bekommt so ihren Inhalt angezeigt.

Zitat:

Zitat von qwertz543221
gibt es vlt einen effizienteren algorithmus zur modulo-bestimmung, dann bräuchte ich die division gar nicht?? - das ganze soll ja irgendwann für RSA dienen, bei dem die zahlen über alle normalen delphi-variablentypen hinausgehen.

Und das ist schon ein recht effektiver Algo dafür
gut, da es sich hier ja, aus Sicht des PCs um "alleinstehende" einzelne Dezimalzahlen handelt,
müssen wir diese halt auch komplett behandeln und dann jeweils um eine ganze verschieben.

Bei einer "rein" binären Lib, hätte man hier Bitweise gehen können und dann schön über shl die ganzen Bits verschieben können.

Problem ist halt, daß soeine auf Strings aufbauende Lib nunmal nicht ganz mit dem Wort Effizienz vereinbar ist.

qwertz543221 14. Jun 2009 11:42

Re: qwertz543221 kleine String-Math-Lib
 
Liste der Anhänge anzeigen (Anzahl: 1)
hallo, ich habe das projekt einmal als rar hochgeladen, dann kannst du es testen
vlt liegt es nur an einer kleinigkeit - das ist ja meistens so beim programmieren - oder ich habe deine vorschläge einfach falsch interpretiert.

mfG

himitsu 14. Jun 2009 14:45

Re: qwertz543221 kleine String-Math-Lib
 
OK, das kommt davon, wenn man bei seiner Vergleichsfunktion fernab von jeglichen Standards seine Rückgabewerte definiert ... hatte ganz übersehen, daß diese anders vergleicht.

mach mal aus dem
Delphi-Quellcode:
while vergleich(b, a) <= 0 do
dieses hier
Delphi-Quellcode:
while vergleich(b, a) >= 1 do
ich hoff das stimmt dann



standard:
0 a=b
-1 a<b
1 a>b

und zum Auswerten dann
Delphi-Quellcode:
if vergleich(a, b) < 0 then  a < b  if vergleich(a, b) = -1 then
if vergleich(a, b) <= 0 then  a <= b
if vergleich(a, b) = 0 then  a = b
if vergleich(a, b) >= 0 then  a >= b
if vergleich(a, b) > 0 then  a > b  if vergleich(a, b) = 1 then
if vergleich(a, b) <> 0 then  a <> b
du siehst ... so verhält sich dann a zu b wie "vergleich" zu 0

oder man nutzt bei seiner Vergleichs-Funktion das TValueRelationship aus der Unit Types
(wie vorher schonmal vorgeschlagen), dann fällt zusätzlich noch auf, daß auch sowas geht

Delphi-Quellcode:
if vergleich(a, b) = LessThanValue   then  a < b
if vergleich(a, b) <> GreaterThanValue then  a <= b
if vergleich(a, b) = EqualsValue     then  a = b
if vergleich(a, b) <> LessThanValue   then  a >= b
if vergleich(a, b) = GreaterThanValue then  a > b
if vergleich(a, b) <> EqualsValue     then  a <> b

himitsu 14. Jun 2009 18:23

Re: qwertz543221 kleine String-Math-Lib
 
also das sollte jetzt bei dir Laufen ...
Delphi-Quellcode:
function tform1.Quotient(a, b: AnsiString): AnsiString;
var
  c: Int64;
begin
  if b = '0' then System.Error(reDivByZero);
  Result := '0';
  c     := 0;
  while Length(b) < Length(a) do
  begin
    c := c + 1;
    b := b + '0'; // b := produkt(b, '10');
  end;
  while c >= 0 do
  begin
    while vergleich(b, a) <> 0 do
    begin
      Result := summe(Result, inttostr(trunc(power(10, c))));
      a := differenz(a, b);
    end;
    c := c - 1;
    Delete(b, Length(b), 1); // b := quotient(b, '10');
  end;
end;
es gibt nur ein Problem ...
die Funktion summe rechnet falsch ...
und zwar wenn man sie einzeln benutzt, dann 1+1=2
aber in der schleife 0+1=1 ... 1+1=21 ... 21+1=221 .....
da ich aber bei deiner Summenfunktion einfach nicht durchseh, mußt'e den Fehler da wohl selber finden (hat vielleicht was mit den gloablen Variablen zu tun? :gruebel: )

[add]
Problem gefunden ... du hast in Summe das result nicht initialisiert:!:
ein result:=''; vor der Berechnung liefert Abhilfe.

und noch einen Tipp: das result wurde auch in anderen Funktionen nicht initialisert :zwinker:


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:55 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz