Является ли float медленнее, чем double? 64-битная программа работает быстрее, чем 32-битная?

Использование типа float медленнее, чем использование типа double?

Я слышал, что современные процессоры Intel и AMD могут выполнять вычисления с удвоениями быстрее, чем с числами с плавающей запятой.

Как насчет стандартных математических функций (sqrt, pow, log, sin, cos и т. д.)? Вычисление их с одинарной точностью должно быть значительно быстрее, поскольку для этого требуется меньше операций с плавающей запятой. Например, одинарная точность sqrt может использовать более простую математическую формулу, чем двойная точность sqrt. Кроме того, я слышал, что стандартные математические функции работают быстрее в 64-битном режиме (при компиляции и запуске в 64-битной ОС). Каков окончательный ответ на это?


person Boba Fet    schedule 21.04.2011    source источник
comment
Что быстрее, мой Феррари или твой самосвал? Это зависит от того, пытаетесь ли вы пробежать четверть мили, возможно, это Феррари. Если вы пытаетесь перевезти 5 тонн гравия, скорее всего, самосвал. Это зависит от того, что вы делаете. Это не вопрос, на который можно ответить.   -  person Ken White    schedule 21.04.2011
comment
@Кен Уайт: Конечно, это зависит от того, кто буксирует другого!   -  person Greg Hewgill    schedule 21.04.2011
comment
Однозначный ответ состоит в том, что на такие общие вопросы нет однозначного ответа.   -  person Tim Sylvester    schedule 21.04.2011
comment
@ Тим Сильвестр. Да, похоже, это не так просто, как я. Мне пришлось бы поэкспериментировать с моим кодом, чтобы выяснить, как сделать его быстрее.   -  person Boba Fet    schedule 21.04.2011
comment
@Кен Уайт. Это математический проект. Очень долго кончается. Я пытаюсь заставить его работать быстрее.   -  person Boba Fet    schedule 21.04.2011
comment
См. мой ответ ниже для получения информации о времени, которое я сделал для операций в Java, на случай, если это будет полезно.   -  person Neil Coffey    schedule 21.04.2011
comment
@BobaFet: всегда начинайте с алгоритма. Это неоптимально.   -  person PlasmaHH    schedule 14.05.2012


Ответы (6)


Классическая архитектура x86 использует модуль с плавающей запятой (FPU) для выполнения вычислений с плавающей запятой. FPU выполняет все вычисления в своих внутренних регистрах, каждый из которых имеет 80-битную точность. Каждый раз, когда вы пытаетесь работать с float или double, переменная сначала загружается из памяти во внутренний регистр FPU. Это означает, что нет абсолютно никакой разницы в скорости реальных вычислений, так как в любом случае вычисления выполняются с полной 80-битной точностью. Единственное, что может отличаться, это скорость загрузки значения из памяти и сохранения результата обратно в память. Естественно, на 32-битной платформе загрузка/сохранение double может занять больше времени, чем float. На 64-битной платформе разницы быть не должно.

Современные архитектуры x86 поддерживают расширенные наборы инструкций (SSE/SSE2) с новыми инструкциями, которые могут выполнять те же самые вычисления с плавающей запятой без использования «старых» инструкций FPU. Однако, опять же, я не ожидал увидеть никакой разницы в скорости вычислений для float и double. А так как эти современные платформы 64-битные, то и скорость загрузки/сохранения должна быть одинаковой.

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

Изменить: (Чтобы обратиться к комментарию @MSalters) То, что я сказал выше, относится к фундаментальным арифметическим операциям. Когда дело доходит до библиотечных функций, ответ будет зависеть от нескольких деталей реализации. Если набор инструкций платформы с плавающей запятой содержит инструкцию, которая реализует функциональность данной библиотечной функции, то то, что я сказал выше, обычно применимо и к этой функции (обычно это включает такие функции, как sin, cos, sqrt). Для других функций, функциональность которых не поддерживается непосредственно в наборе инструкций FP, ситуация может оказаться существенно иной. Вполне возможно, что float версии таких функций могут быть реализованы более эффективно, чем их double версии.

