Half-precision floating-point in Java
Gibt es eine Java-Bibliothek überall ausführen können Berechnungen auf IEEE 754 halb-Präzision zahlen oder konvertieren Sie Sie in und aus double-precision?
Ansätze geeignet wären:
- Halten Sie die zahlen in der Hälfte-precision-format und berechnen unter Verwendung der integer-Arithmetik - & bit-twiddling (wie MicroFloat für single - und double-precision)
- Führen Sie alle Berechnungen im single-oder double precision Konvertierung zu/von der Hälfte Präzision für die übertragung (in dem Fall das, was ich brauche, ist gut getestete Funktionen für die Konvertierung.)
Bearbeiten: - Konvertierung Bedürfnisse zu 100% genau - es sind viele NaNs, unendlichen und subnormals in der input-Dateien.
Verwandte Frage, aber für JavaScript: Dekomprimieren die Hälfte Präzision Schwebt in Javascript
- Verwandte: hier ist Python-code konvertiert Python-float IEEE 754-2008 (binary16) - format. Es unterstützt unendlichen, subnormals, plus/minus Nullen aber alle NaNs verwandeln sich in ein einziges Beispiel NaN und ich bin mir nicht sicher, ich verstehe das rundungsverhalten.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Können Sie
Float.intBitsToFloat()
undFloat.floatToIntBits()
konvertieren Sie zu und von der primitive float-Werte. Wenn Sie Leben können mit abgeschnitten Präzision (im Gegensatz zu Runden) die Konvertierung sollte möglich sein, die Umsetzung mit nur ein paar bit-Verschiebungen.Ich habe nun ein bisschen mehr Mühe und es stellte sich heraus, nicht ganz so einfach, wie ich erwartet hatte, zumindest am Anfang. Diese version wird nun getestet und überprüft werden, in jedem Aspekt, den ich mir vorstellen konnte und ich bin sehr zuversichtlich, dass es produziert die genauen Ergebnisse für alle möglichen Eingabewerte. Es unterstützt die exakte Rundung und subnormal Umwandlung in beide Richtungen.
Implementiert habe ich zwei kleine Erweiterungen im Vergleich zu den Buch, weil die Allgemeine Präzision für 16-bit-floats ist eher gering, die könnten die inhärenten Anomalien von floating-point-Formate visuell wahrnehmbar sind, im Vergleich zu größeren floating-point-Typen, wo Sie sind in der Regel nicht bemerkt aufgrund der großen Präzision.
Dem ersten dieser beiden Zeilen in die
toFloat()
Funktion:Floating-point-zahlen in den Normalbereich vom Typ Größe anzunehmen, der exponent und damit die Präzision, um die Größenordnung des Wertes. Aber dies ist nicht eine glatte Annahme, es geschieht in den Schritten: Wechsel auf die nächst höhere Exponenten Ergebnisse in der Hälfte der Präzision. Die Präzision bleibt nun das gleiche für alle Werte der Mantisse, bis der nächste Sprung in die nächst höhere Exponenten. Die Erweiterung code oben macht diese übergänge glatter durch Rücksendung einen Wert, der in der geografischen Mitte der enthaltenen 32-bit-float-Bereich für diese Besondere Hälfte einem float-Wert. Jeder normale Hälfte float-Wert-Karten, um genau 8192 32-bit-float-Werte. Der zurückgegebene Wert sein soll, genau in der Mitte dieser Werte. Aber am übergang von der Hälfte float exponent der unteren 4096 Werte in doppelter Genauigkeit wie die oberen 4096 Werte und decken somit eine Reihe Raum, der ist nur halb so groß wie auf der anderen Seite. All diese 8192 32-bit-float-Werte anzeigen, um die gleiche Hälfte einem float-Wert, so dass die Konvertierung eine halbe float zu 32-bit-und wieder die Ergebnisse in der gleichen Hälfte einem float-Wert unabhängig davon, welche 8192 intermediate 32-bit-Werten gewählt wurde. Die Erweiterung führt jetzt zu so etwas wie ein glatter halben Schritt um einen Faktor sqrt(2) am übergang (siehe unten rechts) Bild unten, während die linke Bild soll die Visualisierung der scharfen Schritt durch einen Faktor von zwei, ohne anti-aliasing. Sie können sicher entfernen Sie diese beiden Zeilen aus dem code, um das standard-Verhalten.
Die zweite Erweiterung ist in der
fromFloat()
Funktion:Dieser extension etwas erweitert, die Zahl der half-float-format durch speichern einige 32-bit-Werte bilden, immer gefördert "Unendlich". Die betroffenen Werte sind diejenigen, die gewesen wäre, die kleiner als Unendlich, ohne Rundung und würde sich die Unendlichkeit nur durch die Rundung. Sie können sicher entfernen Sie die Zeilen, die oben gezeigt, wenn Sie nicht möchten, dass diese Erweiterung.
Habe ich versucht zu optimieren, der Weg für den normalen Werten in der
fromFloat()
Funktion so viel wie möglich, die machte es ein wenig weniger lesbar durch die Verwendung von vorausberechneten und unshifted Konstanten. Ich habe nicht so viel in 'toFloat ()', da er nicht überschreiten würde die Leistung einer lookup-Tabelle sowieso. Also, wenn Geschwindigkeit wirklich wichtig ist könnte dietoFloat()
Funktion nur ausfüllen, statische lookup-Tabelle mit 0x10000 Elemente und verwenden Sie diese Tabelle für die eigentliche Konvertierung. Dies ist etwa 3 mal schneller mit einem aktuellen x64-server-VM und etwa 5-mal schneller mit dem x86-client-VM.Ich den code hiermit in die public domain.
fromFloat
(im Gegensatz zum abschneiden) ist nicht allzu schwer, um in die Entscheidung um auf-oder abrunden entscheiden die Mantisse bits verworfen: 0???????????? -> abrunden, 100000000000 -> Runde sogar, sonst aufrunden. EDIT: es IST schwer zu hinzufügen, ich vergaß die Sonderfälle NaN und Inf. Wahrscheinlich nicht Wert.fromFloat
code zum Versagen durch überlaufen auf die Rundung derval
und damit die Umwandlung in null. Sie können dieses Problem beheben, ohne Verlust der Geschwindigkeit durch subtrahieren 0x1000 von jeder Stelle, die Sie vergleichen oder subtrahieren vonval
, aber ich bin mir nicht sicher, es lohnt sich. Trotzdem, schöne Lösung!Float.floatToIntBits
die normalisiert alle NaNs zu 0x7fc00000. Die abgerundetenval
kann also nie geworden nagative. Vielleicht wäre es schnellerfloatToRawIntBits
(was Sie nicht tut, NaN Normalisierung) und befasst sich dann mit dem überlauf NaNs, d.h. durch hinzufügen|| val < 0
um die erste Filiale. Dies würde es auch erlauben, zu bewahren einige der extra NaN bits. Ich erinnere mich, dass ich geplant hatte, dies zu tun, aber konnte Sie nicht finden, ausreichende Dokumentation, wie man mit diesen bits und so ließ sich mit normalisierten NaNs.short
? Ich merkeshort
ist ein bisschen wie ein Bürger zweiter Klasse, abershort[]
undShortBuffer
sind die natürlichen und schnell Container für die Hälften.MAX_VALUE
undPOSITIVE_INFINITY
?Den code von x4u codiert der Wert 1 korrekt als 0x3c00 (ref: https://en.wikipedia.org/wiki/Half-precision_floating-point_format). Aber der decoder mit Glätte Verbesserungen dekodiert, die in 1.000122. Der wikipedia-Eintrag sagt, dass integer-Werte 0..2048 können exakt dargestellt werden. Nicht schön...
Entfernen der
"| 0x3ff"
von der toFloat code sorgt dafür, dasstoFloat(fromFloat(k)) == k
für ganzzahlige k im Bereich von -2048..2048, vermutlich auf Kosten von etwas weniger Glätte.| 0x3ff
hat den job schön!Vorher sah ich die Lösung hier gepostet, ich hatte bis Schlagsahne etwas einfaches:
Mir gefällt der Ansatz, in den anderen gepostet Lösung, obwohl. Referenz:
Erstellte ich eine java-Klasse aufgerufen, die die HalfPrecisionFloat, die verwendet x4u Lösung. Die Klasse bietet bequeme Methoden und Fehler zu überprüfen. Es geht weiter und hat Methoden für die Rücksendung eine Doppel-und Float-2 byte half-precision-Wert.
Hoffentlich jemand helfen.
==>
Und hier ist die unit-tests