PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++-Funktion nach Java ...


aths
2004-10-19, 14:06:09
// Berechnung von Determinanten anhand des Laplacschen Entwicklungssatzes
// aths 28.10.2001, aths@gmx.net
// Arne Seifert


// Ziel: Möglichst einfaches Programm schreiben
// Lösung: Rekursive Programmierung


#include <iostream.h> // für cin und cout

struct matrix { // Matrix:
double feld[20][20]; // mit einem feld(x,y)
int gr;} // und einer Größe
m1; // namens m1


matrix imatrix(void) { // Input einer Matrix
struct matrix mi; // Arbeits-Matrix anlegen
int x,y; // Zähl-Variablen
cout<<"Groesse: ";
cin>>mi.gr;
for (y=1;y<=mi.gr;y++) {
for (x=1;x<=mi.gr;x++) {
cout<<"("<<x<<":"<<y<<") ";
cin>>mi.feld[x][y]; // Wert speichern
}
cout<<endl;
}
return mi; // die eingegebene Matrix zurück liefern
}

void pmatrix(matrix m1) { // gibt eine Matrix aus
int a,b;
for (a=1;a<=m1.gr;a++) {
for (b=1;b<=m1.gr;b++) {
cout<<m1.feld[b][a]<<" ";
}
cout<<endl;
}
}

matrix umat(matrix m2,int s) { // Erzeugt einer Untermatrix
struct matrix me; // Ergebnis-Matrix
int i,j,a; // Zähl-Variablen
me.gr=m2.gr-1; // Grösse um 1 reduzieren
for (i=2;i<=m2.gr;i++) { a=0; // Alle Spalten ab x=2 durchgehen
for (j=1;j<=m2.gr;j++) { // und die Zeilen
if (j!=s) // wenn nicht die Zeile, die gestrichen werden soll...
{a++;me.feld[i-1][a]=m2.feld[i][j];}
// dann den Inhalt übertragen
}
}
return me; // Die Ergebnismatrix zurück geben
}

double det(matrix m2) {
int a,b; // Laufvariablen und Adjunkte
double adj,e; // Ergebnis e
if (m2.gr==1) {return m2.feld[1][1];} // Wenn Größe=1 dann das Ergebnis direkt zurück liefern
e=0; // Das Ergebnis ist erstmal 0
for (a=1;a<=m2.gr;a++) { // für alle Zeilen...
adj=1;if (a%2==0) {adj=-1;} // Adjunkte für die 1. Spalte bestimmen
adj*=m2.feld[1][a]; // mit dem Faktor (Zahl nach der entwickelt wird) multiplizieren
e+=adj*det(umat(m2,a)); // zugehörige Unterdeterminante multiplizieren und auf e addieren
}
return e; // Das Ergebnis zurück geben
}




void main(void) { // HAUPTPROGRAMM
m1=imatrix(); // Matrix eingeben
pmatrix(m1); // und nochmal ausgeben
cout<<"-----------"<<endl;
cout<<det(m1)<<endl<<flush; // Die Determinante ausgeben
} // ENDDieses nette Programm würde ich gerne nach Java umschreiben. Außerdem soll es erweitert werden. Im Moment wird die Matrix ein- und die Determinante ausgegeben. Man soll dann aber die Matrix sowie einen Vektor eingeben, und die Determinantenberechnung wird genutzt um nach Cramerscher Regel das entsprechende Gleichungssystem zu lösen. Lange Rede, kurzer Sinn, ich müsste dies hier als Matrix-Klasse schreiben, Methoden sind Eingabe, Berechnung und Rückgabe (sowie eine später zu ergänzende Methode zur Manipulation von Spalten.)

Als Einstieg bräuchte ich aber nur obiges als Java-Programm. Am besten wäre, wenn die Matrix-Stuktur dynamisch wäre, statt fix [20][20]. Es muss kein komplett umgeschriebener Code sein, es würde reichen wenn mir jemand sagt was alles geändert werden muss.

HellHorse
2004-10-19, 14:47:47
Öhh? Irgendweie sehe ich das Problem nicht.


public class matrix {
double feld[][];
int gr;

static void pmatrix(matrix m1) {
....
}

static double det(matrix m2) {
....
}
}

