2010-05-05 4 views
23

Gibt es eine Möglichkeit, Gleitkommazahlen zu Ints oder unsignierten Ints zu mappen, so dass die Reihenfolge beibehalten wird, mit Ausnahme von NaN?Eine 32-Bit-Gleitkommazahl einer 32-Bit-Ganzzahl zuordnen

Also, wenn a und b Schwimmern, und F die Funktionszuordnung,

a < b bedeutet F (a) < F (b) und a == b bedeuten, F (a) == F (b)

+0

Ja, ich glaube, ich habe schon solche Abbildung gesehen - es war ziemlich clever - ich wünschte nur, ich könnte mich erinnern * wo * Ich sah es ... –

+0

Darf ich Ihren Anwendungsfall für solch ein Mapping fragen? –

+3

+1 große Frage –

Antwort

12

Hm, gerade aus der DawsonCompare Routine in Game Programming Gems 6, ist es eine normale Bit-Cast gefolgt von einem Zeichen Flip (da negative Floats Reihenfolge gegenüber dann negative ganze Zahlen). Ich werde mir diese Idee ausleihen.

Sie haben:

// utility 
template <typename R, typename T> 
R& bit_cast(T& pX) 
{ 
    return reinterpret_cast<R&>(pX); 
} 

// int32_t defined in <boost/cstdint.hpp>. 
boost::int32_t float_to_int_bits(float pX) 
{ 
    boost::int32_t x = bit_cast<boost::int32_t>(pX); 

    if (x < 0) 
     x = 0x80000000 - x; 

    return x; 
} 

Wenn Sie Ihre int 32 Bits garantieren können, können Sie nur diese verwenden.


Fun Tatsache: Das Buch geht weiter diese (beachten Sie, nicht mit der genauen Code stelle ich, da ich den Schwimmer-to-int Teil gezupft) zu verwenden, mit Toleranz Gleitkomma-Werte vergleichen:

Dies vergleicht Floats als wahr, wenn ihre Ganzzahldarstellungen innerhalb eines bestimmten Bereichs liegen. (Er verwendet 1000 als einen guten Standard.) Eine zweiglose Version namens LomontCompare ist mit der gleichen Idee präsentiert, aber Sie müssen das Buch dafür kaufen. :)

+5

+1 hier ist eine große verwandte Verbindung: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm –

+1

Danke für die Hilfe – zounds

1

einfach die potenziell langsam if aus den anderen Antworten zu beseitigen ...

int32_t float_to_int(float f) { 
    int32_t i = reinterpret_cast< int32_t& >(f); 
    uint32_t sgn = static_cast<uint32_t>(i) >> 31; 

    return i^-sgn & numeric_limits<int32_t>::max(); 
} 

Beachten Sie, dass im Gegensatz zu der anderen Lösung, diese 0 und -0 falsch behandelt. Als Gleitkommawerte vergleichen sie gleich, aber nach dem Mapping auf Ganzzahlen werden sie 0 bzw. -1. Als einen einzelnen Schluckauf in der Zahlenzeile glaube ich nicht, dass es einfach wäre, diesen Fall ohne einen Verzweigungsbefehl zu handhaben.

Natürlich setzt dies voraus, Zweier-Komplement-Arithmetik, float wobei IEEE 754 mit einfacher, gleicher endianness und gleichen Adressraum für Schwimmer und Ints usw.

+0

GMans Lösung behandelt positiv und negativ 0 richtig. –

+0

Ah, jetzt sehe ich 'INT_MIN' =>' INT_MIN - INT_MIN'. Vielen Dank. – Potatoswatter