С++ встроенные функции SSE atan2

Мне нужен очень быстрый atan2 для получения градиента из значений sobel (я реализую алгоритм canny edge). Кто-нибудь знает очень быструю реализацию, предпочтительнее во встроенных функциях (SIMD) или очень быстром приближении. (Думаю, приближения достаточно, потому что значения округлены до 0°, 45°, 90°, 135°)

заранее спасибо

ДОБАВИТЬ: я знаю о Intel IPP atan2 в SVML, к сожалению, я не могу его использовать.


person user1235183    schedule 31.07.2015    source источник
comment
Если вы округляете только до нескольких значений угла, просто проверьте знак аргументов и сравните отношение их величины с известными пороговыми значениями.   -  person Sneftel    schedule 31.07.2015
comment
Как вы думаете, почему std::atan2() работает медленно? Вы измеряли его процессорное время? Вы смотрели на дизассемблирование, которое компилятор C++ генерирует в режиме Release? Разве atan2 уже не одна инструкция FPU?   -  person Serge Rogatch    schedule 31.07.2015
comment
Медленно это точка зрения. Первый std::atan2 слишком точен для моей цели, и он не использует инструкцию simd.   -  person user1235183    schedule 31.07.2015


Ответы (2)


Кажется, что вы хотите округлить до числа октанта, предположительно от -22.5° до 337.5° с шагом 45°.

Октанты разделены четырьмя линиями через начало координат с уравнением

Y = X tan(Θ),

or

a.Y - b.X = 0.

с подходящими коэффициентами масштабирования.

Вычислив знаки этих выражений для четырех искомых углов, вы найдете октант. Умной комбинацией вы можете ограничиться тремя оценками знаков, так как существует 8=2³ возможностей.

Вполне вероятно, что это можно оценить с помощью инструкций SIMD, вычислив дискриминантные выражения, их знаки и подходящие комбинации их знаков, но это не тривиально.

Вероятно, преобразование в число, кратное 45°, не требуется, даже порядковая нумерация. Все зависит от того, что вы делаете с информацией о октанте.


Дополнительное предложение SIMD:

С предварительно загруженными коэффициентами вы можете вычислить все четыре линейных уравнения за один раз для пары (X, Y), используя 16-битную целочисленную арифметику (возможно, с умножением и сложением). Затем получите знаки и упакуйте их в четыре бита с помощью _mm_movemask_epi8. Используйте четырехбитное значение в качестве входных данных для небольшой таблицы поиска.

person Yves Daoust    schedule 31.07.2015
comment
@user1235183 user1235183: проверьте дополнение. - person Yves Daoust; 31.07.2015

Как упоминалось здесь atan2() уже есть одна инструкция FPU: x87 код операции FPU FPATAN. Просто посмотрите на дизассемблирование, которое генерирует ваш компилятор, когда вы вызываете std::atan2(). Если это не единственная инструкция FPU, вы можете попробовать это во встроенной сборке GCC:

inline double my_atan2 (double y, double x) { 
  double result; 
  asm (
     "fpatan\n\t" 
     : "=t" (result)       // outputs; t = top of fpu stack
     : "0" (x),            // inputs; 0 = same as result
       "u" (y)             //         u = 2nd floating point register
     );   
  return result; 
}
person Serge Rogatch    schedule 31.07.2015
comment
Задержка FPATAN может составлять 150 циклов и более. - person Yves Daoust; 31.07.2015
comment
Большинство реализаций математических библиотек не используют fpatan, потому что без него можно работать лучше. Кроме того, получение данных между регистрами XMM и стеком x87 происходит медленно, и это дает только один результат atan2 за раз. Будущие читатели, см. agner.org/optimize для таблиц инструкций. - person Peter Cordes; 15.09.2017