С плавающей точкой по сравнению с фиксированной точкой: каковы плюсы / минусы?
Тип с плавающей запятой представляет собой число, сохраняя его значащие цифры и показатель степени отдельно в отдельных двоичных словах, поэтому он умещается в 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 или расширенных наборов команд. В этом случае вы можете быть вынуждены использовать методы с фиксированной запятой или ограниченные наборы команд с плавающей запятой, которые не очень быстрые. Таким образом, в этих обстоятельствах фиксированная точка будет лучшим - или даже вашим единственным - выбором.