Funktion die mir fuer einen String eine Zahl zwischen 0.0 und 1.0 zurueckliefert..?

sirbender

Top Contributor
Hallo,

ich suche eine Funktion die mir fuer einen String eine Zahl zwischen 0.0 und 1.0 zurueckliefert. Ich will diese Zahl in Tests verwenden, deswegen sollte sie fuer alle Ewigkeiten (auch bei anderer JRE version bzw. Hersteller der JRE) gleich bleiben.
Wenn ich dann z.B. den String via getBytes umwandle habe ich dann z.B. Bammel, dass durch das verwendete CharSet in Zukunft das Ergebnis anderst wird. Ich denke aber, dass ich durch Spezifikation des CharSet "UTF-8" auf der sicheren Seite bin?

Auch z.B. die Verwendung von Math.sin um den Wert zwischen 0..1 weiter zu normalisieren halte ich im Moment fuer Problematisch. Wer weiss wie Math.sin in Zukunft implementiert wird. Dadurch koennte mein Test kaputtgehen und ich suche das Problem bestimmt zuerst wo anderst.

Ein Problem ist, dass lange Strings Zahlen nahe bei 1 sind und kurze nahe bei 0.
Versuche ich dieses Problem zu beseitigen (ich normalisiere mit der laenge des String) tritt ein anderes Problem auf, naemlich, dass die Zahlen zwischen 0.0 und 1.0 nicht sehr gleichmaessig verteilt sind.

Ich will jetzt nicht meinen aktuellen Code zeigen um eure Ideen nicht zu beeinflussen. Was wuerdet ihr machen um fuer eine Liste von Strings eine Liste von Werten zwischen 0..1 zu erhalten. Die Zahlen sollten relativ gleichverteilt sein und auch nicht von der Laenge des Strings abhaengen.
 
Ich denke ohne das Du uns sagst was die Anwendung für diese Funktion sein soll, können wir auch schlecht helfen. Für mich klingt das erstmal wie eine recht sinnfreie Idee etwas zu verschlüsseln.

Gruß

Claus
 
Welchen Sinn soll das haben? Und egal wie Sinus implementiert ist oder wird ich denke die Ergebnisse sind durch aus "definiert".

Könnte sein, dass es viel zu früh ist, aber mir erschließt sich das hier nicht.
 
Was soll überhaupt gleichverteilt bedeuten, wenn du doch komplett deterministisch ein reproduzierbares Ergebnis erhalten willst? Allein das ist doch schon total widersprüchlich.
 
Hätte jetzt folgendes Vorgeschlagen:

Java:
public static double between0And1(final String s) {
  final int rawHash = s.hashCode(); // Hash ausrechnen
  final double hash = Math.abs(Math.max(rawHash, -Integer.MAX_VALUE)); // hash in positive Zahl <= MAX verwandeln
  return (1.0 / Integer.MAX_VALUE) * hash; // Zahl zwischen 0.0 und 1.0 berechnen 
}
Damit werden alle Hash-Werte auf einen Zahlenraum zwischen 0 und 1 umgelegt.

Zugegeben werden rawHash=-2147483648 und rawHash=-2147483647 beide zu hash=2147483647, aber ich denke diesen "Schnitzer" in der Verteilung kann man ignorieren, da der positive und negative Zahlenraum von int eben einfach nicht symetrisch ist.
 
Zuletzt bearbeitet:
Also wenn sicher ist, das der String immer dieselbe Bitkombination sein wird, dann suchst du nach einer (guten) Hashfunktion. Z.B. eine CRC-Checksumme. Das geht recht schnell, und schon 1 Bit Änderung ändert die Checksumme total - damit ist eine "Gleichverteilung" sehr wahrscheinlich.

Du solltest aber dringend weg von der Idee, als Ergebnis mit Gleitkommazahlen arbeiten zu wollen. Gleitkommazahlen sind niemals "genau gleich" zu irgend etwas. Schon wenn du eine AMD-CPU anstatt einem Intel-Prozessor nimmst, oder Intel die FPU ein wenig überarbeitet, sind die letzten Mantisse-Bits in Gefahr.