Das kannst du so praktisch 1:1 konvertieren, mal von cout und cin abgesehen.

Wenn du mehr Aufwand willst kannst du die Matrix als Objekt kapseln und die statischen Methoden zu Instanzmethoden machen und Nameskonventionen einhalten. Aber irgendwie bezweifle ich das. ;)

aths
2004-10-19, 15:58:07
Öhh? Irgendweie sehe ich das Problem nicht.


public class matrix {
double feld[][];
int gr;

static void pmatrix(matrix m1) {
....
}

static double det(matrix m2) {
....
}
}

Das kannst du so praktisch 1:1 konvertieren, mal von cout und cin abgesehen.Bei Java muss man doch solche komischen Dings mit throws exception schreiben.

Wenn du mehr Aufwand willst kannst du die Matrix als Objekt kapseln und die statischen Methoden zu Instanzmethoden machen und Nameskonventionen einhalten. Aber irgendwie bezweifle ich das. ;)Matrix soll eine Klasse werden, die im späteren Hauptprogramm genutzt wird. Was ist jetzt der Unterschied zwischen statischen und Inzstanz-Methoden?

Was sind die wichtigsten Java-Namenskonventionen (abgesehen davon dass Klassen mit einem Großbuchstaben anfangen?)

HellHorse
2004-10-19, 16:10:14
Bei Java muss man doch solche komischen Dings mit throws exception schreiben.
Äh, nein. Bloss wenn du den Aufrufer zwingen willst die Exception zu behandeln oder selbst hättest welche benhandeln sollen, aber zu faul dazu warst.
Was ist jetzt der Unterschied zwischen statischen und Inzstanz-Methoden?
Das eine sind Methoden der Klasse, das andere des Objektes.

Was sind die wichtigsten Java-Namenskonventionen (abgesehen davon dass Klassen mit einem Großbuchstaben anfangen?)

Methoden mit kleinen Buchstaben beginnen, nachfolgede Wörter gross beginnen: eineMethode
Konstanten gross mit, Wörter mit _ getrennt: EINE_KONSTANTE
(Modifikatoren vor alles)

HellHorse
2004-10-22, 09:22:50
Da du anscheinend wirklich Pobleme hast, will ich mal nicht so sein.

public class matrix {

double feld[][]; // mit einem feld(x,y)
int gr; // und einer Größe

matrix() {
this(20);
}

matrix(int gr) {
feld = new double[gr][gr];
this.gr = gr;
}

static matrix imatrix() throws IOException { // Input einer Matrix
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Groesse: ");
int gr = Integer.parseInt(br.readLine());
matrix mi = new matrix(gr); // Arbeits-Matrix anlegen
for (int y = 0; y < gr; ++y) {
for (int x = 0; x < gr; ++x) {
System.out.print("("+x+":"+y+") ");
mi.feld[x][y] = Double.parseDouble(br.readLine());
}
System.out.println();
}
return mi; // die eingegebene Matrix zurück liefern
}

static void pmatrix(matrix m1) { // gibt eine Matrix aus
for (int a = 0; a < m1.gr; ++a) {
for (int b = 0; b < m1.gr; ++b) {
System.out.print(m1.feld[b][a]+" ");
}
System.out.println();
}
}

static matrix umat(matrix m2,int s) { // Erzeugt einer Untermatrix
matrix me = new matrix(m2.gr - 1); // Ergebnis-Matrix
int i,j,a; // Zähl-Variablen
for (i=1;i<m2.gr;i++) { a=0; // Alle Spalten ab x=2 durchgehen
for (j=0;j<m2.gr;j++) { // und die Zeilen
if (j!=s) // wenn nicht die Zeile, die gestrichen werden soll...
{me.feld[i-1][a]=m2.feld[i][j];a++;}// dann den Inhalt übertragen
}
}
return me;
}

static double det(matrix m2) {
int a; // Laufvariablen und Adjunkte
double adj,e; // Ergebnis e
if (m2.gr==1) {return m2.feld[0][0];} // Wenn Größe=1 dann das Ergebnis direkt zurück liefern
e=0; // Das Ergebnis ist erstmal 0
for (a=0;a<m2.gr;a++) { // für alle Zeilen...
adj=1;if (a%2==1) {adj=-1;} // Adjunkte für die 1. Spalte bestimmen
adj*=m2.feld[0][a]; // mit dem Faktor (Zahl nach der entwickelt wird) multiplizieren
e+=adj*det(umat(m2,a)); // zugehörige Unterdeterminante multiplizieren und auf e addieren
}
return e; // Das Ergebnis zurück geben
}

public static void main(String[] args) { // HAUPTPROGRAMM
try {
matrix m1= imatrix(); // Matrix eingeben
pmatrix(m1); // und nochmal ausgeben

System.out.println("-----------");
System.out.println(det(m1));
} catch (IOException e) {
System.out.println("Fehler beim Einlesen");
}
}
}

