double aufteilen
-
Hi,
Wie kann ich denn eine double-Zahl in zwei Teile aufteilen und diese dann jeweils 2 int-Variablen zuweisen? Ich will praktisch alle Bits der double-Zahl mithilfe von zwei 4-Byte-ints überprüfen. Kann mir jemand weiterhelfen?
lg
-
Inwieweit diese deine "Aufteilung" in int Sinn macht, kannst nur du selbst beantworten, üblicherweise nimmt man bei sowas unsigned char.
union bietet sich für dein Problem an, auch muss double nicht 8 Byte und int nicht 4 Byte groß sein.typedef union { double d; unsigned int ia[2]; } Union; Union u = {12345.67890}; assert( sizeof u.d == sizeof u.ia ); printf("%08X;%08X",u.ia[0],u.ia[1]);
-
mööp... falsch :p
-
KingKarl_ schrieb:
mööp... falsch :p
Das schreib mal fix an die glibc-Mailingliste. Die werden aufgrund deiner bahnbrechenden Entdeckung eine Menge Code neu schreiben müssen.
Wutz hat da schon recht, Unions sind ein gängiger Weg, Fließkommazahlen in Maschinenworte zu zerlegen, und unter allen Methoden die sauberste mir bekannte (obwohl ich wohl uint32_t statt unsigned int benutzen würde). Man könnte wohl auch Zeiger casten, aber was soll das?
Allerdings ist das ganze Vorhaben, völlig unabhängig davon, wie man es genau umsetzt, mit Fallstricken gespickt. Gut, dass ein double ein ieee754-binary64 ist, ist heute allgemein Usus und wird wohl auch noch eine Weile so bleiben (das irgendwo zu asserten ist sicher trotzdem eine gute Idee), aber auf einen Endian hat man sich nicht geeinigt. Das bedeutet: In welchem der beiden Worte du nachher den Exponenten findest, ist plattformabhängig. In der glibc findet sich deshalb Folgendes:
/* A union which permits us to convert between a double and two 32 bit ints. */ #if __FLOAT_WORD_ORDER == BIG_ENDIAN typedef union { double value; struct { u_int32_t msw; u_int32_t lsw; } parts; } ieee_double_shape_type; #endif #if __FLOAT_WORD_ORDER == LITTLE_ENDIAN typedef union { double value; struct { u_int32_t lsw; u_int32_t msw; } parts; } ieee_double_shape_type; #endif
...allerdings sind die Makros __FLOAT_WORD_ORDER, BIG_ENDIAN und LITTLE_ENDIAN nicht Teil des C-Standards. Mit POSIX käme man da wohl weiter, aber unter Windows hilft einem das auch nicht - und jetzt, wo es Windows auch auf ARM gibt, kann man da auch nicht mehr so ohne weiteres Little-Endian voraussetzen (oder?). Von NUXI und dergleichen mal ganz zu schweigen, aber so was gibt es ja heute glücklicherweise kaum noch.
Was genau hast du eigentlich vor? Vielleicht gibt es ja andere, besser portable Wege, das zu erreichen.
-
Mir ist nicht klar, was aus einem double in 2 integer aufgeteilt werden soll. Intern besteht jeder double sowieso aus 2 integer für Mantisse und Exponent. Oder soll es um Vorkommastellen und Nachkommastellen gehen?
-
Vielleicht hilft dir die Funktion modf() weiter.
-
Ich dachte es ginge mit Assembler auch, hab also folgendes versucht:
#include <iostream> using namespace std; int main() { double alpha_w=DBL_MAX; double *alpha=&alpha_w; int beta_w=0, gamma_w=0; int *beta=&beta_w; int *gamma=&gamma_w; _asm { mov eax, [alpha] mov [beta], eax mov eax, [alpha+4] mov [gamma], eax } std::cout << hex << *alpha << '\n' << hex << *beta << '\n' << hex << *gamma; return 0; }
Kann mir jemand sagen wo der Fehler liegt? Bekomme durch mov eax, [alpha+4] eine Zugriffsverletzung an der Stelle 0xC...C.