2010-05-05 21 views
23

¿Hay alguna manera de asignar flotantes a ints o ints sin signo para que, a excepción de NaN, el orden se conserve?Asignar un flotador de 32 bits a un entero de 32 bits

Así que si a y b son los flotadores, y F es la función de mapeo,

un < b implica F (a) < F (b) y a == b implica F (a) == F (b)

+0

Sí, creo que he visto un mapeo tal ante - Era bastante ingenioso - Solo desearía poder recordar * dónde * Lo vi ... –

+0

¿Puedo preguntar su caso de uso para tal mapeo? –

+3

+1 gran pregunta –

Respuesta

12

Hm, recién salido de la rutina DawsonCompare en Game Programming Gems 6, es un lanzamiento de bits normal seguido de un cambio de signo (ya que los flotantes negativos ordenan los enteros negativos opuestos). Tomaré prestada esa idea.

tiene:

// 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; 
} 

Si se puede garantizar sus int es de 32 bits, sólo puede usar eso.


Dato curioso: El libro va a utilizar esto (nota, no con el código exacto presento, ya que me quité la parte de flotación a int) para comparar los valores de punto flotante con la tolerancia:

bool DawsonCompare(float pX, float pY, int pDiff) 
{ 
    int x = float_to_int_bits(pX); 
    int y = float_to_int_bits(pY); 

    int diff = x - y; 
    return abs(diff) < pDiff; 
} 

Esto compara los flotantes como verdaderos si sus representaciones enteras están dentro de un cierto rango. (Utiliza 1000 como un buen valor predeterminado). Una versión sin ramas llamada LomontCompare se presenta con la misma idea, pero debe comprar el libro para eso. :)

+5

+1 aquí hay un gran enlace relacionado: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm –

+1

Gracias por la ayuda – zounds

1

, sólo para eliminar el potencial lento if de las otras respuestas ...

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(); 
} 

Tenga en cuenta que a diferencia de la otra solución, esto trata incorrectamente 0 y -0. Como flotantes se comparan iguales, pero después del mapeo a enteros se convierten en 0 y -1, respectivamente. Como un solo tropiezo en la recta numérica, no creo que sería fácil manejar ese caso sin una instrucción de bifurcación.

Por supuesto, esto supone la aritmética de complemento a dos, siendo float simple IEEE 754, el mismo orden de bits y el mismo espacio de direcciones para los flotadores y enteros, etc.

+0

La solución de GM maneja el 0 positivo y negativo correctamente. –

+0

Ah, ahora veo, 'INT_MIN' =>' INT_MIN - INT_MIN'. Gracias. – Potatoswatter

Cuestiones relacionadas