oops:
Die Indices scheinen off-by-1 zu sein. Ist aber schon im Original so.
*gefixt*

Indices in C (und in allen C Derivaten) sind 0 basierend.
Daher kann ich mir nicht vorstellen, dass der von dir gepostete Code funktionert. Ich kann mir nicht einmal vorstellen, dass er auf Linux ohne zu crashen läuft.

Dann sollte die Untermatrix wohl quadratisch sein.
Und der Code ist etwas besser formatiert.

Wie ich es ungefähr machen würde:

public class JavaMatrix {
private double data[][];

JavaMatrix() {
this(20);
}

JavaMatrix(int size) {
if (size <= 0) {
throw new IllegalArgumentException("parameter must be bigger than 0");
}
data = new double[size][size];
}

public static JavaMatrix readFromConsole() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Grösse: ");
int size = Integer.parseInt(br.readLine());
JavaMatrix matrix = new JavaMatrix(size);
for (int x = 0; x < size; ++x) {
for (int y = 0; y < size; ++y) {
System.out.print("("+x+":"+y+") ");
matrix.data[x][y] = Double.parseDouble(br.readLine());
}
System.out.println();
}
return matrix;
}

public int getSize() {
return this.data.length;
}

public String toString() {
int size = this.getSize();
// StringBuilder buffer = new StringBuilder();
StringBuffer buffer = new StringBuffer();
for (int x = 0; x < size; ++x) {
for (int y = 0; y < size ; ++y) {
buffer.append(this.data[x][y]);
buffer.append(" ");
}
buffer.append("\n");
}
return buffer.toString();
}

public JavaMatrix subMatrix(int except) {
int currentSize = this.getSize();
JavaMatrix result = new JavaMatrix(currentSize - 1);
int resultX = 0;
for (int thisX = 0; thisX < currentSize; ++thisX) {
if (thisX != except) {
for (int thisY = 1; thisY < currentSize; ++thisY) {
result.data[resultX][thisY - 1] = this.data[thisX][thisY];
}
resultX += 1;
}
}
return result;
}

public double determinant() {
if (this.getSize() == 1) {
return this.data[0][0];
}
double det = 0.0;
double subMatrixDet;
for (int x = 0; x < this.getSize(); ++x) {
subMatrixDet = this.data[x][0] * this.subMatrix(x).determinant();
if (x % 2 == 0) {
det += subMatrixDet;
} else {
det -= subMatrixDet;
}
}
return det;
}


public static void main(String[] args) {
try {
JavaMatrix matrix = readFromConsole();
System.out.println(matrix);

System.out.println("-----------");
System.out.println(matrix.determinant());
} catch (IOException e) {
System.out.println("Fehler beim Einlesen");
}
}

Hier ist eine Matrix als Objekt gekapselt. Wir haben nicht mehr ein struct von einem int und einem 2d int Array auf dem wir operieren, sondern ein Objekt vom Typ Matrix, dass die Dienste toString(), getSize(), determinant() und subMatrix() anbietet.
(Auch wenn hier schlussendlich das Gleiche passiert)
(ist eigentlich bei C++ das Gleiche, streng genommen hast du C++ als besseres C verwendet)

readFromConsole ist keine Instanzmethode sondern eine Klassenmethode, da es keinen Sinn macht wenn ein Matrix Objekt diesen Dienst anbietet. Man müsste dann auch zuerst eine Matrix kreieren um eine von der Konsole einzulesen.

