Krautkanal.com

Veröffentlicht am 2016-02-19 09:12:07 in /prog/

/prog/ 8463: Verzweigungen mit Wahrscheinlichkeiten

bluesix Avatar
bluesix:#8463

Es ist sicher schon erfahrener Java Bernd hier. Ich mache hier mit Processing rum, ist ja an sich auch Java Zeug. Nun, ich verstehe die Basics, aber so ganz pfiffig und wunderschön ist mein Kott nicht.

Bernd, ich bitte um Tipps. So zum bei Spiel habe ich die Situation, dass ich nach einigen gewissen "Wahrscheinlichkeiten" zwischen mehreren Optionen wählen muss (also jede Option hat sein eigenes Gewicht). Dann mache ich so ziemlich hässliche Sachen wie:


...
boolean doesTriggered(double treshold, double limit, double activate){
  if (activate <= limit && activate >= treshold) return true;
  return false;
}
double rand = random(1);
double shit = 0;
if (doesTriggered(shit, shit+=0.2, rand)) {println("Event X mit 0.2");}
if (doesTriggered(shit, shit+=0.3, rand)) {println("Event Y mit 0.3");}
if (doesTriggered(shit, shit+=0.1, rand)) {println("Event A mit 0.1");}
if (doesTriggered(shit, shit+=0.4, rand)) {println("Event B mit 0.4");}
...


Wie kann man das besser machen?

rangafangs Avatar
rangafangs:#8464

Ich sehe in dem Text die Frage nach der Abwägung zwischen Quellcodelesbarkeit und Geschwindigkeit.

Aus irgend einem Grund ist noch eine Bremse in den Systemen, also in Richtung Lesbarkeit arbeiten: Bei komplexen Anfragen evtl javax.sql ansonsten evtl aus java.util sowas wie List<>. Für Mehrprozessoranwendungen evtl java.util.concurrent durchgucken.

Ist hier zu finden: http://docs.oracle.com/javase/7/docs/api/

naupintos Avatar
naupintos:#8466

Oh Gott. Schonmal was von Verteilung gehört?
https://de.wikipedia.org/wiki/Verteilungsfunktion_%28Stochastik%29
double rand = random(1);
if (rand < .2) { println("X"); }
else if (rand < .5) { println("Y"); }
else if (rand < .6) { println("A"); }
else { println("B"); }

chaabane_wail Avatar
chaabane_wail:#8477


boolean doesTriggered(double treshold, double limit, double activate){
  if (activate <= limit && activate >= treshold) return true;
  return false;
}


Das ist guter Stil Bernd mit dem finalen Return. Der Funktionsname ist aber sehr, sehr seltsam. Naja, die Funktion ist letzten Endes sowieso überflüssig, wenn man den Vorschlag des Vorpfostens in Betracht zieht.

_kkga Avatar
_kkga:#8478

>>8477
>Das ist guter Stil
Nein, absolut nichts an dieser Methode ist guter Stil:
- beschissener Name
- Parameter haben beschissene Namen
- if (...) return true; return false; ist in etwa so toll wie if (x == true)
- die Reihenfolge der Variablen in diesem Ausdruck ist schwer verständlich

Besser:
boolean isBetween(double x, double low, double high) {
return low <= x && x <= high;
}

yassiryahya Avatar
yassiryahya:#8479

>>8478
Nachtrag: Außerdem kann es mit OPs Muster durch die fehlenden elses passieren, dass zwei Ereignisse gleichzeitig eintreten. Nämlich dann, wenn man als Treshold einen Wert benutzt, der als double exakt dargestellt werden kann (z.B. 0,5) und der Zufallsgenerator genau diesen Wert würfelt.

Bernd ist sich nicht ganz sicher, ob dieser gesamte Faden (einschließlich der ersten Antwort) nur eine Trollierung ist.

kriegs Avatar
kriegs:#8480

>>8478
Du hast recht. Bernds IDE beschwert sich sogar über die überflüssige If-Bedingung. `min`/`max` oder `low`/`high` sind tatsächlich wesentlich besser als `treshold`/`limit` und man müsste bei den Ungleichungen schon etwas komisch gucken.

>Bernd ist sich nicht ganz sicher, ob dieser gesamte Faden (einschließlich der ersten Antwort) nur eine Trollierung ist.

Na immerhin fehlt Programmieranfängern in der Regel noch der richtige Stil.

Bei dem Weg: Das hier ist noch das unüberbotende Beispiel an Programmieranfängertum:

