Umwandlung von Int in Float oder Float zu Int Bitweise Operationen (software-floating-point)
Ich Frage mich, ob Sie könnte helfen, erklären, den Prozess der Umwandlung eines integer zu float oder float zu einem integer. Für meine Klasse, wir sind zu diesem Zweck mit nur bitweise Operatoren, aber ich denke, dass eine Feste Vereinbarung über die Umwandlung von Typ zu Typ wird mir helfen, mehr in diesem Stadium.
Von dem, was ich bisher wissen, für int, float, müssen Sie konvertieren den Ganzzahl in Binär, normalisieren den Wert der integer-durch das finden der Mantisse, exponent, und die Fraktion, und dann geben Sie den Wert in float von dort?
Als für float zu int, haben Sie zum trennen der Werte in der Mantisse, exponent, und die Fraktion, und dann drehen Sie den Anweisungen oben, um einen int-Wert?
Ich habe versucht, Folgen den Anweisungen von dieser Frage: Casting float zu int (bitweise) in C.
Aber ich war nicht wirklich in der Lage, es zu verstehen.
Auch, könnte mir jemand erklären, warum die Rundung wird notwendig sein, Werte größer als 23 bits bei der Umwandlung von int nach float?
- Umwandlung von float zu int (bitweise) in C ist Typ-Zweideutigkeiten der
binary32
bit-Muster, um eineunsigned int
, nicht konvertieren (mit Rundung) auf die nächste Ganzzahl. Typ-Zweideutigkeiten wäre der erste Schritt in der Umsetzung von software-floating-point -, der verschiebt die Mantisse durch die Exponenten, um line-up der Dezimalpunkt an der richtigen Stelle. (Eigentlich ist der radix Punkt, denn dies ist die Basis 2, Basis 10, also das Wort "decimal" ist falsch.) - Duplikate: Wie man manuell (bitweise) durchführen (float)x?, Wie wandelt einen unsigned int in einen float?, Umwandlung von float zu int (bitweise) in C
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erste, ein Papier, das Sie berücksichtigen sollten Lesen, wenn man verstehen will, floating-point-Schwächen besser: "Was Jeder Computer Scientist should Know About Floating Point Arithmetic," http://www.validlab.com/goldberg/paper.pdf
Und nun zu etwas Fleisch.
Folgende code ist nackten Knochen, und die versuche zur Erzeugung eines IEEE-754-single-precision-float von einem
unsigned int
im Bereich von 0 < Wert < 224. Das ist das format, das Sie am ehesten zu begegnen, sind auf moderne hardware, und es ist das format, in dem Sie erscheinen als Referenz in Ihrer ursprünglichen Frage.IEEE-754-single-precision-floats sind in drei Felder unterteilt: Ein single-sign-bit, 8 bit exponent und 23 bits für Mantisse (manchmal auch als Mantisse). IEEE-754 verwendet eine versteckte 1 Mantisse, d.h. die Mantisse ist eigentlich 24 bit insgesamt. Die bits werden gepackt von Links nach rechts, mit dem Vorzeichenbit in bit 31, Exponenten in bit 30 .. 23, und die Mantisse in den bits 22 .. 0. Die folgende Grafik von Wikipedia zeigt:
Exponenten einen bias von 127, was bedeutet, dass der tatsächliche exponent im Zusammenhang mit der floating-point-Zahl ist 127 weniger als der gespeicherte Wert im exponent-Feld. Ein exponent von 0 würde daher codiert sein 127.
(Hinweis: Der vollständige Wikipedia-Artikel für Sie interessant sein können. Ref: http://en.wikipedia.org/wiki/Single_precision_floating-point_format )
Daher, IEEE-754-Zahl 0x40000000 ist wie folgt interpretiert:
Also der Wert ist 1.0 x 21 = 2.0.
Konvertieren
unsigned int
in der begrenzten Reichweite, die oben gegeben werden, dann, um etwas in IEEE-754-format, können Sie eine Funktion wie die unten. Es führt die folgenden Schritte aus:reinterpret_cast
, wandelt die resultierende bit-Muster, um einefloat
. Dieser Teil ist ein hässlicher hack, weil es verwendet eine type-punned pointer. Sie könnte auch durch den Missbrauch einesunion
. Einige Plattformen bieten eine systeminterne operation (wie_itof
) machen diese Neuinterpretation weniger hässlich.Gibt es schnellere Wege, dies zu tun; dieses soll pädagogisch sinnvoll, wenn nicht super effizient:
Können Sie diesen Prozess effizienter zu gestalten, mit Funktionen, die die Erkennung der führenden 1 in einer Reihe. (Diese gehen manchmal durch Namen wie
clz
für "count leading zeros", odernorm
für "normalisieren".)Können Sie auch erweitern, diese zu zahlen unterzeichnet, die durch die Aufnahme der Zeichen, wobei der absolute Wert die ganze Zahl, die Durchführung der oben genannten Schritte, und dann setzen die Vorzeichen in bit 31 in der Rufnummer.
Für Ganzzahlen >= 224, die gesamte Ganzzahl passt nicht in die Mantisse-Feld der 32-bit-float-format. Dies ist der Grund, warum Sie brauchen, um "Runde": Sie verlieren die LSBs, um den Wert passen. So, mehrere ganze zahlen werden am Ende die Zuordnung zu den gleichen floating-point-Muster. Die genaue Zuordnung hängt von der Rundung-Modus (hin-gegen -Inf, Runde gegen +Inf, round toward zero, Runde Richtung nächste auch). Aber die Tatsache der Angelegenheit ist, Sie können nicht schieben, 24 bit in weniger als 24 bits ohne einigen Verlust.
Sehen Sie dies in Bezug auf den code oben. Es funktioniert durch eine Angleichung der führenden 1 um den versteckten 1-position. Wenn man einen Wert >= 224, der code müsste shift Recht, nicht Links, und dass notwendigerweise Verschiebungen LSBs entfernt. Rundung Modi nur sagen, wie es zu handhaben ist, die bits verschoben, entfernt.
BIC ..., #0x00800000
). Ich habe nicht codiert viel ARM-assembly in letzter Zeit, aber ich glaubst ist gültig.Joe Z s Antwort ist elegant, aber Bereich der Eingabewerte ist sehr begrenzt. 32-bit-float kann alle ganzzahligen Werte aus der folgenden Auswahl:
und einige andere Werte außerhalb dieses Bereichs.
Die ganze Bandbreite abgedeckt wäre von diesem:
Natürlich gibt es auch andere Mittel zu finden, die abs-Wert int (astfreie). Ähnlich couting führende Nullen können auch durchgeführt werden, ohne eine Niederlassung, so behandeln Sie dieses Beispiel als Beispiel ;-).
return *((float*)&ret);
ist Undefiniertes Verhalten in C (einige Compiler wie MSVC tun definieren Sie das Verhalten, aber andere möglicherweise nicht). Verwendenmemcpy
oder eine union-type-pun.unsigned int
(oder in diesem Fall besseruint32_t
) zu verlagern / ODER FP-bit-Muster wäre auch eine gute Idee. Eine Verschiebung nach Links einer Ganzzahl mit Vorzeichen, ändert das Vorzeichen-bit ist technisch signed-überlauf UB, denke ich. (Sie müssen nicht tatsächlich tun, und es gibt genug andere Annahmen der 2-Komplement-und 32-bit -int
dass es vielleicht egal ist.)Haben Sie überprüft, die IEEE 754 floating-point-Darstellung?
In 32-bit normalisierten form, es hat (Mantisse s) Vorzeichen-bit, 8-bit exponent (exzess-127, glaube ich) und 23-bit-Mantisse in "dezimal", außer dass die "0." wird gelöscht (in dieser form) und die radix ist 2, nicht 10. Das ist: der MSB-Wert ist 1/2, das nächste bit 1/4 und so auf.