Использует ли double быстрее, чем float?


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

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

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

7   60   2010-08-06 21:23:40

7 ответов:

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

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

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

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

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


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

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

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

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

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

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

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

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

в экспериментах добавления 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

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

даже Страуструп рекомендует удвоить поплавок:

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

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

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

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

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

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

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

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