Отобразите плавание на 32 бита на целое число на 32 бита

Существует ли способ отобразить плавания на ints или неподписанный ints так, чтобы за исключением NaN, порядок был сохранен?

Таким образом, если a и b являются плаваниями, и F является отображающейся функцией,

<b подразумевает, что F (a) <F (b) и == b подразумевает F (a) == F (b)

23
задан starblue 5 May 2010 в 19:13
поделиться

2 ответа

Хм, только что из DawsonCompare рутины в Game Programming Gems 6, это обычная побитовая перестановка с последующим переворотом знака (поскольку отрицательные плавающие числа имеют порядок, противоположный отрицательным целым). Я позаимствую эту идею.

У вас есть:

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

Если вы можете гарантировать, что ваш int 32-битный, вы можете просто использовать его.


Забавный факт: в книге говорится о том, как использовать это (заметьте, не в том коде, который я привел, так как я убрал часть с float-to-int) для сравнения значений с плавающей точкой с допуском:

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

Это сравнивает плавающие значения как истинные, если их целочисленные представления находятся в определенном диапазоне. (Он использует 1000 как хорошее значение по умолчанию.) Версия без ветвления под названием LomontCompare представлена с той же идеей, но для этого вам придется купить книгу. :)

.
12
ответ дан 29 November 2019 в 03:08
поделиться

Просто чтобы исключить потенциально медленное if из других ответов...

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

Обратите внимание, что в отличие от другого решения, это неправильно обрабатывает 0 и -0. Как плавающие числа они равны, но после преобразования в целые числа они становятся 0 и -1, соответственно. Как единственная заминка в линии чисел, я не думаю, что с этим случаем будет легко справиться без инструкции ветвления.

Конечно, это предполагает, что арифметика дополнения двойки, float является единицей IEEE 754, одинаковая эндианальность и одинаковое адресное пространство для float и ints, и т.д.

1
ответ дан 29 November 2019 в 03:08
поделиться