С плавающей точкой по сравнению с фиксированной точкой: каковы плюсы / минусы?

Тип с плавающей запятой представляет собой число, сохраняя его значащие цифры и показатель степени отдельно в отдельных двоичных словах, поэтому он умещается в 16, 32, 64 или 128 бит.

Тип с фиксированной запятой хранит числа с 2 словами, одно из которых представляет целую часть, другое представляет часть после радиуса, в отрицательных показателях, 2^-1, 2^-2, 2^-3 и т. Д.

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

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

В программировании видеоигр все используют плавающую точку, потому что FPU делает это быстрее, или потому что падение производительности просто ничтожно, или они делают свой собственный фиксированный тип?

Почему в C/C++ нет фиксированного типа?

8 ответов

Решение

Это определение охватывает очень ограниченное подмножество реализаций с фиксированной запятой.

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

  • 64-битная мантисса, масштабируется на 2-32 (это соответствует определению, указанному в вопросе)
  • 64-битная мантисса, масштабируется на 2-33 (теперь целая и дробная части не могут быть разделены границей октета)
  • 32-битная мантисса, масштабируется на 24 (теперь нет дробной части)
  • 32-битная мантисса, масштабируется на 2-40 (теперь нет целочисленной части)

Графические процессоры, как правило, используют фиксированную точку без целочисленной части (обычно 32-битная мантисса, масштабированная до 2-32). Поэтому такие API, как OpenGL и Direct3D, часто используют типы с плавающей запятой, которые могут содержать эти значения. Однако манипулирование целочисленной мантиссой часто более эффективно, поэтому эти API-интерфейсы также позволяют указывать координаты (в текстурном пространстве, цветовом пространстве и т. Д.).

Что касается вашего утверждения, что C++ не имеет типа с фиксированной запятой, я не согласен. Все целочисленные типы в C++ являются типами с фиксированной запятой. Экспонента часто принимается равной нулю, но это не обязательно, и у меня есть немного кода DSP с фиксированной точкой, реализованного таким образом в C++.

На уровне кода арифметика с фиксированной точкой является просто целочисленной арифметикой с подразумеваемым знаменателем.

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

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

Некоторые архитектуры предоставляют аппаратные реализации для определенных математических функций, таких как sin, cos, atan, sqrt, только для типов с плавающей точкой. Некоторые архитектуры вообще не предоставляют никакой аппаратной реализации. В обоих случаях специализированные математические программные библиотеки могут предоставлять эти функции, используя только целочисленную или арифметику с фиксированной запятой. Зачастую такие библиотеки обеспечивают несколько уровней точности, например, ответы, которые являются точными только с точностью до N-битов, что меньше, чем полная точность представления. Версии с ограниченной точностью могут быть быстрее, чем версии с самой высокой точностью.

Фиксированная точка широко используется в DSP и встроенных системах, где часто целевой процессор не имеет FPU, а фиксированная точка может быть реализована достаточно эффективно с использованием целочисленного ALU.

С точки зрения производительности это может варьироваться в зависимости от целевой архитектуры и приложения. Очевидно, что если нет FPU, то фиксированная точка будет значительно быстрее. Когда у вас есть FPU, это также зависит от приложения. Например, выполнение некоторых функций, таких как sqrt() или log(), будет намного быстрее, если поддерживается напрямую в наборе команд, а не реализовано алгоритмически.

Нет встроенного типа с фиксированной точкой в ​​C или C++, я думаю, потому что они (или, по крайней мере, C) были предусмотрены как языки системного уровня, и нужда в фиксированной точке в некоторой степени зависит от предметной области, а также, возможно, потому, что на процессоре общего назначения есть как правило, нет прямой аппаратной поддержки для фиксированной точки.

В C++ определение класса типа данных с фиксированной точкой с подходящими перегрузками операторов и связанными математическими функциями может легко преодолеть этот недостаток. Однако есть хорошие и плохие решения этой проблемы. Хороший пример можно найти здесь: http://www.drdobbs.com/cpp/207000448. Ссылка на код в этой статье не работает, но я отследил ее до ftp://66.77.27.238/sourcecode/ddj/2008/0804.zip

Вы должны быть осторожны при обсуждении "точности" в этом контексте.

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

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

И так далее.

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

Например, вы можете определить ширину экрана / видового экрана в диапазоне от 0,0 до 1,0, а высоту экрана - от 0,0 до 1,0. Глубина слова от 0,0 до 1,0. и так далее. Математическая математика и т. Д. Делает вещи действительно простыми для реализации. Сделайте всю математику до того момента, когда вам нужно вычислить реальные пиксели на реальном размере экрана, скажем, 800x400. Проецируйте луч от глаза к точке на объекте в мире и вычислите, где он прокалывает экран, используя 0 к 1 математике, затем умножьте x на 800, y на 400 и поместите этот пиксель.

Плавающая точка не хранит экспоненту и мантиссу отдельно, а мантисса - это глупое число, которое остается после экспоненты и знака, как 23 бита, а не 16, 32 или 64 бита.

математика с плавающей точкой в ​​своей основе использует логику с фиксированной точкой с дополнительной логикой и необходимыми дополнительными шагами. По определению, сравнивать яблоки с яблоками математика с фиксированной точкой дешевле, потому что вам не нужно манипулировать данными на пути в alu и не нужно манипулировать данными на выходе (нормализовать). Когда вы добавляете в IEEE и весь его мусор, который добавляет еще больше логики, больше тактов и т. Д. (Правильно подписанные бесконечности, тихие и сигнальные nans, разные результаты для той же операции, если включен обработчик исключений). Как кто-то указал в комментарии в реальной системе, где вы можете фиксировать и перемещать параллельно, вы можете воспользоваться некоторыми или всеми процессорами и таким образом восстановить некоторые часы. как с плавающей, так и с фиксированной тактовой частотой можно увеличить, используя огромное количество чипов, фиксированная останется дешевле, но с плавающей точкой можно приблизиться к фиксированной скорости, используя эти виды трюков, а также параллельную работу.

Разница между вычислением с плавающей запятой и целочисленной математикой зависит от вашего процессора. На чипах Intel разница в часах невелика. Int math все еще быстрее, потому что есть несколько целочисленных ALU, которые могут работать параллельно. Компиляторы также умны использовать специальные инструкции для расчета адреса для оптимизации сложения / умножения в одной инструкции. Конверсия тоже считается операцией, поэтому просто выберите свой тип и придерживайтесь его.

В C++ вы можете создать свой собственный тип для математики с фиксированной запятой. Вы просто определяете как struct с одним int и переопределяете соответствующие перегрузки, и заставляете их делать то, что они обычно делают плюс сдвиг, чтобы вернуть запятую в правильное положение.

Один из вопросов, который не был рассмотрен, - это энергопотребление. Хотя это сильно зависит от конкретной аппаратной архитектуры, обычно FPU потребляет гораздо больше энергии, чем ALU в ЦП, поэтому, если вы ориентируетесь на мобильные приложения, где энергопотребление важно, стоит рассмотреть возможность реализации алгоритма с фиксированной запятой.

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

Плюсы и минусы сводятся к скорости и ресурсам. На современных 32-битных и 64-битных платформах действительно нет необходимости использовать фиксированную точку. Большинство систем поставляются со встроенными FPU, которые специально спроектированы для работы с фиксированной точкой. Кроме того, большинство современных встроенных функций процессора поставляются с такими операциями, как набор SIMD, которые помогают оптимизировать методы на основе векторов посредством векторизации и развертывания. Так что фиксированная точка идет только с обратной стороной.

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

Другие вопросы по тегам