开发者

Map a 32 bit float to a 32 bit integer

开发者 https://www.devze.com 2022-12-29 13:20 出处:网络
Is there a 开发者_运维技巧way to map floats to ints or unsigned ints so that with the exception of NaN, order is preserved?

Is there a 开发者_运维技巧way to map floats to ints or unsigned ints so that with the exception of NaN, order is preserved?

So if a and b are floats, and F is the mapping function,

a < b implies F(a) < F(b) and a == b implies F(a) == F(b)


Hm, just out of the DawsonCompare routine in Game Programming Gems 6, it's a normal bit-cast followed by a sign flip (since negative floats order opposite then negative integers). I'll borrow that idea.

You have:

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

If you can guarantee your int is 32 bits, you can just use that.


Fun fact: The book goes on to use this (note, not with the exact code I present, since I stripped out the float-to-int part) to compare floating point values with tolerance:

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

This compares floats as true if their integer representations are within a certain range. (He uses 1000 as a good default.) A branch-less version called the LomontCompare is presented with the same idea, but you have to buy the book for that. :)


Just to eliminate the potentially-slow if from the other answers…

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

Note that unlike the other solution, this incorrectly handles 0 and -0. As floats they compare equal, but after mapping to integers they become 0 and -1, respectively. As a single hiccup in the number line, I don't think it would be easy to handle that case without a branch instruction.

Of course, this assumes two's complement arithmetic, float being IEEE 754 single, same endianness and same address space for floats and ints, etc.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号