Быстрое преобразование с плавающей точкой в ​​int (усечение) - PullRequest
9 голосов
/ 19 февраля 2012

Я ищу способ урезать float в int быстрым и переносимым (IEEE 754) способом.Причина в том, что в этой функции 50% времени тратится на приведение:

float fm_sinf(float x) {
    const float a =  0.00735246819687011731341356165096815f;
    const float b = -0.16528911397014738207016302002888890f;
    const float c =  0.99969198629596757779830113868360584f;

    float r, x2;
    int k;

    /* bring x in range */
    k = (int) (F_1_PI * x + copysignf(0.5f, x)); /* <-- 50% of time is spent in cast */

    x -= k * F_PI;

    /* if x is in an odd pi count we must flip */
    r = 1 - 2 * (k & 1); /* trick for r = (k % 2) == 0 ? 1 : -1; */

    x2 = x * x;

    return r * x*(c + x2*(b + a*x2));
}

Ответы [ 4 ]

4 голосов
/ 19 февраля 2012

Замедление приведения типа float-> int в основном происходит при использовании инструкций x87 FPU на x86. Чтобы выполнить усечение, режим округления в управляющем слове FPU необходимо изменить на округление до нуля и обратно, что имеет тенденцию быть очень медленным.

При использовании SSE вместо инструкций x87 доступно усечение без изменения контрольного слова. Вы можете сделать это, используя параметры компилятора (например, -mfpmath=sse -msse -msse2 в GCC) или скомпилировав код как 64-битный.

В наборе команд SSE3 есть инструкция FISTTP для преобразования в целое число с усечением без изменения управляющего слова. Компилятор может сгенерировать эту инструкцию, если ему предписано принять SSE3.

В качестве альтернативы функция C99 lrint() преобразует в целое число с текущим режимом округления (от округления до ближайшего, если вы его не изменили). Вы можете использовать это, если удалите термин copysignf. К сожалению, эта функция все еще не повсеместна после более чем десяти лет.

2 голосов
/ 19 февраля 2012

чтобы быть переносимым, вам нужно было бы добавить несколько директив и выучить пару языков ассемблера, но теоретически вы могли бы использовать встроенную сборку для перемещения частей регистра с плавающей запятой в eax / rax ebx / rbx и конвертировать то, что вам нужноС другой стороны, спецификация с плавающей запятой, хотя и является проблемой, но я вполне уверен, что если вы сделаете это со сборкой, вы будете намного быстрее, так как ваши потребности очень специфичны, а системный метод, вероятно, более универсален и менее эффективен для вашегоцель

1 голос
/ 28 марта 2012

Я нашел метод быстрого усечения от Sree Kotay, который обеспечивает именно ту оптимизацию, которая мне нужна.

0 голосов
/ 19 февраля 2012

Вы можете вообще пропустить преобразование в int, используя frexpf , чтобы получить мантиссу и экспоненту и проверить необработанную мантиссу (используйте union) в соответствующей позиции бита (рассчитанной с использованиемпоказатель степени) для определения (квадрант зависимый) r.

...