|
Antwort |
Jaaaaaaa, was soll ich sagen ...
» 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 » was es derzeit kann ... siehe hier:
Delphi-Quellcode:
// 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 Summe (a, b: String): String; Function Differenz (a, b: String): String; Procedure Plus1 (Var a: String); Procedure Minus1 (Var a: String); Procedure Negieren (Var a: String); Function Absolut (a: String): String; 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)
Code:
[edit2] wurde geändert
[s]Function TMathe.Potenz(a, b: MatheString): MatheString;
Begin Result := Potenz_langsam(a, b); End;[/s] 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. |
Delphi 12 Athens |
#71
Zitat von xZise:
Naja ich weiß nicht Weil P10 macht mehr als an a eine 0 dran zuhängen. Weil P10 halt universell ist.
(es ist ja eigentlich ein *10 und im Code sieht es nach +0 aus) nja und daß es sozusagen Insert, statt Concat (+) nutzt weißt du, was eine langsame Multiplikation ist?
Delphi-Quellcode:
so ähnlich sahen Produkt_langsam, QuotientModulo_langsam und Potenz_langsam aus
// für c := a * b;
c := 0; while b > 0 do begin c := c + a; b := b - 1; end;
Zitat von xZise:
Aber ganz von der Hand zu weisen ist das Bestreben nach schnelleren Code ja auch nicht
und nun existieren sie nur noch virtuell als Kommantare
Zitat von gammatester:
In Ord(TMatheParserFListe(Liste[i + 1].Operanden)[i3].Operand) wendest Du ord auf einen String. Kann mir eigentlich keine Delphiversion vorstellen, die das erlaubt.
sooo, nun müßte nur noch irgendwer alle möglichen restlichen Testfälle zusammenstellen
Delphi-Quellcode:
// Function StringMatheLib.UnitTest:
With TMathe.Create do Try _Test(Normalisieren( '123') = '123'); _Test(Normalisieren( '+123') = '123'); _Test(Normalisieren( '-123') = '-123'); _Test(Normalisieren('--123') = '123'); Try _Test(Normalisieren('a123') <> '123'); _Test(False); Except End; _Test(Formatieren('+1234567', False, False) = '1234567'); _Test(Formatieren('-1234567', False, False) = '-1234567'); _Test(Formatieren('+1234567', True, False) = '1.234.567'); _Test(Formatieren('-1234567', True, False) = '-1.234.567'); _Test(Formatieren('+1234567', True, True) = '+1.234.567'); _Test(Formatieren('-1234567', True, True) = '-1.234.567'); _Test(Formatieren('+1234567', True, False, 15) = '0000001.234.567'); _Test(Formatieren('+1234567', True, True, 15) = '+000001.234.567'); _Test(Formatieren('-1234567', True, False, 15) = '-000001.234.567'); _Test(Formatieren('-1234567', True, True, 15) = '-000001.234.567'); // //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; ... |
Zitat |
|
#72
Ohne nerven zu wollen, aber in beiden Zips ist die alte Version von StringMatheParser.pas (29.719 01.07.09 0:22) und der Fehler tritt bei mir immer noch auf. Da die Exes von heute 10Uhr sind, mußt Du sie doch irgendwie kompiliert haben!? Willst Du ernsthaft sagen, daß Dein Delphi die StringMatheParser aus den Zips ohne Fehler übersetzt?
|
Zitat |
Delphi 12 Athens |
#73
hab grad die Browsercache geleert, alles selber runtergeladen und vergleichen lassen ...
oben ist die aktuelle Version. hatte es getestet und kompilieren lassen und danach gepackt und hochgeladen. hab's auch grad nochmal (mit der Demo6) unter Delphi 7 versucht, und bis auf einige Sachen in den .DFMs, welche man ignorieren kann und dem Application.MainFormOnTaskbar:=True; in der .DPR lief es sofort (der Debugger bemängelt nur, zu recht, eine Exception im UnitTest, welche absichtlich ausgelößt und per Try-Except abgefangen wird) |
Zitat |
|
#74
Habe gerade von einem Kollegen erfahren, daß Uni-Code D2009 den Parser mit dem kritschen Teil zwar übersetzt, aber alle Funktion mit mehr als einem Argument scheinen nicht mehr zu funktioniern. (Wäre nach Deinem "Argument" auch kein Wunder, den der Ord(Pointer) wir wohl nie ',' oder so sein)
Edit: Seine Prä-2009-Versionen erzeugen den gleichen Fehler wie bei mir |
Zitat |
Delphi 12 Athens |
#75
Zitat:
[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 und in D2009 lief es sowieso werd' gleich nochma TDE versuchen wobei Ord(Pointer) eigentlich schon seit 10°° behoben sein sollte ich probier das mit den Parametern aber gleich nochmal aus. [edit] ok, da stimmt wirklich was nicht ... mal sehn was da los ist [/edit] [edit2] bin blöd, hab es nur in einem der zwei Parser geändert [/edit2] und ich hoff die Kompilerschalter, bei den Konstanten, funktionieren (in D7 ging es zumindestens), damit werden die Unicode-Versionen, wie Φ und π ausgeschlossen. [add] OK, erstmal hatte ich das Ord(Pointer)-Problem einmal übersehn und dann hatte ich doch vor Kurzem die Verwaltung der Operatoren, Konstanten und Funktionen überarbeitet und mit neuen Funktionen versehn, wie z.B. SetzeOperator. Nun wird intern z.B. das Komma nicht extra behandelt, sondern einfach zusammen mit den anderen Operatoren.
Delphi-Quellcode:
Das ging auch anfangs gut, also wo ich die Werte noch direkt in das Array eingetragen hatte.
// aus'm Konstruktor
SetzeOperator('+', opDavor, -1, nil); SetzeOperator('-', opDavor, -1, nil); SetzeOperator(',', opDazwischen, -1, nil); SetzeOperator(';', opDazwischen, -1, nil); Nun hat die SetzeOperator-Funktion die eigenschaft, daß sie einen Eintrag löscht, wenn keine Funktion (nil) übergeben wird und demnach nicht die "internen" Verwaltungs-Operatoren anlegte ... die fehlten also, wodurch eben auch kein Komma mehr erkannt wurde Download in #1 aktuelle Version v1.4 14:30 |
Zitat |
Delphi 12 Athens |
#76
Einen "kleinen" Fehler in der Division hab ich noch entdeckt, da wurde bei der letzen Umstellung ein Vergleich mit einem "falschen" Wert gemacht, welcher vorher zu früh auf "1" gesetzt wurde.
OK, da das nur die interne optimierung betraf, wurde zwar immernoch richtig gerechnet, aber leider wurde mit steigender Dezimalstellenanzahl (der Stellen-Differenz zwischen Divisor und Dividend) die Berechnung expotentiell zur Stellenanzahl verlangsamt Dann hab ich mal einige Stringoperationen beim Vergleich entfernt und wenn dann demnächst eine "neue" Normalisierungsfunktion vorhanden ist, wird bei bereits normalisierten Zahlen keine Stringoperation/-veränderung mehr erforderlich sein, also nur noch ein "reiner" Vergleich.
Delphi-Quellcode:
// vorher
Function TMathe.Vergleich(a, b: String): TValueRelationship; Begin _Formatieren(a, False, True); _Formatieren(b, False, True); If (a[1] = '-') and (b[1] = '+') Then Result := LessThanValue Else If (a[1] = '+') and (b[1] = '-') Then Result := GreaterThanValue // jetzt Function TMathe.Vergleich(a, b: String): TValueRelationship; Begin If _ImmerNormalisieren Then Begin _Normalisieren(a); _Normalisieren(b); End; If (a[1] = '-') and (b[1] <> '-') Then Result := LessThanValue Else If (a[1] <> '-') and (b[1] = '-') Then Result := GreaterThanValue Das Nachkommaproblem bei Potenz10, Produkt10 und Quotient10, im Fließkommaparser, ist jetzt behoben, aber für Potenz hab ich keine wirkliche Lösung, außer daß ich da wohl eine komplett eigene Potenz-Funktion (nur für den Parser) erstellen müßte, denn so wäre das nicht wirklich effektiv,
Delphi-Quellcode:
da dann abhängig von den Nachkommastellen ein sehr großes Zwischenergebnis entsteht ... also dieses wäre a*10^n ^ b*10^n = 20*10^100 ^ 50*10^100
// in Ganzzahl umwandeln
a := Trunc(a * (10 ^ n)); b := Trunc(b * (10 ^ n)); // rechnen Result := Mathe.Potenz(a, b); Result := Mathe.Quotient(Result, 10 ^ (n * b-1)); // wieder in natürlichen Zahl umwandeln (mit Komma) Result := Result / (10 ^ n); // n = Anzahl der Nachkommastellen 102 ^ 20^50 bei 100 Stellen nach'm Komma = statt einer 65-stelligen Zahl eine mit über 5e103 Dezimalstellen Nja, aber erstmal schau ich nach den Rechenfehlern, welche noch auf Seite 5 erwähnt wurden. [add]
Zitat:
[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) |
Zitat |
Delphi 12 Athens |
#77
ChangeLog [01.07.2009 20°° v1.5] - Rechenfehler aus #67 behoben Plus1(-1) -> -0 statt 0 dieses Problem tritt hier nicht auf (wie vermutzt, wird es durch die "Normalisierung" behandelt) eventuell lag es ja an einem Fehler der Normalisierung, welchen ich vorhin schon behoben hatten
Delphi-Quellcode:
diese Sonderfälle werden jetzt geprüft und behandelt
PotenzModulo(x,0,0) -> 1 statt Fehler
PotenzModulo(x,0,1) -> 1 statt 0 PotenzModulo(x,0,-1) -> 1 statt 0 Negieren(0) -> -0 statt 0 Sonderfall 0 wird nun beachtet und nicht behandelt
Delphi-Quellcode:
war auf den Fehler in Negieren zurückzuführen
Quotient(-0,-x) -> -0 statt 0
Produkt(-x,0) -> -0 statt 0 PS: laß dir mal im Debugger das e anzeigen ... vonwegen -0 gäbe es nicht
Delphi-Quellcode:
e := 0;
PByte(@e)[9] := $80; if e = 0 then ; |
Zitat |
Delphi 10.4 Sydney |
#78
Hallo himitsu,
bei deiner Demo1 werden jetzt bei allen Ausgaben, die keine Zahlen sind, Fehlermeldungen geworfen, a la "ungültige Zahl ""a ist größer als b"". Kann man das irgendwie abschalten oder habe ich was übersehen? Gruß, Stefan
Stefan
|
Zitat |
Delphi 12 Athens |
#79
OK, das hatte ich nicht beachtet
Ich schau gleich mal, aber ich hab 'ne Befürchtung Nach der Berechnung wird doch die Dezimalstellenanzahl ermittelt und mit angezeigt. Und ich denk mit jetzt einfach mal, daß dabei die "neue" Exception in der Zahlenprüfung zuschlägt -.-° (bis vor Kurzem wurden in der Normalisierung einfach stillschweigend alle ungültigen Zeichen gelöscht und nun gibt's halt 'ne Exception) ich glaub statt die Demo umzuschreiben, werd ich die Zählfunktion umschreiben und dort die Exception abfangen und dann "0" zurückgeben. Oder sollte ich lieber "-1" machen (gültige Zahlen haben immer mindestens eine Stelle) [add] hab doch die -1 genommen ChangeLog [03.07.2009 12°° v1.5] - Dezimalstellenfunktion mit Fehlerprüfung versehen und die Anzeige der Stellen in den Demos etwas umgestellt[/size] |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |