2016-07-14 31 views
0

Ich versuche, die AKAZE Feature Implementierung in OpenCV und war verblüfft, zu verstehen, wenn ich auf der anderen folgende Makro kam:Toggle Float-Makro zusammen mit Int * - Was macht es?

/* IEEE754 constants and macros */ 
#define CV_TOGGLE_FLT(x) ((x)^((int)(x) < 0 ? 0x7fffffff : 0)) 

Es ist in den MLDB binären Vergleichen in der folgenden Art und Weise verwendet wird (ich alle irrelevanten Teile entfernt der Code):

void MLDB_Binary_Comparisons(float* values) 
{ 
    int* ivalues = (int*)values; 
    for (int i = 0; i < count * chan; i++) 
     ivalues[i] = CV_TOGGLE_FLT(ivalues[i]); 

    /* ... The ivalues are then compared to each other using the > operator */ 
} 

Versteht jemand, was hier vorgeht? Ist es wirklich sicher, float * in ein int * zu schreiben, und was macht das Makro?

Vielen Dank im Voraus!

+0

extrahiert nur Ints aus Float in einem bestimmten Format. Es ist schwer, mehr zu sagen, da mehr Code analysiert werden muss, als Sie zur Verfügung gestellt haben. Bitte überprüfen Sie diesen Link, vielleicht wird es für Sie klarer, wenn Sie das Float-Format überprüfen. https://en.wikipedia.org/wiki/Single-precision_floating-point_format – nosbor

Antwort

1

Im Wesentlichen macht es einige binäre Manipulation der Gleitkommadaten, in einer nicht tragbaren Art und Weise: Es gibt klare Annahmen über die relativen Größen von int und float und auch über ihre Darstellung. Ich denke, dass , wennint ist eine 32-Bit 2'-Komplement Integer und float ist ein IEEE 32-Bit Gleitkommawert, dann können Sie die Gleitkommawerte nur mit ganzzahligen Operationen vergleichen.

mehr Details ...

int* ivalues = (int*)values; 

Dies gibt uns nur einen Zeiger, der durch die Fließkommawerte zu Fuß verwendet wird. Sie sind interpretiert als ints, nicht umgewandelt zu int - mit anderen Worten: es gibt keinen Grund zu denken, dass ein float mit einem Wert von 1.0 zu einem int Wert von 1 abbildet. Das Wichtigste, was Sie tun können, sind bitweise Operationen oder spezifische Manipulationen, die darauf angewiesen sind, das für float verwendete Binärformat zu verstehen.

auf der Makro-Blick ...

#define CV_TOGGLE_FLT(x) ((x)^((int)(x) < 0 ? 0x7fffffff : 0)) 

Der Wert x (denken Sie daran, nur einige der Bits, die sonst einen Fließkommawert darstellen, aber hier sehen wir nur an sie als Bitmuster) ist XOR-ed mit entweder 0 (die keine Wirkung hat) oder 0x7fffffff (die die niederwertigen 31 Bits invertiert). Die Entscheidung, was zu tun ist, basiert darauf, ob x kleiner als Null ist oder nicht.

Ich denke, dieses Makro basiert auf der Annahme, dass eine int eine 32-Bit-2's-Komplement-Darstellung ist. Das bedeutet, dass x < 0 wahr ist, wenn das oberste Bit gesetzt ist. Das XOR mit 0x7fffffff wird die anderen Bits invertieren. Dies bedeutet, dass -1, die positivste negative Zahl, von 0xffffffff zu 0x8000000 geändert wird. Dies ist die negativste negative Zahl (-2147483648) und ebenfalls 0x8000000 wird 0xffffffff. Wenn Sie danach > verwenden, um zwei negative Zahlen zu vergleichen, bedeutet das, dass die negativere Nummer nun die positivere Nummer ist, und die "größer als" Verzweigung wird genommen. Vergleicht man zwei positive Zahlen unverändert, vergleicht man eine positive Zahl mit einer negativen Zahl, ist die positive Zahl erwartungsgemäß immer noch größer.

Damit können Sie Vergleiche für float s mit nur ganzzahligen Operationen durchführen. Dies liegt daran, dass die Art und Weise, wie float s im IEEE-Format negative Zahlen speichern, sich deutlich von dem Zweierkomplement unterscheidet: Das Vorzeichenbit ist wirklich nur ein Flag, dass der Wert positiv oder negativ ist, und die restlichen Bits speichern die Größe der Zahl. Sobald Sie die CV_TOGGLE_FLT(x) angewendet haben, haben Sie keine Werte, die Sie direkt verwenden können, aber sie sind auf die gleiche Weise wie die ursprünglichen float Werte sortiert.

+0

Wow, das hat es kristallklar gemacht - danke! –

+0

@ 4-bit Danke, froh, dass ich helfen konnte. Und es hat Spaß gemacht, herauszufinden, was los ist! – AAT