Каков самый быстрый способ сопоставить uint64_t {0,1} с float 64 {1.0,-1.0}?C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Каков самый быстрый способ сопоставить uint64_t {0,1} с float 64 {1.0,-1.0}?

Сообщение Anonymous »


У меня есть 64-битное целое число без знака uint64_t, переменная-флаг, называемая uintflag, которая может содержать только значения 0 или 1.
>
Мне нужно преобразовать 0 в 1.0 и 1 в -1.0. Это преобразование происходит из uint64_t (64-разрядного) в двойной (64-разрядный).

Хотя тесты проводятся на платформе x86-64, я пишу GNU и не знаю, на каком процессоре он может быть запущен, поэтому цель состоит в том, чтобы написать переносимый код, который может работать на различных архитектурах. Поэтому, чтобы обеспечить корректность на разных платформах, я не могу полагаться на битовые форматы, специфичные для x86. Я отдаю предпочтение правильности, а не оптимизации производительности для платформ, отличных от x86.

В x86 преобразование uint в double занимает 5 циклов, поэтому это дорого

return double(1.0 - 2.0 * uintflag); if не намного лучше, возможно, потому, что он не является безветвевым, а код без ветвей обычно работает быстрее.

return uintflag ? двойной (-1,0): двойной (1,0); Я также пробовал использовать массив, содержащий значения с плавающей запятой, и использовать uint в качестве индекса.

Это, как правило, лучше, поскольку не имеет ветвей и не выполняет приведение типов от int к double, но я подозреваю, что они извлекаются из кэша L1, что занимает около 10 циклов.

double arrayMap[2] = {1.0, -1.0}; вернуть arrayMap[uintflag]; Существует ли какой-либо подход, который гарантирует, что массив находится в регистрах ЦП и не извлекается из кэша L1?

Я получаю противоречивые результаты тестов. Можете ли вы помочь мне определить правильный подход к сравнительному тестированию и определить наиболее эффективный метод преобразования uintflag в двойное значение?

Среднее время getFromArray: 5768500 наносекунд Среднее время ifBranching: 6114700 наносекунд. Среднее время выполнения mathFormulaCasingtoFloat: 6803000 наносекунд. Среднее время getFromArray: 8157100 наносекунд. Среднее время ifBranching: 9361300 наносекунд. Среднее время выполнения mathFormulaCasingtoFloat: 16988800 наносекунд. Среднее время getFromArray: 8792100 наносекунд. Среднее время ifBranching: 7761900 наносекунд. Среднее время выполнения mathFormulaCasingtoFloat: 8643100 наносекунд. Вот код
#include #include #include #include #include использование пространства имен std; typedef double (*conversion_function)(uint64_t); двойной ifBranching (uint64_t uintflag) { вернуть uintflag? двойной (-1,0): двойной (1,0); } двойной arrayMap[2] = {1.0, -1.0}; двойной getFromArray (uint64_t uintflag) { вернуть arrayMap[uintflag]; } двойная математикаFormulaCasingtoFloat (uint64_t uintflag) { return double(1.0 - 2.0 * uintflag); } интервал основной() { uint64_t uintflag = 1; карта функции преобразования; конверсионные_функции["ifBranching"] = ifBranching; конверсионные_функции["getFromArray"] = getFromArray; конверсионные_функции["mathFormulaCasingtoFloat"] = mathFormulaCasingtoFloat; const int numRuns = 100000; for (авто &[имя_функции, функция]: функции преобразования) { auto totalDuration = Chronic::duration::zero(); for (int я = 0; я
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»