derletztekick: in einer Methode zusammenfassen

Hi,

ich habe ein ganz kleines Programm in JAVA geschrieben, das mir 13 Parameter berechnet.

Diese gehören zu einem Objekt Clothoid. Der User kann einen Parameter eingeben und das Tool berechnet die zugehörigen 12 anderen. Problem ist, das man nur aus drei Parametern einen direkte Umkehrrechnung machen kann.
Sollte ein anderer Parameter gegeben sein, so löse ich das iterativ, wobei ich einen der drei direkten Parameter bestimme (in meinem Fall L) und dann eine normale Rechnung starte.

Das funktioniert auch alles, sieht aber augescheinlich recht Quick&Dirty aus und man kann erkennen, das gewisse Regelmäßigkeiten auftauchen, die ich gern zusammengefasst hätte.

Der User gibt einen der Paramert ein, die nur iterativ zu einer Lösung kommen, dann rechne ich durch Intervallverschiebung so:

  
  public void getParametersFromSigma(double value){  
    int loop = 0;  
    while (Math.abs(this.end_index - this.start_index)>this.tol && ++loop < stop_loop && this.end_index > this.start_index){  
      this.getParametersFromL( 0.5*(this.start_index + this.end_index) );  
      if (this.sigma > value){  
        this.end_index = 0.5*(this.start_index + this.end_index);  
      }  
      else if(this.sigma < value){  
        this.start_index = 0.5*(this.start_index + this.end_index);  
      }  
      else {  
        break;  
      }  
    }  
  }

Der User hat hier SIGMA eingegeben. Der Parameter L ist _immer_ der Parameter, auf den ich meine ganze Rechnung zurückführe. Mit L kann man also SIGMA berechnen aber nicht umgedreht. Ich habe eine obere und eine untere Grenze für L, die ich solange verschiebe, bis für mein L ein SIGMA kommt, das nahe an dem liegt, was der User eingegeben hat => Lösung.

Diese oben gezeigte Methode habe ich nun noch 9mal in meinem Dokument kopiert. Sie sieht für alle "indirekten" Parameter gleich aus zB für X:

  
  public void getParametersFromX(double value){  
    int loop = 0;  
    while (Math.abs(this.end_index - this.start_index)>this.tol && ++loop < stop_loop && this.end_index > this.start_index){  
      this.getParametersFromL( 0.5*(this.start_index + this.end_index) );  
      if (this.x > value){  
        this.end_index = 0.5*(this.start_index + this.end_index);  
      }  
      else if(this.x < value){  
        this.start_index = 0.5*(this.start_index + this.end_index);  
      }  
      else {  
        break;  
      }  
    }  
  }

usw.

Das einzige was sich ändert ist die Bedingung bzw. die Objektvariable, die eingehalten werden muss bspw.:
if (this.x > value){ } else if(this.x < value){ }
Diese Objektvariable wird in der Methode immer erst durch die Methode: getParametersFromL() erzeugt und ist vorher nicht bekannt; diese müsste ich irgendwie übergeben können. Die Methode müsste also "wissen", nach welchem Parameter sie iterativ eine Lösung sucht.

Ist es irgenwie möglich, statt immer wieder die Methode zu kopieren, eine allg. zu verfassen?

Auf java.de hat meine Frage bisher wenig Beachtung gehabt ;)

Micha

Mit freundlichem Gruß
Micha