Um die Gleitkomma-Probleme zu umgehen, darf man auf keinen Fall den Gleitkommawert errechnen.
Allenfalls könnte man eine Bitübertragung machen - also z.B. einen Ganzzahl-Wert direkt bitweise als Gleitkomma-Mantisse verwenden. Ein 32-Bit-'int' passt problemlos in die 52 Bit Mantisse eines 'double'.
 
Zuletzt bearbeitet:
[...]Gleitkommazahlen sind niemals "genau gleich" zu irgend etwas. Schon wenn du eine AMD-CPU anstatt einem Intel-Prozessor nimmst, oder Intel die FPU ein wenig überarbeitet, sind die letzten Mantisse-Bits in Gefahr.

Dafür gibt es den IEEE-Standard. Und der wird von Intel/AMD und anderen unterstützt. Sonst bleiben da nur noch Fehler in der Implementierung. Da hat man in den letzten Jahren aber jetzt auch nichts mehr gelesen, Intel hatte da mal ein lustiges Problem vor Jahrzehnten 😉
 
Was soll überhaupt gleichverteilt bedeuten, wenn du doch komplett deterministisch ein reproduzierbares Ergebnis erhalten willst? Allein das ist doch schon total widersprüchlich.

Erstmal generell: es geht nicht um verschluesseln oder sowas. Ich will einen speziellen Unit-Test schreiben und die Details sind schwer zu erklaeren. Wichtig ist nur, dass der Unit-Test eine Liste von Woertern hat und ich fuer jedes Wort im Unit-Test ein double zwischen 0..1 speichere der einmalig aus dem String generiert wurde (der wird aber nicht neu generiert wenn der Unit-Test laeuft sondern wird (und muss auch) statisch in der Datei gespeichert werden).

Ja. Hast du natuerlich recht...wobei ich mich da unsauber ausgedrueckt habe. Bei den Strings handelt es sich einfach um Worte von 2-15 Zeichen Laenge aus dem Woerterbuch. Nun will ich einfach eine Zahl zwischen 0..1 aus jedem String generieren koennen. Die Liste dieser Zahlen sollte bei zufaelligen Woertern aus dem Woerterbuch auch relativ gleichmaessig den Bereich 0..1 abdecken. Und die Laenge das Strings sollte auch keine (bzw. nur eine sehr kleine) Rolle spielen fuer die Zahl die ich generiere.
 
Ist das Wörterbuch bekannt? Wenn ja, dann kannst du ja einfach durchnummerieren* und anschließend entsprechend auf [0..1] skalieren. Wenn du die Wörter ohnehin zufällig auswählst, dann bekommst du es auch mit komplizierteren Ansätzen nicht besser hin.

*Edit: also die möglichen Wörter des Wörterbuchs

Edit 2: Oder reden wir von beliebigen Zeichenketten? Dann landen wir wieder bei der zuvor schon getätigten Aussage, dass du einfach nur eine Hashfunktion suchst?
 
Zuletzt bearbeitet:
Dafür gibt es den IEEE-Standard. Und der wird von Intel/AMD und anderen unterstützt. Sonst bleiben da nur noch Fehler in der Implementierung.
Java unterstützt IEEE 754, ja. (Die Java-NaN's bilden nicht alle IEEE-NaNs ab.)
Die Fehler-Listen aktueller Prozessoren sind jedoch ellenlang, ob da ein Gleitkommafehler in den letzten Mantissen-Bits es "in die Öffentlichkeit schafft", ist nicht sicher.
Zwar rechnen heutige FPU normalerweise intern mit 80 Bit, gerade um Fehler aus den hinteren Mantissen-Bits heraushalten zu können, aber ob z.B. AVX auch mit 80 Bit pro 64-Bit-Wert rechnet, weis ich nicht.
 

Zurück
Oben