person AnT    schedule 21.04.2011
comment
Почему поплавки не работают быстрее на SSE/SSE2? Я читал, что SSE может делать 4x32-битные числа с плавающей запятой и только 2x64-битные удвоения одновременно. Я не использую SSE напрямую, но думаю, что мой компилятор может векторизовать некоторые простые циклы для использования SSE. Я использую компилятор Intel, но еще не прочитал руководство полностью. Я думаю, что С# не может векторизовать любые циклы. - person Boba Fet; 21.04.2011
comment
@Boba Fet: я рассматривал только невекторизованные вычисления. Для векторизованных вычислений все может оказаться иначе по причинам, которые вы только что упомянули. - person AnT; 21.04.2011
comment
Шина памяти 64-битная со времен Pentium. Загрузка 1 поплавка или 1 двойника одинакова. Разница возникает, если вы загружаете более 1 значения, тогда в float 2 значения могут быть загружены в каждой транзакции. - person Patrick Schlüter; 21.04.2011
comment
-1. Утверждение, что вычисления выполняются с полной 80-битной точностью, ошибочно неверно для вопроса: стандартные математические функции (sqrt, pow, log, sin, cos и т. д.). Да, собственные операции x87 выполняются с полной точностью. Но pow не родная операция x87, это нетривиальная функция. 32-битная реализация этой функции может быть быстрее, потому что она использует меньше 80-битных операций (примечание: проблема намного хуже для новых математических функций C99, источник: Мистер Плаугер) - person MSalters; 21.04.2011

На ваш первый вопрос уже был дан ответ здесь, на SO.

Ваш второй вопрос полностью зависит от «размера» данных, с которыми вы работаете. Все сводится к низкоуровневой архитектуре системы и тому, как она обрабатывает большие значения. 64-битные данные в 32-битной системе потребуют 2 тактов для доступа к 2 регистрам. Те же самые данные в 64-битной системе должны занимать только 1 цикл для доступа к 1 регистру.

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

person Pete    schedule 21.04.2011
comment
Спасибо за ссылку. Удивительно, что использование float может замедлить работу. Похоже, это сложнее, чем я думал. - person Boba Fet; 21.04.2011
comment
Да, есть много вещей, которые мы принимаем как должное. Только когда я прошел курс микропроцессоров, я понял всю работу, которую требует ЦП для выполнения простых вещей, таких как представление отрицательных чисел, десятичных знаков и т. д. Чем больше данные (больше точность, большие числа), с которыми вы работаете. тем больше работы должен выполнять процессор. - person Pete; 21.04.2011
comment
Нет, начиная с Pentium все шины данных имеют ширину 64 бита. Загрузка double (если он выровнен) занимает всего 1 цикл шины. - person Patrick Schlüter; 21.04.2011

Хотя в большинстве систем double будет иметь ту же скорость, что и float для отдельных значений, вы правы в том, что вычисление таких функций, как sqrt, sin и т. д. с одинарной точностью, должно быть намного быстрее, чем их вычисление с двойной точностью. В C99 вы можете использовать функции sqrtf, sinf и т. д., даже если ваши переменные double, и получить преимущество.

Еще одна проблема, о которой я упоминал, - это пропускная способность памяти (а также устройства хранения). Если вам приходится иметь дело с миллионами или миллиардами значений, float почти наверняка будет в два раза быстрее, чем double, поскольку все будет привязано к памяти или вводу-выводу. Это хорошая причина для использования float в качестве типа в массиве или в дисковом хранилище в некоторых случаях, но я бы не считал это хорошей причиной для использования float для переменных, с которыми вы выполняете свои вычисления.

person R.. GitHub STOP HELPING ICE    schedule 21.04.2011

Из некоторых исследований и эмпирических измерений, которые я сделал на Java:

  • основные арифметические операции с числами типа double и float практически идентичны на оборудовании Intel, за исключением деления;
  • с другой стороны, на Cortex-A8, который используется в iPhone 4 и iPad, даже «базовая» арифметика для двойных чисел занимает примерно в два раза больше времени, чем для чисел с плавающей запятой (добавление FP регистра для числа с плавающей запятой занимает около 4 нс по сравнению с FP регистра для числа с плавающей запятой). двойной занимает около 9 нс);
  • Я сделал некоторые тайминги методов в java.util.Math (тригонометрические функции и т. д.), что может представлять интерес - в принципе, некоторые из них могут работать быстрее с числами с плавающей запятой, поскольку для расчета с точностью до числа с плавающей запятой потребуется меньше терминов; с другой стороны, многие из них оказываются «не такими плохими, как вы думаете»;

Верно также и то, что могут быть особые обстоятельства, при которых, например. проблемы с пропускной способностью памяти перевешивают время «сырых» вычислений.

person Neil Coffey    schedule 21.04.2011

«Родное» внутреннее представление с плавающей запятой в x86 FPU имеет ширину 80 бит. Это отличается как от float (32 бита), так и от double (64 бита). Каждый раз, когда значение перемещается в FPU или из него, выполняется преобразование. Существует только одна инструкция FPU, которая выполняет операцию sin и работает с внутренним 80-битным представлением.

Будет ли это преобразование быстрее для float или для double, зависит от многих факторов и должно быть измерено для данного приложения.

person Greg Hewgill    schedule 21.04.2011

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

person QuantumMechanic    schedule 21.04.2011
comment
Привет. Мы используем Intel Core 2 и новее и AMD Opteron. Я заметил, что переключение на float происходит несколько медленнее. - person Boba Fet; 21.04.2011