Что касается арифметики произвольной точности: можно ли использовать AVX-512 для вычисления умножения двух 256-битных целых чисел на 64-битном компьютере на C++? Существует ли встроенный 512-битный тип данных Integer для результата в компиляторе C++, который делает это возможным?
Если это невозможно, можно ли это сделать на языке ассемблера? Если да, то можно ли вызвать эту процедуру на языке ассемблера из программы на C++? Может ли 512-битный результат процедуры языка ассемблера использоваться 64-битными целочисленными типами данных без использования строки?
512 означает максимальный объем данных, которые могут быть обработаны одновременно, но каждый элемент в 512-битном блоке по-прежнему имеет длину не более 64 бит intel.com/content/www/us/en/docs/intrinsics-guide/index. html#
Технически да, но не с одной инструкцией с простым форматом хранения. См. Могут ли подпрограммы с длинными целыми числами выиграть от SSE? - ускорение возможно при использовании форматов хранения, которые оставляют некоторые биты неиспользованными в каждой 64-битной конечности, что позволяет AVX-512IFMA или bithacks использовать часть мантиссы FMA (как это делает Prime95 или y-Cruncher).
Да и нет.
Нет, в AVX-512 нет инструкции по умножению двух 256-битных операндов для получения 512-битного результата. Максимальные операнды, которые вы можете умножить, имеют длину 64 бита каждый, чтобы получить 128-битный результат.
Итак, чтобы умножить 256-битные операнды, вы делаете что-то вроде умножения в начальной школе. За исключением того, что вы хотите рассматривать 256-битное число как четырехзначное число по основанию 264. Итак, у вас есть что-то вроде:
D C B A
H G F E
--------------------
ED EC EB EA
FD FC FB FA 0
GD GC GB GA 0 0
HD HC HB HA 0 0 0
--------------------
[где HD означает H*D
, GB означает G*B
и так далее.]
Итак, как и в начальной школе, мы умножаем каждую цифру одного на каждую цифру другого, переносим верхнюю цифру каждого в следующий столбец и складываем все частичные произведения вместе, чтобы получить окончательный результат.
Разница в том, что вместо того, чтобы каждая цифра была цифрой от 0 до 9, в этом случае каждая цифра идет от 0 до 264-1.
Но да, поскольку вам приходится выполнять одинаковые операции с каждым из нескольких операндов, вполне разумно выполнять их параллельно, используя векторные инструкции. Но это просто параллельное выполнение нескольких 64-битных умножений, а не работа с каким-либо отдельным операндом, размер которого превышает 64 бита1.
Если вы работаете с действительно большими числами (например, миллионами цифр или более), есть более эффективные методы умножения, такие как умножение Карацубы и умножение Шёнхаге-Штрассена, но 512 бит почти наверняка слишком малы для того, чтобы получить заметную выгоду от таких вещей.
Хороший ответ. Но… поправьте меня, если я ошибаюсь: для этого вам понадобится 64-битное умножение, которое генерирует 128-битные результаты, верно? Возвращаясь к примеру с начальной школой, вам нужно выполнить однозначное умножение, которое может привести к двузначному результату (9x9 = 81 и т. д.). Поскольку в AVX этого нет, нам нужно выполнить векторизованное 32-битное умножение, которое даст 64-битный результат. И когда мы делаем сложения, нам приходится беспокоиться о битах переноса.
@Homer512: Homer512: Да, это правда. Если вы имеете дело с чем-то, что не может генерировать результат двойного размера, вы обычно начинаете с разбиения его на 32-битные фрагменты, чтобы отдельные результаты помещались в 64-битные регистры (или, в более общем смысле, в отдельные регистры). размер регистра, чтобы каждый результат помещался в регистр).
Вам придется много перетасовывать и складывать с переносом, что, вероятно, не оправдает затраченных усилий, если вы создадите только один продукт размером 256x256. Если у вас действительно большие продукты и у вас есть AVX512IFMA52, возможно, стоит рассмотреть возможность разделения числа на 52-битные части (vpmadd52luq
и vpmadd52huq
имеют лучшую пропускную способность, а окончательное сложение переноса можно выполнить в самом конце).
Вы можете использовать Intel Intrinsics для доступа ко всем инструкциям AVX512 из C/C++. Однако AVX не имеет расширенного умножения. Лучшее, что вы можете получить, — это векторизованное знаковое 64-битное умножение, которое возвращает младшие 64 бита результата для 8 независимых умножений (
_mm512_mullo_epi64
) или 8 x 32-битных умножений с полными 64-битными результатами (_mm512_mul_epi32
для знаковых,_mm512_mul_epu32
для беззнаковых).