Поплавок медленнее, чем в два раза? Работает ли 64-разрядная программа быстрее, чем 32-битная программа?

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

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

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

Ответ 1

Классическая архитектура 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.

Ответ 2

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

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