Как эффективно сравнить знак двух значений с плавающей точкой при обработке отрицательных нулей

Учитывая два числа с плавающей точкой, я ищуэффективное способ проверить, имеют ли они одинаковый знак,учитывая, что если любое из двух значений равно нулю (+0.0 или -0.0), они должны иметь одинаковый знак.

Например,

SameSign (1.0, 2.0) должен вернуть trueSameSign (-1.0, -2.0) должен вернуть trueSameSign (-1.0, 2.0) должен вернуть falseSameSign (0.0, 1.0) должен вернуть trueSameSign (0.0, -1.0) должен вернуть trueSameSign (-0.0, 1.0) должен вернуть trueSameSign (-0.0, -1.0) должен вернуть true

Наивная, но правильная реализацияSameSign в C ++ будет:

bool SameSign(float a, float b)
{
    if (fabs(a) == 0.0f || fabs(b) == 0.0f)
        return true;

    return (a >= 0.0f) == (b >= 0.0f);
}

Предполагая модель с плавающей точкой IEEE, вот вариантSameSign который компилируется в код без ветвей (по крайней мере, с Visual C ++ 2008):

bool SameSign(float a, float b)
{
    int ia = binary_cast<int>(a);
    int ib = binary_cast<int>(b);

    int az = (ia & 0x7FFFFFFF) == 0;
    int bz = (ib & 0x7FFFFFFF) == 0;
    int ab = (ia ^ ib) >= 0;

    return (az | bz | ab) != 0;
}

сbinary_cast определяется следующим образом:

template <typename Target, typename Source>
inline Target binary_cast(Source s)
{
    union
    {
        Source  m_source;
        Target  m_target;
    } u;
    u.m_source = s;
    return u.m_target;
}

Я ищу две вещи:

Более быстрое и эффективное внедрениеSameSignс использованием битовых трюков, трюков FPU или даже встроенных функций SSE.

Эффективное расширениеSameSign до трех значений.

Редактировать:

Я сделал несколько измерений производительности на трех вариантахSameSign (два варианта, описанные в первоначальном вопросе, плюс вариант Стивена). Каждая функция выполнялась 200-400 раз на всех последовательных парах значений в массиве из 101 числа с плавающей запятой, заполненных случайным образом с -1,0, -0,0, +0,0 и +1,0. Каждое измерение повторялось 2000 раз, и минимальное время сохранялось (чтобы отсеять все эффекты кэша и замедления, вызванные системой). Код был скомпилирован с Visual C ++ 2008 SP1 с максимальной оптимизацией и включенным генерацией кода SSE2. Измерения проводились на Core 2 Duo P8600 2,4 ГГц.

Вот временные параметры, не считая затраты на выборку входных значений из массива, вызов функции и получение результата (который составляет 6-7 тактов):

Наивный вариант: 15 тиковБит волшебный вариант: 13 тиковВариант Стивенса: 6 тиков

Ответы на вопрос(0)

Ваш ответ на вопрос