AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Mathe mit Strings (die deutsche StringMatheLib ._. )
Thema durchsuchen
Ansicht
Themen-Optionen

Mathe mit Strings (die deutsche StringMatheLib ._. )

Ein Thema von himitsu · begonnen am 13. Jun 2009 · letzter Beitrag vom 8. Apr 2013
Antwort Antwort
Seite 8 von 10   « Erste     678 910      
Benutzerbild von himitsu
himitsu
Registriert seit: 11. Okt 2003
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:
[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 Bei Google suchen7zip umgestiegen (ist 60% kleiner)
Miniaturansicht angehängter Grafiken
demo_828.png  
Angehängte Dateien
Dateityp: 7z stringmathelib_131.7z (97,5 KB, 315x aufgerufen)
Dateityp: exe demo5_106.exe (566,0 KB, 165x aufgerufen)
Dateityp: 7z stringmathelib__154.7z (439,3 KB, 190x aufgerufen)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
 
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#71
  Alt 1. Jul 2009, 09:27
Zitat von xZise:
Naja ich weiß nicht Weil P10 macht mehr als an a eine 0 dran zuhängen. Weil P10 halt universell ist.
ein sinnvoller Grund für P10 ist, daß der "Rechenweg" dann "versändlicher" wäre,
(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:
// für c := a * b;
c := 0;
while b > 0 do
begin
  c := c + a;
  b := b - 1;
end;
so ähnlich sahen Produkt_langsam, QuotientModulo_langsam und Potenz_langsam aus

Zitat von xZise:
Aber ganz von der Hand zu weisen ist das Bestreben nach schnelleren Code ja auch nicht
ich hatte anfangs ja die "langsamen" Versionen noch als zusätzliche Extraversionen drin
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.
String ist ein Zeiger und per Ord würde man wohl den "Pointer" in einen Integer casten


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;
    ...
  Mit Zitat antworten Zitat
gammatester
 
#72
  Alt 1. Jul 2009, 11:37
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?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#73
  Alt 1. Jul 2009, 12:10
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)
Miniaturansicht angehängter Grafiken
unbenannt_172.png  
  Mit Zitat antworten Zitat
gammatester
 
#74
  Alt 1. Jul 2009, 12:13
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
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#75
  Alt 1. Jul 2009, 13:37
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
wie gesagt, mit D7 hatte ich keine großen Probleme
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:
// aus'm Konstruktor
SetzeOperator('+', opDavor, -1, nil);
SetzeOperator('-', opDavor, -1, nil);
SetzeOperator(',', opDazwischen, -1, nil);
SetzeOperator(';', opDazwischen, -1, nil);
Das ging auch anfangs gut, also wo ich die Werte noch direkt in das Array eingetragen hatte.
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
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#76
  Alt 1. Jul 2009, 17:42
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:
// 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
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
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)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#77
  Alt 1. Jul 2009, 18:59
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:
PotenzModulo(x,0,0) -> 1 statt Fehler
PotenzModulo(x,0,1) -> 1 statt 0
PotenzModulo(x,0,-1) -> 1 statt 0
diese Sonderfälle werden jetzt geprüft und behandelt
Negieren(0) -> -0 statt 0 Sonderfall 0 wird nun beachtet und nicht behandelt
Delphi-Quellcode:
Quotient(-0,-x) -> -0 statt 0
Produkt(-x,0) -> -0 statt 0
war auf den Fehler in Negieren zurückzuführen


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 ;
  Mit Zitat antworten Zitat
Benutzerbild von GPRSNerd
GPRSNerd

 
Delphi 10.4 Sydney
 
#78
  Alt 3. Jul 2009, 08:21
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
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#79
  Alt 3. Jul 2009, 10:19
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]
  Mit Zitat antworten Zitat
qwertz543221
 
#80
  Alt 3. Jul 2009, 16:31
entschuldige, aber bei welchem beitrag finde ich die aktuelle version deines meisterwerks
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 8 von 10   « Erste     678 910      


Forumregeln

Es 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

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:40 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