Является ли float медленнее, чем double? 64-разрядная программа работает быстрее, чем 32-разрядная программа?
использует float
введите медленнее, чем с помощью double
тип?
Я слышал, что современные процессоры Intel и AMD могут выполнять вычисления с удвоениями быстрее, чем с поплавками.
насчет стандартных математических функций (sqrt
, pow
, log
, sin
, cos
, etc.)? Вычисление их с одной точностью должно быть значительно быстрее, поскольку для этого требуется меньше операций с плавающей запятой. Например, single precision sqrt
можно использовать более простую математическую формулу, чем double точность sqrt
. Кроме того, я слышал, что стандартные математические функции быстрее в 64-битном режиме (при компиляции и запуске на 64-битной ОС). Каков окончательный ответ на этот вопрос?
6 ответов
классическая архитектура x86 использует блок с плавающей запятой (FPU) для выполнения вычислений с плавающей запятой. FPU выполняет все вычисления в своих внутренних регистрах, которые имеют 80-разрядную точность каждый. Каждый раз, когда вы пытаетесь работать с float
или double
переменная сначала загружается из памяти во внутренний регистр сопроцессора FPU. Это означает, что нет абсолютно никакой разницы в скорости на реальных расчетах, так как в любом случае расчеты выполняются с полной 80-битной точностью. Единственное что может отличаться-скорость загрузки значения из памяти и запись результата обратно в память. Естественно, на 32-битной платформе загрузка / хранение double
по сравнению с float
. На 64-разрядной платформе не должно быть никакой разницы.
современные архитектуры x86 поддерживают расширенные наборы инструкций (SSE / SSE2) с новыми инструкциями, которые могут выполнять те же вычисления с плавающей запятой без привлечения " старого" FPU инструкции. Однако, опять же, я не ожидал бы увидеть какую-либо разницу в скорости расчета для float
и double
. И поскольку эти современные платформы являются 64-битными, скорость загрузки / хранения также должна быть одинаковой.
на другой аппаратной платформе ситуация может быть разной. Но обычно меньший тип с плавающей запятой не должен обеспечивать никаких преимуществ производительности. Основная цель меньших типов с плавающей запятой-сохранить память, а не улучшить спектакль.
Edit: (для адреса комментария @MSalters)
То, что я сказал выше, относится к фундаментальным арифметическим операциям. Когда дело доходит до библиотечных функций, ответ будет зависеть от нескольких деталей реализации. Если набор инструкций с плавающей запятой платформы содержит инструкцию, которая реализует функциональность данной библиотечной функции, то то, что я сказал выше, обычно будет применяться и к этой функции (которая обычно включает такие функции, как sin
, cos
, sqrt
). Для других функций, функциональность которых не сразу поддерживается в наборе инструкций FP, ситуация может оказаться значительно иной. Вполне возможно, что float
версии таких функций могут быть реализованы более эффективно, чем их double
версий.
ваш первый вопрос уже был ответ здесь на SO.
ваш второй вопрос полностью зависит от" размера " данных, с которыми вы работаете. Все сводится к низкоуровневой архитектуре системы и тому, как она обрабатывает большие значения. 64-битные данные в 32-битной системе потребуют 2 циклов для доступа к 2 регистрам. Те же данные в 64-битной системе должны принимать только 1 цикл для доступа к 1 регистру.
все всегда зависит от то, что ты делаешь. Я считаю, что нет быстрых и жестких правил, поэтому вам нужно проанализировать текущую задачу и выбрать то, что лучше всего подходит для ваших нужд для этой конкретной задачи.
из некоторых исследований и эмпирических измерений, которые я сделал на Java:
- основные арифметические операции на двойниках и поплавках по существу выполняются одинаково на оборудовании Intel, за исключением деления;
- С другой стороны, на Cortex-A8, как используется в iPhone 4 и iPad, даже "базовая" арифметика на двойниках занимает примерно в два раза больше времени, чем на поплавках (добавление регистра FP на поплавке занимает около 4ns против регистра FP на двойном 9нс);
- Я сделал несколько тайминги методов на java.утиль.Математика!--9--> (тригонометрические функции и т. д.), которые могут представлять интерес - в принципе, некоторые из них могут быть быстрее на поплавках, поскольку для вычисления точности поплавка потребуется меньше терминов; с другой стороны, многие из них оказываются "не такими плохими, как вы думаете";
также верно, что могут быть особые обстоятельства, в которых, например, проблемы с пропускной способностью памяти перевешивают " raw" время расчета.
" собственное " внутреннее представление с плавающей запятой в x86 FPU имеет ширину 80 бит. Это отличается от обоих float
(32 бита) и double
(64 бит). Каждый раз, когда значение перемещается в или из FPU, выполняется преобразование. Существует только одна инструкция FPU, которая выполняет грех операция, и она работает на внутреннем 80-битном представлении.
будет ли это преобразование быстрее float
или double
зависит от многих факторов, и должны быть измерены для данного приложения.
в то время как в большинстве систем double
будет такой же скоростью, как float
для отдельных значений, вы правы, что вычислительные функции, такие как sqrt
, sin
, etc. в одинарной точности должно быть намного быстрее, чем вычислять их с двойной точностью. В C99, вы можете использовать sqrtf
, sinf
, etc. функции, даже если ваши переменные double
, и получить выгоду.
еще одна проблема, которую я видел, - это пропускная способность памяти (а также устройства хранения). Если у вас есть миллионы или миллиарды ценностей, с которыми приходится иметь дело,float
почти наверняка будет вдвое быстрее, чем double
поскольку все будет связано с памятью или io-связью. Это хороший повод использовать float
как тип в массиве или на диске в некоторых случаях, но я бы не счел это хорошей причиной для использования float
для переменных, с которыми вы делаете свои вычисления.
Это зависит от процессора. Если процессор имеет собственные инструкции двойной точности, обычно быстрее просто выполнить арифметику двойной точности, чем получить float, преобразовать его в double, выполнить арифметику двойной точности, а затем преобразовать его обратно в float.