Hallo zusammen,
ich suche nach einer Erklärung oder einem Beispiel wie der Typecast
double -> float vollzogen wird. Leider war meine google-Suche da nicht
sehr ergiebig. Wahrscheinlich suche ich nach den falschen
Schlüsselwörtern.
Hintergrund meiner Frage: Ich möchte dieses Cast-Verfahren als Vorlage
für einen Typecast von float auf ein 16 Bit Floatingpoint-Format (1 Bit
Vorzeichen, 5 Bit Exponent, 10 Bit Mantisse) anwenden und das Rad nicht
neu erfinden.
Viele Grüße
Zisko
Zisko schrieb:> Hallo zusammen,>> ich suche nach einer Erklärung oder einem Beispiel wie der Typecast> double -> float vollzogen wird. Leider war meine google-Suche da nicht> sehr ergiebig. Wahrscheinlich suche ich nach den falschen> Schlüsselwörtern.
Nicht nur das. Das wird dir auch nicht viel helfen.
Denn im Grunde besteht der cast bei den üblichen Floating Point Formaten
nur darin, solange in der Mantisse (beginnend mit den niederwertigsten
Bits), Bits wegzuwerfen, bis die geforderte Anzahl an Bits übrig bleibt.
Beim Exponenten wird im Prinzip auch nicht anders verfahren, nur das
diesmal am MOst signifikant Bit Ende angefangen wird, wenn float und
double eine unterschiedliche Anzahl an Exponentenbits benutzen.
D.h. man könnte die Operation auch so beschreiben: Das ist nichts
anderes als ein Umkopieren von einem Speicherbereich in einen anderen,
wobei nur ausgewählte Teile des Original mitgenommen werden.
> Hintergrund meiner Frage: Ich möchte dieses Cast-Verfahren als Vorlage> für einen Typecast von float auf ein 16 Bit Floatingpoint-Format (1 Bit> Vorzeichen, 5 Bit Exponent, 10 Bit Mantisse) anwenden und das Rad nicht> neu erfinden.
Ergo nehme ich beim cast double -> float die ersten 23 Bit der Mantisse
und die ersten 8 bit des Exponenten, pack das Vorzeichen hinzu und lege
alles auf 32 Bit Speicher ab, wenn ich das richtig verstanden habe.
Zisko schrieb:> Ergo nehme ich beim cast double -> float ...> die ersten 8 bit des Exponenten
die letzten 8 Bit
Ein "2 hoch 12" ist auch als float "2 hoch 12"
// Vorzeichen, Exponent und Mantisse zu einer 16-Bit-Zahl zusammensetzen
49
h=(s<<HE_BITS|e)<<HM_BITS|m;
50
51
returnh;
52
}
53
54
// Konvertierung von half nach double
55
doubleh2d(halfh){
56
uint64_tid,m;
57
ints,e;
58
59
// Vorzeichen, Exponent und Mantisse extrahieren
60
s=h>>(HE_BITS+HM_BITS);
61
e=h>>HM_BITS&((1<<HE_BITS)-1);
62
m=h&((1<<HM_BITS)-1);
63
64
// Exponent und Mantisse neu skalieren
65
if(e){
66
e+=DE_BIAS-HE_BIAS;
67
m<<=DM_BITS-HM_BITS;
68
}
69
else
70
m=0;
71
72
// Vorzeichen, Exponent und Mantisse zu einer 64-Bit-Zahl zusammensetzen
73
id=((uint64_t)s<<DE_BITS|e)<<DM_BITS|m;
74
75
return*(double*)&id;
76
}
77
78
intmain(intargc,char*argv[]){
79
doubled=strtod(argv[1],NULL);
80
halfh;
81
82
// double nach half konvertieren ...
83
h=d2h(d);
84
85
// ... und wieder zurück
86
d=h2d(h);
87
88
printf("%g\n",d);
89
90
return0;
91
}
Dabei folgt die Anordnung und Darstellung der Zahlenbestandteile
(Vorzeichen, Exponent und Mantisse) dem Standard IEEE-754:
http://de.wikipedia.org/wiki/IEEE_754
Denormalisierte Zahlen, Unendlich und NaN sind nicht implementiert.
Dafür ist das Bitmuster 11111 für den Exponenten erlaubt, was den
Wertebereich für große Zahlen etwas erweitert. Er reicht von
±6.10352e-05 bis ±1.31008Ee+05. Zusätzlich gibt es noch die Werte ±0.
Die Darstellungsgenauigkeit beträgt 3 bis 4 Stellen.
Bei der Konvertierung von double nach half kann es passieren, dass der
Exponent nicht darstellbar ist. Ist er zu klein, wird auf ±0 gerundet.
Ist er zu groß, wird eine Fehlermeldung ausgegeben. Man könnte an dieser
Stelle auch eine Exception auslösen oder Unendlich liefern, wenn dieses
implementiert wäre.
Wenn es auf Laufzeiteffizienz ankommt, kann der Code sicher noch etwas
optimiert werden. So können bspw. die Shifts für die Extraktion der
Zahlenbestandteile mit denen beim Wiederzusammensetzen der Zahl
zusammengefasst werden.
Edit: Hab gerade noch einen Bug gefixt :)
Yalu X. schrieb:> Ich habe mal Konvertierungroutinen von double nach half und half nach> double geschrieben
Ich liebe ja einbuchstabige Variablennamen total ;-)
Mark Brandis schrieb:> Ich liebe ja einbuchstabige Variablennamen total ;-)
Ich bin etwas schreibfaul und dachte, wenigstens diese Kürzel sollten
klar sein:
s = sign
e = exponent
m = mantissa
h = half
d = double
Aber wohl doch nicht ;-)
Yalu X. schrieb:> Ich bin etwas schreibfaul und dachte, wenigstens diese Kürzel sollten> klar sein:>> s = sign> e = exponent> m = mantissa> h = half> d = double>> Aber wohl doch nicht ;-)
Nun ja, die Kommentare sind auf deutsch, die Variablennamen kürzen die
englischen Begriffe ab... find ich jetzt nicht unbedingt ideal. Auch
wenn es hier nur beim Vorzeichen einen Unterschied macht.
Ich seh halt so einen Deutsch/Englisch Mischmasch im Code auf der Arbeit
jeden Tag, und wesentlich schlimmer als hier... wahrscheinlich hängt's
mir deshalb schon zum Hals raus. ;-)
Mark Brandis schrieb:> Nun ja, die Kommentare sind auf deutsch, die Variablennamen kürzen die> englischen Begriffe ab... find ich jetzt nicht unbedingt ideal. Auch> wenn es hier nur beim Vorzeichen einen Unterschied macht.
Oh Mann, ich habe die Bezeichnungen einfach aus dem (deutschsprachigen)
Wikipedia-Artikel übernommen, zu dem ich schon oben den Bezug
hergestellt habe:
http://de.wikipedia.org/wiki/IEEE_754
Du kannst die Diskussion über lange/kurze und deutsche/englische
Variablennamen gerne dort fortführen. Wenn ich dann sehe, dass sie dort
im gegenseitigen Einvernehmen geändert worden sind, werde ich diese
Änderungen auch in meinen obigen Code einfließen lassen ;-)