https://github.com/pear/Image_Color/blob/master/Image/Color.php#L183-L211

Man davon abgesehen, dass `<= 255` besser ist als `< 256` (oder `>= 0` statt `> -1`), könnte man auch einfach `math.min()' und `math.max()` benutzen, oder am besten gleich eine Funktion `clamp()` schreiben, zur besseren Lesbarkeit.

shesgared Avatar
shesgared:#8481

Das IST auch nicht der richtige Stil.

Abgesehen von if bla return true else return false, hat OP hier eine einfache if-then-else Kette (siehe alternativen Code von Bernd) total verkompliziert, so daß bernd erstmal WTF machen mußte. Sein API ist auch nicht einfach zu benutzen, += mandatorisch, was? Und dann hat er auch noch einen echten Heisenbug eingebaut mit 2 Resultaten gleichzeitig.

Der einzige Vorteil ist, daß die Nummern in den Abfragen direkt den Gewichten entsprechen und nicht aufsummiert werden müssen. Für sowas würde man aber ne Tabelle Gewicht-Aktion bzw. Gewicht-String oder sowas nehmen und in ner Schleife hochzählen, also was Alternativbernd gepostet hat in eine Schleife rollen.

ntfblog Avatar
ntfblog:#8482

>>8481
>+= mandatorisch, was? Und dann hat er auch noch einen echten Heisenbug eingebaut mit 2 Resultaten gleichzeitig

Bernd findet es fantastisch. Es ist ganz wichtig sowas falsch zu machen. Nur so lernt man daraus. Wenn man Programmieranfängern nur perfekten Code zeigt, dann lernen sie nicht viel.

Gab es in den letzten Jahre eigentlich beim CCC eigentlich noch das Literarische Codequartett?

BillSKenney Avatar
BillSKenney:#8483

>die Situation, dass ich nach einigen gewissen "Wahrscheinlichkeiten" zwischen mehreren Optionen wählen muss

Keine Ahnung, Bernd, mehr als eine hässliche IF-Kette kommt mir nicht ins Sinn.

bighanddesign Avatar
bighanddesign:#8514

gibt es andere Ansätze, so etwas zu machen?

kershmallow Avatar
kershmallow:#8521

Statt if-else kaskaden bieten sich oft Maps an. Das lässt sich dann später einfacherer erweitern und es gibt weniger fehlerquellen als bei switch/case oder if/elseif. Außerdem kann man die map schön als static final deklarieren und aus dem eigentlichen Code herausziehen.

Allerdings macht das bei Funktionsaufrufen wie in diesem Fall erst mit Java 8 spaß, sonst ist das etwas viel schreibaufwand.
In diesem Fall könnte man das dann noch mit einer RangeMap kombinieren:

RangeMap<Integer, Runnable> map = new ImmutableRangeMap.Builder<Integer, Runnable>()
.put(Range.closed(0, 30), () -> System.out.println("event a"))
.put(Range.closed(31, 70), () -> System.out.println("event b"))
.put(Range.closed(71, 100), () -> System.out.println("event c"))
.build();

map.get(new Random().nextInt(100)).run();

kuldarkalvik Avatar
kuldarkalvik:#8522

Für ne einfache Feldfallunterscheidung (statische Konstanten) mal eben mit dynamischen Objektierungen rumwirbeln? Oh wow. Glaub aber du hast noch eine PatternFactory vergessen irgendwie.

to_soham Avatar
to_soham:#8525

Kann sein, dass das kostenlose Visual Studio 'ne Bremse drin hat. Evtl war das damit begründbar, dass Programmieren Sachkompetenz fehlte oder Kurse nötig waren, um überhaupt auf bestimmte API-Teile aufmerksam zu werden.

seanwashington Avatar
seanwashington:#8526

>>8525
Aaah! Gerade gesehen, dass ich den falschen Thread im Kopf hatte.

oskamaya Avatar
oskamaya:#8527

>>8522
>Feldfallunterscheidung (statische Konstanten) mal eben mit dynamischen Objektierungen
nö, die map kannst du ohne probleme statisch anlegen.
Für nur ein paar unterschiedliche Werte lohnt sich das sicherlich nicht, aber bei einer größeren Menge ist das durchaus als Option in betracht zu ziehen. Außerdem hast du durch die Map dann in der Regel auch eine konstante zugriffszeit während sie bei if/else linear mit der Anzahl der verzweigungen zunimmt.