--
LeagueEditor JavaScript :: simple Ligaverwaltung auf der Basis von JavaScript
  1. Hallo derletztekick,

    Also zuerst einmal würde es stark zur Übersichtlichkeit beitragen, wenn Du Dir überflüssige Verwenung von "this" sparst ;-)

    Wenn Du Deine Datenstruktur nicht verändern willst, musst Du irgendwie den Parameter, auf den zugegriffen werden soll, parametrisieren. Dafür gibt es im Wesentlichen zwei Lösungsmöglichkeiten:

    1. Annonyme Klasse und Interface:

      
    public static interface Parameter {  
      double getValue();  
    }  
      
    public void getParameters(double value, Parameter parameter){  
      int loop = 0;  
      while (Math.abs(end_index - start_index) > tol && ++loop < stop_loop && end_index > start_index) {  
        getParametersFromL(0.5 * (start_index + end_index));  
        if (parameter.getValue() > value) {  
          end_index = 0.5 * (start_index + end_index);  
        } else if (parameter.getValue() < value) {  
          start_index = 0.5 * (start_index + end_index);  
        } else {  
          break;  
        }  
      }  
    }  
      
    //Aufruf:  
    getParameters(value, new Parameter() {public double getValue() {return x}});  
    
    

    2. Reflection

      
    impor java.lang.reflection.Field;  
      
    public void getParameters(double value, Field parameter){  
      int loop = 0;  
      while (Math.abs(end_index - start_index) > tol && ++loop < stop_loop && end_index > start_index) {  
        getParametersFromL(0.5 * (start_index + end_index));  
        if (parameter.getDouble(this) > value) {  
          end_index = 0.5 * (start_index + end_index);  
        } else if (parameter.getDouble(this) < value) {  
          start_index = 0.5 * (start_index + end_index);  
        } else {  
          break;  
        }  
      }  
    }  
      
    //Aufruf:  
    getParameters(value, getClass().getField("x"));  
    
    

    Die andere (vermutlich elegantere) Möglichkeit ist, Parameter nicht als Felder zu definieren, sondern in einer Tabelle zu verwalten:

      
    import java.util.EnumMap;  
      
    public enum Parameter {X, Y, Z};  
      
    private EnumMap<Parameter, Double> parameter = new EnumMap<Parameter, Double>();  
      
    public void getParameters(double value, Parameter p){  
      int loop = 0;  
      while (Math.abs(end_index - start_index) > tol && ++loop < stop_loop && end_index > start_index) {  
        getParametersFromL(0.5 * (start_index + end_index));  
        if (parameter.get(p) > value) {  
          end_index = 0.5 * (start_index + end_index);  
        } else if (parameter.get(p) < value) {  
          start_index = 0.5 * (start_index + end_index);  
        } else {  
          break;  
        }  
      }  
    }  
      
    //Aufruf:  
    getParameters(value, Parameter.X);  
    
    

    Diese Variante kann man natürlich auch ohne Enumerationen realisieren, wenn man eine ältere Java-Version verwendet. Außerdem könnte man statt der EnumMap einen Array verwenden, falls man die Wrapper-Objekte vermeiden will. Das ist aber nur interessant, wenn mit diesen Parametern so viel gearbeitet wird, dass das Performancevorteile bringt.

    Grüße

    Daniel

    1. Hallo Daniel Thoma,

      zunächst Danke für Deine Antwort. Mein JAVA Wissen ist leider nicht so komplex und besteht mehr aus den Grundlagen und einer Menge Try-and-Error Versuchen, wenn ich das mal so zusammenfassen darf. Mit fällt es daher schwer, auch nur eine Deiner drei Möglichkeiten zu interpretieren...

      Also zuerst einmal würde es stark zur Übersichtlichkeit beitragen, wenn Du Dir überflüssige Verwenung von "this" sparst ;-)

      Ich hatte mal gehört/gelesen, das es sauberer wäre, ist dem nicht so?

      Wenn Du Deine Datenstruktur nicht verändern willst, musst Du irgendwie den Parameter, auf den zugegriffen werden soll, parametrisieren.

      Natürlich bin ich auch für eine Veränderung der Datenstruktur offen, da die Berechnung eher simple sind, wie Du an der Clothoid.class sehen kannst, in der ich Deinen 1. Vorschlag eingesetzt habe.

      Dein erster Vorschlag klang noch verständlich und sah augenscheinlich auch recht einfach aus - sah ;).

      1. Annonyme Klasse und Interface:

      public static interface Parameter {
        double getValue();
      }

      public void getParameters(double value, Parameter parameter){
        int loop = 0;
        while (Math.abs(end_index - start_index) > tol && ++loop < stop_loop && end_index > start_index) {
          getParametersFromL(0.5 * (start_index + end_index));
          if (parameter.getValue() > value) {
            end_index = 0.5 * (start_index + end_index);
          } else if (parameter.getValue() < value) {
            start_index = 0.5 * (start_index + end_index);
          } else {
            break;
          }
        }
      }

      //Aufruf:
      getParameters(value, new Parameter() {public double getValue() {return x}});

        
      Ich habe in der Class Deine Methode und die Änderung übernommen. In der main-Methode kann ich aber keinen Aufruf machen:  
        
      ~~~java
        
          Clothoid CD = new Clothoid();  
          CD.getParameters(0.005, new Parameter() {public double getValue() {return x;}});  
      
      

      Fehlermeldung:
      Compiliere C:\mclass.java mit Java-Compiler
      mclass.java:13: cannot find symbol
      symbol  : class Parameter
      location: class mclass
          CD.getParameters(0.005, new Parameter() {public double getValue() {return x;}});
                                      ^
      1 error

      Kannst Du mir da noch einen Tipp geben?

      Mit freundlichem Gruß
      Micha

      --
      LeagueEditor JavaScript :: simple Ligaverwaltung auf der Basis von JavaScript
      1. Hallo derletztekick,

        Ich hatte mal gehört/gelesen, das es sauberer wäre, ist dem nicht so?

        Letzten Endes ist das wohl geschmackssache. Wenn es missverständlich sein könnte oder wenn man gleichnamige lokale Parameter hat (was in Konstruktoren und set-Methoden durchaus üblich ist) ist es natrülich sinnvoll/notwendig this zu verwenden. Ansonsten wird der Code wenn viele Objekteigenschaften vor kommen dadurch länger und schwieriger auf einen Blick zu erfassen. Aber über solche Dinge kann man immer beliebig viel philosophieren.

        Ich habe in der Class Deine Methode und die Änderung übernommen. In der main-Methode kann ich aber keinen Aufruf machen:

        Das Interface ist innerhalb der Klasse definiert. Man könnte das natürlich auch außerhalb tun, da es aber nur im Zusammenhang mit dieser Klasse vorkommt, ist es geschickt, das mit in die Klasse zu packen.
        Das Interace musst Du dann von außen über die Klasse ansprechen mit "Clothoid.Parameter". Das Interface als static zu deklarieren, wie ich das gemacht habe, ist übrigens überflüssig, da das Interfaces immer sind. Bei inneren Klassen ist das allerdings anders.
        Wenn Du mehr mit Java machen willst, solltest Du Dir diese Konzepte mal in einem Java-Buch ansehen.

        Grüße

        Daniel

        1. Hallo Daniel Thoma,

          Das Interface ist innerhalb der Klasse definiert. Man könnte das natürlich auch außerhalb tun, da es aber nur im Zusammenhang mit dieser Klasse vorkommt, ist es geschickt, das mit in die Klasse zu packen.

          Ob es geschickt oder nicht ist, muss ich erstmal nachlesen, mir sagt es gar nichts und ich verlass mich da mal ein wenig auf Deine Erfahrung.

          Das Interace musst Du dann von außen über die Klasse ansprechen mit "Clothoid.Parameter".

          Das habe ich nun so gemacht:
          CD.getParameters(0.00000000112499602000, new Clothoid.Parameter() {public double getValue() {return Clothoid.delta_r;}});

          darüber hinaus müssten die Objektvariablen public static werden, danach ging es wie Du Dir das gedacht hattest ;)

          Wenn Du mehr mit Java machen willst, solltest Du Dir diese Konzepte mal in einem Java-Buch ansehen.

          Ich nutze für meine kleinen Programme vorranging das "JavaBuch" und das eBook "Java ist auch ein Insel", wobei ich bei diesem Problem nicht wusste, was ich als Suchbegriff nutzen soll um eine Lösung zu finden.

          Vielen Dank!

          Mit freundlichem Gruß
          Micha

          --
          LeagueEditor JavaScript :: simple Ligaverwaltung auf der Basis von JavaScript
          1. Hallo derletztekick,

            darüber hinaus müssten die Objektvariablen public static werden, danach ging es wie Du Dir das gedacht hattest ;)

            Nun, ich dachte natürlich daran, dass diese Klassen innerhalb des Objektes erzeugt werden. Die Eigenschaften statisch zu machen, ist eher keine gute Idee. Dann kannst Du ja nicht mehr mehrere Instanzen mit verschiedenen Parametern haben. Du solltest darauf dann natürlich über eine Objektreferenz zugreifen.

            Vorhin ist mir auch noch eingefallen, dass man das mit Enumerationen schön kombinieren und damit typsicher machen könnte auch ohne mit Arrays oder Maps statt Eigenschaften zu arbeiten.

              
            public class Clothoid {  
              
                private double x = 1;  
                private double y = 2;  
                private double z = 3;  
              
                public enum Parameter {  
                    X {  
                        double getValue(Clothoid obj) {  
                            return obj.x;  
                        }  
                    },  
                    Y {  
                        double getValue(Clothoid obj) {  
                            return obj.y;  
                        }  
                    },  
                    Z {  
                        double getValue(Clothoid obj) {  
                            return obj.z;  
                        }  
                    };  
                    abstract double getValue(Clothoid obj);  
                }  
              
                public double toWas(double d, Parameter p) {  
                    return d * p.getValue(this);  
                }  
              
            }  
              
            //Von außen kann man dann einfach so zugreifen:  
            public static void main(String[] argv) {  
                Clothoid c = new Clothoid();  
                for (Parameter p: Clothoid.Parameter.values()) {  
                    System.out.println(c.toWas(2, p));  
                }  
            }  
            
            

            Dieses Beispiel habe ich jetzt sogar getestet.

            Grüße

            Daniel

            1. Hallo Daniel Thoma,

              Die Eigenschaften statisch zu machen, ist eher keine gute Idee. Dann kannst Du ja nicht mehr mehrere Instanzen mit verschiedenen Parametern haben.

              Das ist in diesem Fall nicht nötig. Das (bisherige) Programm erwartet genau einen Eingabeparameter und berechnet die anderen - es ersetzt nur ein "unhandliches" Tabellenwerk (Klothoidentafel). Eine zweite Instanz ist hier nicht nötig könnte aber bei einem anderen Programm zukünftig mal von Bedeutung werden.

              Du solltest darauf dann natürlich über eine Objektreferenz zugreifen.

              Ich bin mir nicht sicher, was Du mir hier genau sagen möchtest. Ich vermute so etwas:
              public static double getX() { return x; }
              Wobei x ansich nicht static ist - trifft das meine Vermutung?

              Enumerationen

              Ich muss gestehen, dass ich das noch nie gehört habe und mir recht wenig darunter vorstellen kann. Dein gezeigtes Beispiel ist daher etwas schwer zu lesen. Es sieht so aus, als würde innerhalb der Klasse ein Objekt der selben Klasse erzeugt werden (sowas habe ich noch nie gemacht, das muss ja nichts heißen).

              ohne mit [...] Maps statt Eigenschaften zu arbeiten.

              Mir sagen auch Maps nicht wirklich was und ich kann mich auch nicht entsinnen, es schon einmal gelesen zu haben. Du dringst hier in Bereich vor,  wo ich nur Böhmische Dörfer sehe ;)

              Warum geht Clothoid.Parameter.values(); obwohl eine Methode values() gar nicht existiert? Um gezielt auf einen Parameter zu zugreifen wäre dann ein:
              Clothoid.Parameter.X.getValue() nötig?

              Ich merke gerade, wie wenig ich bisher eigentlich weiß und hoffe meine Fragen erscheinen nicht zu aufdringlich.

              Vielen Dank für die bisherigen, ausführlichen Antworten!

              Mit freundlichem Gruß
              Micha

              --
              LeagueEditor JavaScript :: simple Ligaverwaltung auf der Basis von JavaScript
              1. Hallo derletztekick,

                Du solltest darauf dann natürlich über eine Objektreferenz zugreifen.
                Ich vermute so etwas: [...]

                Nein, Du sollst nicht über den Klassennamen sondern über ein Objekt zugreifen also:

                new Clothoid.Parameter() {
                   public double getValue() {
                      return obj.x;
                   }
                }

                Du Rufst ja Deine Methode getParameters auch mit einer Instanz von Clothoid auf, also kannst Du auch deren Parameter x da zurückgeben.

                Enumerationen

                Ok, ich hätte das vielleicht besser mit "Aufzählungstyp" übersetzt. Siehe < http://de.wikipedia.org/wiki/Aufz%C3%A4hlungstyp>.
                Zu Aufzählungstypen in Java: < http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html>

                Es sieht so aus, als würde innerhalb der Klasse ein Objekt der selben Klasse erzeugt werden (sowas habe ich noch nie gemacht, das muss ja nichts heißen).

                Ja, im Prinzip macht der Kompiler etwas ähnliches. Wobei wohl auch gleichzeitig noch Unterklassen erzeugt werden, da man ja Methode überschreiben kann.

                Mir sagen auch Maps nicht wirklich was und ich kann mich auch nicht entsinnen, es schon einmal gelesen zu haben.

                Maps sind aber sehr grundlegende Datenstrukturen. Sie ordnen Schlüsseln Werte zu, im Prinzip also zweispaltige Tabellen.
                Zu Maps in Java: < http://java.sun.com/j2se/1.5.0/docs/api/java/util/Map.html> und diverse Implementierungen davon die sich im selben Paket befinden.

                Warum geht Clothoid.Parameter.values();

                Das sind einfach alle Werte, die der Aufzählungstyp hat. Also X, Y und Z. Wenn Du einen bestimmten Parameter festlegen willst, kannst Du einfach Clothoid.Parameter.X nehmen.

                Grüße

                Daniel

                1. Hallo Daniel Thoma,

                  Nein, Du sollst nicht über den Klassennamen sondern über ein Objekt zugreifen also:

                  new Clothoid.Parameter() {
                     public double getValue() {
                        return obj.x;
                     }
                  }

                  Ich glaube ich muss das erstmal nachlesen, das wird (mir) sonst auf die schnelle zuviel. So wie Du es schreibst, mach ich es afaik im Moment:

                  new Clothoid.Parameter() {
                    public double getValue() {
                      return Clothoid.sigma;
                    }
                  }

                  Enumerationen
                  Ok, ich hätte das vielleicht besser mit "Aufzählungstyp" übersetzt.

                  Warum mir das nichts sagt, liegt wohl da ran, das es in "Java (seit Version 5) bekannt" ist, obwohl ich nachfolgenden Typ auch nicht kenne...

                  Maps sind aber sehr grundlegende Datenstrukturen. Sie ordnen Schlüsseln Werte zu, im Prinzip also zweispaltige Tabellen.

                  Ja, darunter kann ich mir was vorstellen. Ich stell mir erstmal ein 2D-Array drunter vor, die kenne ich und kommte ganz gut hin mit denen.

                  Ich habe mir diesen Thread als Lesezeichen gespeichert und muß das "neue" erstmal etwas verdauen. Ich möchte mich nochmal bei Dir bedanken! Sowie ich ein weiteres Problem habe, weiß ich ja, wo ich Dich finde ;)

                  Schöne Grüße,
                  Micha

                  --
                  LeagueEditor JavaScript :: simple Ligaverwaltung auf der Basis von JavaScript
                  1. Hallo derletztekick,

                    new Clothoid.Parameter() {
                      public double getValue() {
                        return Clothoid.sigma;
                      }
                    }

                    Nein eben nicht. Du greifst über die Klasse zu, musst also die Parameter statisch machen. Ich habe gesagt, Du sollst stattdessen eine vorher erzeugte Objektinstanz verwenden. Innere Klassen können auf Objekteigenschaften und lokale, finale Variablen des umgebenden Kontextes zugreifen.

                    Ja, darunter kann ich mir was vorstellen. Ich stell mir erstmal ein 2D-Array drunter vor, die kenne ich und kommte ganz gut hin mit denen.

                    Als Vorstellung vermutlich OK, implementiert wird sowas allerdings anders.

                    Grüße

                    Daniel

                    1. Hallo Daniel Thoma,

                      Nein eben nicht. [...] Du sollst stattdessen eine vorher erzeugte Objektinstanz verwenden.

                      Ich kann aber keine Instanz erzeugen - zumindest nicht so, wie ich mir das aus Deinen Posting zusammenstückle.

                      Um das zu machen:
                      new Clothoid.Parameter() {
                        public double getValue() {
                          return obj.x;
                        }
                      };

                      muss obj bekannt sein.

                      Clothoid.Parameter obj = new Clothoid.Parameter();

                      wäre für mein Verständnis die zugehörige Instanz, die kann ich aber so nicht erzeugen und war sicher von Dir auch nicht so gemeint.

                      Mit freundlichem Gruß
                      Micha

                      --
                      LeagueEditor JavaScript :: simple Ligaverwaltung auf der Basis von JavaScript
                      1. Hallo derletztekick,

                        Also dann mal ein ausführlicheres Beispiel:

                          
                        public static void main(String[] argv) {  
                          final Clothoid obj = new Clothoid();  
                          obj.tuWas(..., new Clothoid.Parameter()) {  
                            public double getValue() {  
                              return obj.x;  
                            }  
                          }  
                        }  
                        
                        

                        Jetzt klar?

                        Grüße

                        Daniel

                        1. Hallo Daniel Thoma,

                          Jetzt klar?

                          CT.getParameters(val, new Clothoid.Parameter() {public double getValue() {return CT.sigma;}});

                          ja, jetzt wird es langsma klar, um nicht zu sagen: Es geht nun so, wie Du es wolltest.

                          Nachdem ich Dein Bsp. gesehen habe, wurde mir auch (endlich) klar, was Du die ganze Zeit von mir wolltest. Ich sollte die Begrifflichkeiten mal näher "studieren" ;-)

                          Vielen Dank Daniel!

                          Mit freundlichem Gruß
                          Micha

                          --
                          LeagueEditor JavaScript :: simple Ligaverwaltung auf der Basis von JavaScript
                          1. Hallo,

                            Das ist einer der Threads, wie ich ihn gerne öfter hätte im Selfhtml-Forum, in Punkto freundlicher, respektvoller Umgang miteinander. Auch der inhaltliche Teil ist Zucker.

                            --
                            Die Leute hören nicht zu, Sie laden nach