Richtig sauber ist dieser Code allerdings auch nicht. Der Code ist immer noch sehr prozedural, es werden keine Accessoren verwendet oder bereitgestellt, die Fehlerbehandlung ist bloss minimal, Matrix lässt sich nicht von einem bel Stream einlesen, Test fehlen ..
Zudem fehlt jeglicher Kommentar inkl javadoc.

Daneben habe ich den Code noch so geändert, dass ich ihm für verständlicher halte.

aths
2004-10-22, 18:43:20
Hallo HellHorse,

der C++-Code lief mit GNU-Compiler auf Linux, immerhin habe ich den in Linux mit gcc (und mc als Editor) programmiert (ohne selbst Linux installiert zu haben, ein Bekannter gab mir ein Login für seine Kiste.)

Danke für den umgeschriebenen Code und die Kommentare, das gucke ich mir mal in Ruhe an, ob ich da verstehe was du da gemacht hast.

(ist eigentlich bei C++ das Gleiche, streng genommen hast du C++ als besseres C verwendet)Ja.

aths
2004-10-22, 19:21:46
IOExecption kennt mein Compiler (1.4.2.04) nicht.

Bei BufferedReader heult er auch rum ("Cannot resolve symbol".)

Coda
2004-10-22, 20:23:40
aths er hat aber schon recht, Indices fangen bei 0 an und enden bei n-1
Das ist ziemlich gefährlich was du da machst und kann zu äußerst zufälligen Crashes führen :/

Abe Ghiran
2004-10-22, 20:38:01
IOExecption kennt mein Compiler (1.4.2.04) nicht.
Bei BufferedReader heult er auch rum ("Cannot resolve symbol".)

Dann fehlt das passende Import Statement, denn diese Klassen liegen in einem extra package der java Bibliothek. Füge mal am Anfang der Datei, also noch vor "public class...",

import java.io.*;

hinzu, dann sollte sich das übersetzen lassen.

Grüße, Jan

aths
2004-10-22, 20:54:06
dann sollte sich das übersetzen lassen.Übersetzung klappt jetzt, doch bei der Ausführung gibt es sofort einen Fehler:

Exception in thread "main" java.lang.NoClassDefFoundError: matrix

Abe Ghiran
2004-10-22, 21:20:15
Exception in thread "main" java.lang.NoClassDefFoundError: matrix

Hmm, wie heißt deine .java Datei (die sollte matrix.java heißen)? Wie übersetzt du das (ich denke mal javac matrix.java)? Und wie führst du es aus (java matrix, ohne die Endung .class!)?

Bei mir klappt das nämlich einwandfrei.

Grüße, Jan

aths
2004-10-22, 21:34:24
Hmm, wie heißt deine .java Datei (die sollte matrix.java heißen)? Wie übersetzt du das (ich denke mal javac matrix.java)? Und wie führst du es aus (java matrix, ohne die Endung .class!)?So heißt sie, so übersetze ich sie, so führe ich sie aus (d. h., dann kommt ja gleich die Fehlermeldung.)

Komisch.

Welche JKD-Version hast du?

Abe Ghiran
2004-10-22, 21:56:01
Welche JKD-Version hast du?

1.4.2_01 aber das sollte keine große Rolle spielen. Ich hatte das eben mit Netbeans gemacht aber mir fällt da was ein: Es könnte auch sein, daß das aktuelle Verzeichnis in deinem classpath fehlt, dann findet java die Klasse auch nicht.
Probier mal "java -cp . matrix", um das Programm zu starten.

Grüße, Jan

aths
2004-10-22, 22:11:12
1.4.2_01 aber das sollte keine große Rolle spielen. Ich hatte das eben mit Netbeans gemacht aber mir fällt da was ein: Es könnte auch sein, daß das aktuelle Verzeichnis in deinem classpath fehlt, dann findet java die Klasse auch nicht.
Probier mal "java -cp . matrix", um das Programm zu starten.

Grüße, JanDann gehts. Danke :) dann kann ich jetzt das Programm untersuchen.

Coda
2004-10-23, 00:18:13
Ignorierst du uns eigentlich absichtlich? :confused:

aths
2004-10-23, 03:37:56
Ignorierst du uns eigentlich absichtlich? :confused:
:confused:

HellHorse
2004-10-23, 11:11:06
Ok aths, halt dich fest. Ich fand in diesem Beispiel Verwendung für Vererbung und Polymorphismus. :ugly:

Eigentlich ist die submatrix Methode recht schlecht. Es wird ein neues Array alloziert und die Werte kopiert. Das ist aber eigentlich gar nicht nötig, denn die Submatrix und eigentliche Matrix teilen die gleichen Daten. Zudem ist sie unverständlich und prozedural.

Was wäre also wenn wir eine leicht andere Form von Matrix machen könnten, die auf einer anderen Matrix basiert, eins kleiner ist, und die Indices transformiert? Dann müssten wir kein neues Array allozieren. Aber hey, wir haben Matrix als Objekt modelliert: wir können!
Wir machen zuerst eine neue Klasse AbstractMatrix, die das gemeinsame Verhalten von der alten und neuen Matrix enthält. Dann lassen wie alte und neue Klasse davon erben.
Und wenn wir gerade dabei sind könnten wir noch eine zweite spezielle Art von Matrix machen. Eine 1*1-Matrix, die bloss einen double enthält und diesen als Determinante zurückgibt.

Die Abstrakte Klasse.
Beachte die drei abstrakten Methoden um an die Grösse zu kommen und den Wert eines bestimmten Elements zu setzen oder holen. Konkrete Subklasssen werden diese dann später implementieren müssen.
Zudem ist submatrix nun wesentlich einfacher und determinant zumindest ein bisschen.
Und habe ich noch Zeugs zum benchen hinzugefügt.

import java.io.*;

public abstract class AbstractMatrix {

public static AbstractMatrix readFromStream(InputStream stream) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(stream));
System.out.print("Grösse: ");
int size = Integer.parseInt(br.readLine());
AbstractMatrix matrix = createMatrix(size);
for (int x = 0; x < size; ++x) {
for (int y = 0; y < size; ++y) {
System.out.print("("+x+":"+y+") ");
matrix.set(x, y, Double.parseDouble(br.readLine()));
}
System.out.println();
}
return matrix;
}

private static AbstractMatrix createMatrix(int size) {
if (size == 1) {
return new OneByOneMatrix();
} else {
return new ArrayMatrix(size);
}
}

public static AbstractMatrix readFromConsole() throws IOException {
return readFromStream(System.in);
}

public abstract int getSize();

public abstract double get(int x, int y);

public abstract void set(int x, int y, double val);

public AbstractMatrix subMatrix(int exceptX) {
if (this.getSize() > 2) {
return new SubMatrix(this, exceptX);
} else {
return new OneByOneMatrix(this.get(exceptX == 0 ? 1 : 0, 1));
}
}

public String toString() {
int size = this.getSize();
// StringBuilder buffer = new StringBuilder();
StringBuffer buffer = new StringBuffer();
for (int x = 0; x < size; ++x) {
for (int y = 0; y < size ; ++y) {
buffer.append(this.get(x, y));
buffer.append(' ');
}
buffer.append('\n');
}
return buffer.toString();
}

public double determinant() {
double det = 0.0;
double subMatrixDet;
for (int x = 0; x < this.getSize(); ++x) {
subMatrixDet = this.get(x, 0) * this.subMatrix(x).determinant();
if (x % 2 == 0) {
det += subMatrixDet;
} else {
det -= subMatrixDet;
}
}
return det;
}


public static void main(String[] args) {
try {
bench();
AbstractMatrix matrix = readFromConsole();
System.out.println(matrix);

System.out.println("-----------");
System.out.println(matrix.determinant());
} catch (IOException e) {
System.out.println("Fehler beim Einlesen");
}
}

public static void bench() {
try {
InputStream is = new ByteArrayInputStream(getBigInput());
AbstractMatrix matrix = readFromStream(is);
System.out.println();
System.out.println("done reading");
long startTime = System.currentTimeMillis();
matrix.determinant();
long endTime = System.currentTimeMillis();
System.out.println("time for new version: " + (endTime - startTime) + " ms");

is = new ByteArrayInputStream(getBigInput());
JavaMatrix jMatrix = JavaMatrix.readFromStream(is);
System.out.println("done reading");
startTime = System.currentTimeMillis();
jMatrix.determinant();
endTime = System.currentTimeMillis();
System.out.println("time for old version: " + (endTime - startTime) + " ms");
} catch (IOException e) {
e.printStackTrace();
}
}

