» also ich weiß, es ist nicht sonderlich schnell, aber dafür seeeeeeeehr einfach aufgebaut
» es läuft mindestens ab Delphi 7 (drunter hab ich nicht getestet)
und auch für Delphi 2009 ist es geeignet
» man kann die Verwendung der Unit SysUtils abschalten (incl. der Unit Math, da diese die SysUtils verwendet, aber außer Max wird daraus eh nix verwendet)
» Zahlen mit theoretisch über 1 Milliarde Dezimalstellen sind möglich
» die Funktionen sind mit deutschsprachigen Namen versehn
» es steht unter MPL + (L)GPL
» Versionen: StringMatheLib.pas » Demo 1 » alle Funktionen in einer Klasse verpackt
StringMatheRec.pas » Demo 2 » in einem Record ("MatheString") verpackt und mit Operatoren versehen (ab D2006/TDE)
StringMatheVar.pas » Demo 4 » in einem Variant/"MatheVariant" verpackt und mit Operatoren versehen
StringMatheFloatRec.pas » Demo 3 » wie "MatheString" in einem Record ("MatheStringF") als Festkommazahl
StringMatheParser.pas » Demo 5 » ein kliner Mathe-Parser
// Normalisieren alle ungültigen und zusätzlichen Zeichen entfernen // Formatieren - // // Vergleich - // Vergleich - // istPositiv - // istNegativ - // istGerade - // istUngerade - // gibVorzeichen - // Dezimalstellen - // // Summe r = a + b // Differenz r = a - b // Plus1 a = a + 1 oder inc(a) // Minus1 a = a - 1 oder dec(a) // Negieren a = -a // Absolut if a < 0 then r = -a else r = a // // Produkt r = a * b // Quotient r = a div b // Modulo r = a mod b // QuotientModulo r = a div b und m = a mod b // // Quadrat r = a * a oder r = a ^ 2 // Quadratwurzel r = a ^ 1/2 // Quadratwurzel r = a ^ 1/2 und m = a - (a ^ 1/2) // Potenz r = a ^ b // Potenz10 r = 10 ^ b // // Quotient2 r = a div 2 // Produkt10 r = a * 10^b // Quotient10 r = a div 10^b // Modulo10 r = a mod 10^b // QuotientModulo10 r = a div 10^b und m = a mod 10^b // // SummeModulo r = (a + b) mod m // DifferenzModulo r = (a - b) mod m // ProduktModulo r = (a * b) mod m // PotenzModulo r = (a ^ b) mod m // // Zufall r = Random(von, bis)
Type MatheString = Type AnsiString;
TVergleich = (vUngleich, vKleiner, vKleinerGleich, vGleich, vGroesserGleich, vGroesser);
TMathe = Class Property ImmerNormalisieren: Boolean Read _ImmerNormalisieren Write _ImmerNormalisieren;
Function Normalisieren (a: String): String; Function Formatieren (a: String; TausenderPunkte, ImmerMitVorzeichen: Boolean; Mindestlaenge: Integer = 0): String;
Function Vergleich (a, b: String): TValueRelationship; Overload; Function Vergleich (a, b: String; Art: TVergleich): Boolean; Overload; Function istPositiv (a: String): Boolean; Function istNegativ (a: String): Boolean; Function istGerade (a: String): Boolean; Function istUngerade (a: String): Boolean; Function gibVorzeichen (a: String): Char; Function Dezimalstellen (a: String): Integer;
Function Produkt (a, b: String): String; Function Quotient (a, b: String): String; Function Modulo (a, b: String): String; Procedure QuotientModulo (a, b: String; Var Result, Rest: String);
Function Quadrat (a: String): String; Function Quadratwurzel (a: String): String; Procedure Quadratwurzel (a: String; Var Result, Rest: String); Function Potenz (a, b: String): String; Function Potenz10 ( b: String): String; Function Potenz10 ( b: Integer): String;
Function Quotient2 (a: String): String; Function Produkt10 (a, b: String): String; Function Produkt10 (a: String; b: Integer): String; Function Quotient10 (a, b: String): String; Function Quotient10 (a: String; b: Integer): String; Function Modulo10 (a, b: String): String; Function Modulo10 (a: String; b: Integer): String; Procedure QuotientModulo10(a, b: String; Var Result, Rest: String); Procedure QuotientModulo10(a: String; b: Integer; Var Result, Rest: String);
Function SummeModulo (a, b, m: String): String; Function DifferenzModulo (a, b, m: String): String; Function ProduktModulo (a, b, m: String): String; Function PotenzModulo (a, b, m: String): String;
Function zuInteger (a: String): LongInt; Function vonInteger (a: LongInt): String; Function zuCardinal (a: String): LongWord; Function vonCardinal (a: LongWord): String; Function zuInteger64 (a: String): Int64; Function vonInteger64 (a: Int64): String;
Function Produkt_langsam (a, b: String): String; Procedure QuotientModulo_langsam(a, b: String; Var Result, Rest: String); Function Potenz_langsam (a, b: String): String; End;
» wer die Parameter a und b vor Funktionsaufruf selber normalisiert (also z.B. mindestens einmal nach Eingabe der Werte), der kann .ImmerNormalisieren auf False setzen und es wird dann nicht ständig, beim Starten von Funktionen, durchgeführt ... es wird so also einen Hauch flotter.
Einen Tipp noch zum Schluß: versucht besser nicht eine "größere" Potenz zu berechnen!
(B also nicht zu groß wählen)
[s]Function TMathe.Potenz(a, b: MatheString): MatheString;
Begin
Result := Potenz_langsam(a, b);
End;[/s]
[edit2] wurde geändert
ChangeLog
[edit]
eine Auto-Refresh-CheckBox in den [berechnen]-Button gelegt
[16.06.2009 v1.0]
mit neuer Lizenz versehen (siehe oben)
[30.06.2009 11°° v1.1]
- einige Optimierungen
- Produkt10, Quotient10, Modulo10 und Co. hinzugefügt
- und der MatheParser kam auch dazu[
[30.06.2009 12°° v1.1]
- der Reinfolgefehler aus Beitrag #55 (Potenzen ala x^y^z) wurde behoben
[30.06.2009 12°° v1.1]
- der Reinfolgefehler aus Beitrag #55 (Potenzen ala x^y^z) wurde behoben
[30.06.2009 14°° v1.1]
- weitere Fehler behoben ... siehe #57+#58
- der Fehler bei den Klammern ist hoffentlich behoben #60
[30.06.2009 15:40 v1.1]
- Fehler im Parser #61
[30.06.2009 16:30 v1.2]
- der Mathe-Parser-Demo um einige Features erweitert (wie den Zwischenspeicher)
- Verwaltung der Konstanten, Funktionen und Operatoren erstellt (im Mathe-Parser)
[01.07.2009 00:30 v1.3]
- ein bissl aufgeräumt
- TMathe.Quadratwurzel, TMathe.PotenzModulo und abhängiges stark beschleunigt
- TMathe.Quotient2 eingeführt r := a div 2 (Grund für vorherigen Punkt)
- Demo6 erstellt = "Fließkomma"-Parser (alles mit # rechnet noch mit "falscher" Nachkommabehandlung)
[01.07.2009 10°° v1.3]
- Anfänge eines UnitTests eingefügt
- XPMan wieder entfernt (#67)
- Fehler behoben (#67 inkompatible Typen)
- TMathe.Produkt nach xZise #67 geändert
[01.07.2009 14²° v1.4]
- einige Dateien von UTF-8 nach Ansi konvertiert
- wegen #72 Version erhöht und alles neu kompiliert bzw. hochgeladen
- weitere Konstanten in die Parser eingefügt
[01.07.2009 14³° v1.4]
- Fehler bei internen Verwaltungsoperatoren behoben ... z.B. Komma wurde nicht erkannt
[01.07.2009 19°° v1.4]
- Verzögerungsfehler in Division entfernt, welcher die Rechenoptimierung abschaltete (#76)
- Vergleichsfunktion optimiert (#76)
- Potenz10, Produkt10 und Quotient10 in StringMatheParserFloat.pas berichtig und freigegeben (Nachkommastellenproblem #76)
[01.07.2009 20°° v1.5]
- Rechenfehler aus #67 behoben
[03.07.2009 12°° v1.5]
- Dezimalstellenfunktion mit Fehlerprüfung versehen und die Anzeiger der Stellen in den Demos etwas umgestellt (siehe #79..#81)
[03.07.2009 21³° v1.6]
- .Normalisieren und .Formatieren überarbeitet (#84)
- etwas aufgeräumt und die "InFile"-Hilfe erweitert
- doch wieder auf 7zip umgestiegen (ist 60% kleiner)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
function TMathe.ZahlNBereinigen(const ZahlN, BasisN: string): string; //Zahl-String zur Basis N von allen Zeichen bereinigen, die nicht zwischen // '0' und Chr(N) liegen var
i: Integer;
ZahlN_: string; begin
ZahlN_:=Uppercase(ZahlN); for i := Length(ZahlN_) downto 1 do//Rückwärts da sonst mehrfach hintereinander //auftretende nicht erlaubte Zeichen nicht korrigiert würden begin if ((_GetZahl(ZahlN_[i]) < 0) or (_GetZahl(ZahlN_[i]) >= StrToInt(BasisN))) then
Delete(ZahlN_, i, 1); end;
Result:=ZahlN_; end;
Zum einen musst du ein Vorzeichen ignorieren und zum anderen, würde ich _GetZahl puffern und StrToInt auch (da aber außerhalb der schleife).
function TMathe.ZahlNBereinigen(const ZahlN, BasisN: string): string; //Zahl-String zur Basis N von allen Zeichen bereinigen, die nicht zwischen // '0' und Chr(N) liegen var
ZahlN_: string;
i, Ziffer, BasisInt, StartZeichen : Integer; begin
ZahlN_:=Uppercase(ZahlN); if Ord(a[1]) in [Ord('+'), Ord('-')] then
StartZeichen := 2 else
StartZeichen := 1;
BasisInt := StrToInt(BasisN);
// Rückwärtige Schleife, da der String hinter der aktuellen Position // verkürzt wird for i := Length(ZahlN_) downto StartZeichen do begin
Ziffer := _GetZahl(ZahlN_[i]); if (Ziffer < 0) or (Ziffer >= BasisInt) then
Delete(ZahlN_, i, 1); end;
Result:=ZahlN_; end;
Zitat von himitsu:
Also im Prinzip sollte es so funktionieren - bei ImmerNormalisieren sowieso
Ich hab es eigentlich abschaltbar gemacht, falls man mit mehreren gekoppelten Berechnungen sich dieses sparren möchte, aber da sollte man dann vorher die "Eingabewerte" selber einmal manuell Normalisieren.
Naja, ich erwarte aber das Dezimalstellen('+12') mir immer 2 zurückgibt
Abgesehen davon müsste es eigentlich statt "a[Length(a)]" nur "a[1]" heißen.
über die Festtage habe ich mir Deinen MatheParser angeguckt und finde ihn sehr gelungen.
Bei kleinen Test ist mir aufgefallen, dass das Potenzieren mit "^" nicht so richtig funktioniert.
Zum einem muß wohl in Constructor TMatheParserF.Create;
der Operator von #^ zu ^ verändert werden.
Zum anderen läuft er sich in Function TMathe.Potenz
aber irgendwie fest. Die Loop-Schleife findet scheinbar irgenwie keinen Ausstieg. Vielleicht muß diese '1' normalisiert werden?
In dem Demo5 tritt der Fehler nicht auf. Gibt es schon eine Korrektur?
ICh weiß der Beitrag ist schon alt aber ich ärgere mich seit gestern mit einem Problem und diese unit hier hat das gleiche Problem.
Kann mir bitte jemand erklären warum matheparser anscheinend ein Problem hiermit haben: (25-20-4) Ergebnis ist dann 6
Aber warum?? Gebe ich das so in den Windowsrechner ein kommt 1 raus.
Andererseits kann Delphi aber dies richtig rechnen: (9*2/2-2)ebenso wie dies (5+3+1) dies kann er wieder nicht berechnen: (5-3-1) da bekommt er 3 raus.
Kann mir das bitte jemand erklären? Danke!
Andererseits kann Delphi aber dies richtig rechnen: (9*2/2-2)ebenso wie dies (5+3+1) dies kann er wieder nicht berechnen: (5-3-1) da bekommt er 3 raus.
Kann mir das bitte jemand erklären? Danke!
Wer ist 'Delphi' und wieso prüfst Du das nicht selbst? Also breakpoint setzen, Einzelschritt ausführen usw.
Beim einen Schritt stimmt es ab dem nächsten dann einfach nicht mehr. Das lässt sich nicht debuggen. Hat auch nicht unbedingt was mit dieser Lib zu tun, scheint eher ein grundsätzliches Problem zu sein. Vlt. antwortet noch jemand der das erklären kann.
Nach meinem Post habe ich mich länger mit Mathparsern, die es in der Delphi-Welt gibt, beschäftigt. Es gibt von diesen ca. 1 Mio., aber keinen der richtig funktioniert. Das kommt wahrscheinlich daher, dass alle heiß sind sich daran zu probieren dann aber nicht zu Ende gebracht werden.
Gefunden habe ich 2 Parser, die etwas taugen: Parser10 Mathparser als den Cindy-Components
Wobei -man glaubt es kaum- der Parser aus Cindy ca. 30% schneller ist als der Parser10, der als schnell gilt.
Beim einen Schritt stimmt es ab dem nächsten dann einfach nicht mehr. Das lässt sich nicht debuggen. Hat auch nicht unbedingt was mit dieser Lib zu tun, scheint eher ein grundsätzliches Problem zu sein. Vlt. antwortet noch jemand der das erklären kann.
Dann hast du ein Zauber-Delphi und wir haben das nicht ... ergo können wir das auch nicht erklären