Использование double быстрее, чем float? - PullRequest
63 голосов
/ 06 августа 2010

Двойные значения сохраняют более высокую точность и в два раза больше числа с плавающей запятой, но оптимизированы ли процессоры Intel для операций с плавающей запятой?

То есть, двойные операции столь же быстрые или более быстрые, чем операции с плавающей запятой для +, -,* и /?

Меняется ли ответ для 64-разрядных архитектур?

Ответы [ 7 ]

72 голосов
/ 06 августа 2010

Не существует единого «процессора ЦП», особенно с точки зрения того, какие операции оптимизированы по отношению к другим !, но большинство из них, на уровне ЦП (особенно в пределах FPU), таковы, что ответ на ваш вопрос:

- двойные операции, такие же быстрые или быстрее, чем операции с плавающей точкой для +, -, * и /?

- это "да" - в ЦП , за исключением деления и sqrt, которые несколько медленнее для double, чем для float. (Предполагая, что ваш компилятор использует SSE2 для скалярной математики FP, как это делают все компиляторы x86-64, и некоторые 32-битные компиляторы, в зависимости от опций. В старых версиях x87 ширина регистров не различается, только в памяти (он конвертируется при загрузке / хранении) ), поэтому исторически даже sqrt и разделение были такими же медленными для double).

Например, Haswell имеет пропускную способность divsd один на 8-14 циклов (зависит от данных), но divss (скалярная единичная) пропускная способность один на 7 циклов. x87 fdiv - пропускная способность от 8 до 18 циклов. (Числа от https://agner.org/optimize/. Задержка коррелирует с пропускной способностью для деления, но выше, чем числа пропускной способности.)

Версии float многих библиотечных функций, таких как logf(float) и sinf(float), также будут быстрее , чем log(double) и sin(double), потому что они имеют намного меньше битов точности, чтобы получить право , Они могут использовать полиномиальные аппроксимации с меньшим количеством терминов, чтобы получить полную точность для float против double


Однако , занимающий вдвое больше памяти для каждого числа, явно подразумевает повышенную нагрузку на кэш (ы) и большую пропускную способность памяти для заполнения и пролива этих строк кэша из / в ОЗУ ; время, когда вы заботитесь о производительности операции с плавающей запятой, это когда вы выполняете много таких операций, поэтому вопросы памяти и кэша имеют решающее значение.

@ Ответ Ричарда указывает на то, что есть и другие способы выполнения операций FP (инструкции SSE / SSE2; старый добрый MMX был только для целых чисел), особенно подходящий для простых операций с большим количеством данных ( «SIMD», одна инструкция / несколько данных) где каждый векторный регистр может содержать 4 плавающих одинарной точности или только 2 с двойной точностью , поэтому этот эффект будет еще более заметным.

В конце концов, вам действительно нужно провести эталонный тест, но мой прогноз заключается в том, что для разумных (то есть больших ;-) эталонных тестов вы найдете преимущество придерживаться с одинарной точностью (при условии, конечно, что вам не нужны дополнительные биты точности! -).

24 голосов
/ 06 августа 2010

Если все вычисления с плавающей запятой выполняются в FPU, то нет, нет никакой разницы между вычислениями double и float, потому что операции с плавающей запятой фактически выполняются с точностью 80 битов вСтек FPU.Записи стека FPU округляются по мере необходимости для преобразования 80-битного формата с плавающей запятой в формат double или float с плавающей запятой.Перемещение sizeof(double) байтов в / из ОЗУ против sizeof(float) байтов является единственной разницей в скорости.

Если, однако, у вас есть векторизованное вычисление, то вы можете использовать расширения SSE для запуска четырех floatрасчеты одновременно с двумя double расчетами.Следовательно, разумное использование инструкций SSE и регистров XMM может обеспечить более высокую пропускную способность для вычислений, которые используют только float s.

10 голосов
/ 14 октября 2012

Я просто хочу добавить к уже существующим отличным ответам, что семейство __m256? семейства одинаковых инструкций с несколькими данными ( SIMD ) C ++ работает с либо 4 double с параллельно (например, _mm256_add_pd) или 8 float с параллельно (например, _mm256_add_ps).

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

10 голосов
/ 06 августа 2010

Еще один момент, который следует учитывать, если вы используете GPU (видеокарту). Я работаю с проектом, интенсивно работающим в цифровом формате, но нам не нужно разрешение, которое предлагает двойное предложение. Мы используем карты GPU, чтобы ускорить процесс обработки. Графическим процессорам CUDA требуется специальный пакет для поддержки double, а объем локальной оперативной памяти на графическом процессоре довольно быстрый, но довольно скудный. В результате использование float также удваивает объем данных, которые мы можем хранить на графическом процессоре.

Еще один момент - это память. Поплавки занимают вдвое больше оперативной памяти, чем удваиваются. Если вы имеете дело с ОЧЕНЬ большими наборами данных, это может быть действительно важным фактором. Если использование двойного означает, что вы должны кэшировать на диск против чистого оперативной памяти, ваша разница будет огромной.

Так что для приложения, с которым я работаю, разница весьма важна.

9 голосов
/ 18 марта 2012

В экспериментах по добавлению 3.3 для 2000000000 раз получаются следующие результаты:

Summation time in s: 2.82 summed value: 6.71089e+07 // float
Summation time in s: 2.78585 summed value: 6.6e+09 // double
Summation time in s: 2.76812 summed value: 6.6e+09 // long double

Таким образом, удвоение происходит быстрее и по умолчанию в C и C ++.Он более переносим и используется по умолчанию для всех функций библиотеки C и C ++.Alos double имеет значительно более высокую точность, чем float.

Даже Stroustrup рекомендует double over float:

"Точное значение одинарной, двойной и расширенной точности определяется реализацией. ВыборПравильная точность для задачи, где выбор имеет значение, требует значительного понимания вычислений с плавающей запятой. Если у вас нет такого понимания, получите совет, найдите время, чтобы научиться, или используйте удвоение и надейтесь на лучшее. "

Возможно, единственный случай, когда вы должны использовать float вместо double, это на 64-битном оборудовании с современным gcc.Потому что поплавок меньше;double - 8 байтов, а float - 4 байта.

7 голосов
/ 06 августа 2010

Единственный действительно полезный ответ: только вы можете сказать.Вы должны сравнить свои сценарии.Небольшие изменения в шаблонах команд и памяти могут оказать существенное влияние.

Это, безусловно, будет иметь значение, если вы используете аппаратное обеспечение типа FPU или SSE (первое выполняет всю свою работу с расширенной точностью 80 бит, поэтому double будет ближе;позже он изначально 32-битный, то есть с плавающей точкой).

Обновление: s / MMX / SSE /, как отмечено в другом ответе.

2 голосов
/ 06 августа 2010

Число с плавающей запятой, как правило, является расширением универсального процессора.Поэтому скорость будет зависеть от используемой аппаратной платформы.Если у платформы есть поддержка с плавающей запятой, я буду удивлен, если есть какая-либо разница.

...