public static byte[] getBigInput() {
// StringBuilder buffer = new StringBuilder();
StringBuffer buffer = new StringBuffer();
buffer.append(10);
buffer.append('\n');
for (int i = 1; i <= 100; ++i) {
buffer.append(i);
buffer.append('\n');
}
return buffer.toString().getBytes();
}
}


Die urspüngliche Matrix Klasse. Zudem umbenannt. Hier gibt es nicht mehr viel zu sehen.

public class ArrayMatrix extends AbstractMatrix {
private double data[][];

ArrayMatrix() {
this(20);
}

ArrayMatrix(int size) {
if (size <= 0) {
throw new IllegalArgumentException("parameter must be bigger than 0");
}
data = new double[size][size];
}

public int getSize() {
return this.data.length;
}

public double get(int x, int y) {
return this.data[x][y];
}

public void set(int x, int y, double val) {
this.data[x][y] = val;
}
}


Die neue Submatrix Klasse. Auch die ist sehr einfach.

public class SubMatrix extends AbstractMatrix {
private AbstractMatrix wrappedMatrix;
private int exceptX;

public SubMatrix(AbstractMatrix wrappedMatrix, int exceptX) {
this.wrappedMatrix = wrappedMatrix;
this.exceptX = exceptX;
}

public double get(int x, int y) {
return this.wrappedMatrix.get(this.translateX(x), y + 1);
}

public int getSize() {
return this.wrappedMatrix.getSize() - 1;
}

public void set(int x, int y, double val) {
this.wrappedMatrix.set(this.translateX(x), y + 1, val);
}

private int translateX(int x) {
if (x < this.exceptX) {
return x;
} else {
return x + 1;
}
}
}


Und zuletzt noch die 1x1-Matrix. Die einfachste von allen. Beachte wie wir auch determinant overridet haben.

public class OneByOneMatrix extends AbstractMatrix {
private double val;

public OneByOneMatrix(double val) {
this.val = val;
}

public OneByOneMatrix() {
this.val = 0.0;
}

public double get(int x, int y) {
return this.val;
}

public int getSize() {
return 1;
}

public void set(int x, int y, double val) {
this.val = val;
}

public double determinant() {
return this.val;
}
}


Was hat's sonst noch gebracht? Für eine Determinante einer 10*10 Matrix habe ich jetzt statt 4.7s noch 3.7s, immerhin.

Ich glaube du wärst wesentlich komfortabler mit einer IDE dran. Muss ja nicht gleich was "fettes" wie Eclipse, NetBeans, JBuilder, ... sein. Jedit tut's für den Anfang auch.

Falls ich dich nicht zu einer IDE überreden kann, dann nimm zumindest ein build-tool wie make oder ant.

ethrandil
2004-10-23, 11:41:07
Also, ich will ja nix sagen, aber vielleicht könnt ihr damit was anfangen, nur als Anregung:

http://java.sun.com/products/java-media/3D/forDevelopers/J3D_1_3_API/j3dapi/javax/vecmath/GMatrix.html

Implementierung:

http://svn.geotools.org/geotools/branches/fid-mm/vecmath/src/javax/vecmath/GMatrix.java

und ihr könntet ja eure Determinantenberechnung dazupacken.

- Eth

(btw: imho geht das implementierte über die spec hinaus, oder?)

HellHorse
2004-10-23, 12:02:50
der C++-Code lief mit GNU-Compiler auf Linux, immerhin habe ich den in Linux mit gcc (und mc als Editor) programmiert (ohne selbst Linux installiert zu haben, ein Bekannter gab mir ein Login für seine Kiste.)
Ja, mit einer 2x2 Matrix vielleicht.

Wenn ich ihm als Input
20
1
2
...
400
gebe, dann segfaultet er wie erwartet, da du deinen Stack korriumpierst.

Coda
2004-10-23, 23:27:48
Genau das meinte ich mit "ignorieren" aths. Der Code stimmt so einfach nicht. Arrays beginnen bei 0, nicht bei 1.

aths
2004-10-25, 00:58:06
Genau das meinte ich mit "ignorieren" aths. Der Code stimmt so einfach nicht. Arrays beginnen bei 0, nicht bei 1.Das hat das Höllenpferd doch schon längst gefixt :)