Эффективный способ добавить два массива с плавающей точкой в ​​C? - PullRequest
2 голосов
/ 29 сентября 2019

Мое аудио приложение MacOS использует цикл for для добавления двух массивов с плавающей точкой.Есть ли более эффективный способ, когда size огромен?

int size = 5;
float array1[size] = {0.0, 0.1, 0.2, 0.3, 0.4};
float array2[size] = {0.5, 0.6, 0.7, 0.8, 0.9};
float sum[size];

for (int i = 0; i < size; i ++)
{
    sum[i] = array1[i] + array2[i];
}

Ответы [ 3 ]

3 голосов
/ 29 сентября 2019

Наиболее значимый трюк, который вы можете сделать: если эти массивы на самом деле указатели и вы передаете их в функцию, обязательно restrict - квалифицируйте указатель суммы, еслина самом деле предполагается, что он указывает на массив, который не зависит от 2:

void do_sum(size_t size,
            float * restrict sum,
            float * array1,
            float * array2)

или с подсказками размера

void do_sum(size_t size,
            float sum[restrict static size],
            float array1[static size],
            float array2[static size])

Это позволит компилятору генерировать гораздо более эффективнокод, потому что он гарантирует, что ни array1[n], ни array2[n] не смогут получить доступ к той же памяти, что и sum[k] для любого n или k, используемого в функции

Посмотрите разницу в Godbolt: с ограничением и без

2 голосов
/ 29 сентября 2019

Если это работает на оборудовании мощностью более нескольких ватт (что угодно, кроме телефона десятилетнего возраста без встроенного FPU и без компилятора, который знает, как использовать экзотические инструкции процессора), в эффективности будет доминировать памятькэширование и пропускная способность шины, поэтому хитрые трюки на Си не будут иметь значения.Единственным значительным ускорением было бы перезаписать один из массивов:
... array1[i] += array2[i];

1 голос
/ 30 сентября 2019

Для macOS (как поясняется в комментарии) решение является простым, по крайней мере, для одной операции добавления.Вставьте #include <Accelerate/Accelerate.h> в код, добавьте Accelerate framework в свой проект и измените цикл на одиночный вызов на vDSP_vadd(sum, 1, array1, 1, array2, 1, size);.При этом используется высокопроизводительная векторизованная подпрограмма, которую Apple настраивает для каждой поддерживаемой платформы.

(* Параметры 1 - это шаги по массивам в единицах элементов. 1 означает обработку каждого элемента иЭто лучший показатель для повышения производительности.)

Поскольку вы работаете с 524 288 элементами, вы также должны учитывать, как ваше приложение взаимодействует с кеш-памятью.Проектирование для высокой производительности не может быть сделано изолированно, рассматривая только каждую процедуру в отдельности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...