Я изучаю инструкции SIMD ARM-v8 Aarch64, надеясь, что смогу оптимизировать некоторые вычисления. В этом случае я ищу операцию по модулю над вектором 4xf32.
Как я могу реализовать модуль с набором инструкций NEON?
Примечание. На самом деле я ищу что-то, чтобы гарантировать, что мои значения угла остаются между -PI и +PI (циклически, без ограничения), поэтому меня также интересуют другие решения для этого.
Примечание: в настоящее время я пытаюсь сделать это с заголовком Arm_neon.h в C, но в какой-то момент я мог бы сделать это напрямую с помощью ассемблера для еще большей оптимизации объединения инструкций без сохранения результатов в переменных.
Эх, ок. Но я спрашиваю о модуле с плавающей запятой. По целочисленному модулю я, по крайней мере, знаю несколько приемов, как это сделать.
Извините, я пропустил модуль поплавков. Не можете ли вы просто выполнить x mod y = x - y * (floor(x/y)), приведя к целым числам и обратно для пола? Я не очень знаком с НЕОНОМ.
Что касается встроенных функций: компилятор обычно делает свою работу довольно хорошо, поэтому, если вы не знаете, что ассемблерный код плох, вам не обязательно переходить на уровень ассемблера. Однако для обучения это все равно будет полезно.
@SimonGoater да, именно так я собирался решить эту проблему, если бы не было лучшего решения. Кажется, нет. Спасибо.
@fuz Интересно, это, безусловно, стоит изучить. Gcc способен оптимизировать (значительно) собственный сгенерированный стандартный код, поскольку он знает об используемых им инструкциях, но как только вы начнете вводить свои собственные инструкции, я не знаю, сможет ли он это оптимизировать.





Расширение набора команд ASIMD Armv8-A не имеет инструкций по модулю ни для чисел с плавающей запятой, ни для целых чисел. Однако для делителя 1 вы можете эмулировать по модулю, округляя число с помощью «преобразования в целое число», а затем вычитая из округленного числа, получая дробную часть с соответствующим знаком. Затем вы можете реализовать свою операцию по модулю с помощью этих тождеств:
fmod(a, 1) = a - round_towards_zero(a)
fmod(a, b) = fmod(a/b, 1) * b
Обратите внимание, что в вашем случае b является константой, поэтому это будет выглядеть так:
fmod(a, b) = a - round_towards_zero(a * 1/b) * b
Тогда это превращается в три инструкции: умножение a и 1/b, операция «округление к нулю» и операция «умножение и вычитание». Для еще большей производительности вам следует рассмотреть возможность сохранения предварительно масштабированных углов так, чтобы они находились в открытом интервале (-1, +1).
Еще одна вещь, которую следует учитывать: если известно, что углы выходят за пределы диапазона не более чем на b, может быть быстрее вместо этого сравнить с ±b и при необходимости условно добавить/вычесть b.
Именно так я собирался решить эту проблему, но немного разочарован. Спасибо!
Модуль чисел с плавающей запятой — не такая уж распространенная операция.
Фиксация чисел с плавающей запятой или двойных чисел в SIMD с помощью операций min и max будет намного проще, чем операция с целочисленным модулем.