Существует ли способ отобразить плавания на ints или неподписанный ints так, чтобы за исключением NaN, порядок был сохранен?
Таким образом, если a и b являются плаваниями, и F является отображающейся функцией,
<b подразумевает, что F (a) <F (b) и == b подразумевает F (a) == F (b)
Хм, только что из 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
представлена с той же идеей, но для этого вам придется купить книгу. :)
Просто чтобы исключить потенциально медленное 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, и т.д.