Русская Википедия:Число с фиксированной запятой
Число с фиксированной запятой (Шаблон:Lang-en) — формат представления вещественного числа в памяти ЭВМ в виде целого числа. При этом само число x и его целочисленное представление x′ связаны формулой
- <math>x = x' \cdot z</math>,
где z — цена (вес) младшего разряда.
В случае, если <math>z<1</math>, для удобства расчётов его делают дольным единице, чтобы целые числа кодировались без погрешности. Другими словами, выбирают целое число u (машинную единицу) и принимают <math>z = \frac 1 u</math>. В случае, если <math>z>1</math>, его делают целым.
Если не требуется, чтобы какие-либо конкретные дробные числа входили в разрядную сетку, программисты обычно выбирают {{{1}}} это позволяет использовать в операциях умножения и деления битовые сдвиги. Про такую арифметику говорят: «f битов на дробную часть, i=n−f — на целую» и обозначают как «i,f», «i.f» или «Qi.f» (см. Шаблон:Iw). Например: арифметика 8,24 отводит на целую часть 8 бит и 24 — на дробную. Соответственно, она способна хранить числа от −128 до 128−z с ценой (весом) младшего разряда <math>z = 2^{-24} = 5{,}96 \cdot 10^{-8}</math>.
Для угловых величин зачастую делают <math>z=2 \pi \cdot 2^{-f}</math> (особенно если тригонометрические функции вычисляются по таблице).
Название
Название «фиксированная запятая» (или «фиксированная точка»; далее — ФЗ) произошло из-за простой метафоры: между двумя заранее определёнными разрядами ставится запятая для превращения целого числа в дробное. Например, целое число 1234 после вставки запятой превращается в дробное 12,34.
В Великобритании, США и других странах вместо запятой для отделения целой части числа от дробной используется точка, поэтому понятия «фиксированная точка» и «фиксированная запятая» эквивалентны.
Применение
Арифметику с фиксированной запятой часто применяют в тех областях, когда использование чисел с плавающей запятой затратно или невозможно ввиду используемой архитектуры процессоров. Например, видеосопроцессоры приставок PlayStation (Sony), Saturn (Sega), Game Boy Advance (Nintendo), Nintendo DS, GP2X используют арифметику с фиксированной запятой для того, чтобы увеличить пропускную способность на архитектурах без FPU. Стандарт OpenGL ES 1.x включает поддержку чисел с фиксированной запятой, так как он создан для встраиваемых систем, у которых часто нет FPU.
Кроме того, арифметику с фиксированной запятой используют для обеспечения минимальной поддержки дробных чисел на целочисленном процессоре: микроконтроллера, мобильного телефона, приставок вплоть до Playstation и т. д. Если не решаются некорректные задачи и СЛАУ высокого порядка, фиксированной запятой зачастую достаточно — важно только подобрать подходящую цену (вес) младшего разряда для каждой из величин.
Числа с фиксированной запятой используют там, где не нужна высокая точность, но требуется производительность. В большинстве современных процессоров ФЗ аппаратно не реализована, но даже программная ФЗ очень быстра — поэтому она применяется в разного рода игровых движках, растеризаторах[1] и т. д. Например, движок Doom для измерения расстояний использует арифметику Q16.16, для углов — 360°=232.
Также фиксированную запятую удобно использовать для записи чисел, которые по своей природе имеют постоянную абсолютную погрешность: координаты в программах вёрстки, отметки времени, денежные суммы. Например, и сдачу в супермаркете, и налоги в стране вычисляют с точностью до сотой доли. Файлы метрики шрифтов TeX используют 32-битный знаковый тип с фиксированной запятой Q12.20, библиотека растеризации шрифтов FreeType — Q26.6[2]. На подобные величины можно отдать и плавающую запятую с достаточным количеством знаков мантиссы — но тогда поле порядка становится излишним. Кроме того, фиксированная запятая ведёт себя абсолютно предсказуемо — при подсчёте денег это позволяет наладить разные виды округления, а в играх — наиболее простой способ реализовать многопользовательский режим и запись повторов.
Недостатки
Недостаток фиксированной запятой — очень узкий диапазон чисел, с угрозой переполнения на одном конце диапазона и потерей точности вычислений на другом. В сложных вычислениях приходится постоянно вписываться в этот диапазон с помощью перемасштабирования — использования разных форматов фиксированной запятой для величин времени, координаты, скорости… Эта проблема и привела к изобретению плавающей запятой. Например: если нужна точность в 3 значащих цифры, 4-байтовая фиксированная запятая даёт диапазон в 6 порядков (то есть, разница приблизительно 106 между самым большим и самым маленьким числом), 4-байтовое число одинарной точности — в 70 порядков.
Реализации
Немногие языки программирования предоставляют встроенную поддержку чисел с фиксированной запятой, поскольку для большинства применений двоичное или десятичное представление чисел с плавающей запятой проще и достаточно точно. Числа с плавающей запятой проще из-за их большего динамического диапазона, для них не нужно предварительно задавать количество цифр после запятой. Если же потребуется арифметика с фиксированной запятой, она может быть реализована программистом на используемом им языке.
Числа с фиксированной запятой в формате BCD часто используются для хранения денежных величин — неточности от форматов с плавающей запятой недопустимы, а простеньким микроконтроллерам платёжных терминалов BCD предпочтительнее двоичного представления. Исторически числа с фиксированной точкой часто использовались для десятичных типов данных, например в языках PL/I и COBOL. Язык программирования Ada 2012 включает встроенную поддержку чисел с фиксированной запятой (как двоичных, так и десятичных) и чисел с плавающей запятой. JOVIAL и Coral 66 предоставляли оба формата.
Стандарт ISO/IEC TR 18037 добавляет поддержку чисел с фиксированной запятой в язык C. Разработчики компилятора GCC уже реализовали[3] эту поддержку.
Практически все СУБД и язык SQL поддерживают арифметику с фиксированной запятой и хранение таких данных. Например, PostgreSQL имеет специальный численный тип для точного хранения чисел до 1000 цифр.
Операции
- Сложение и вычитание чисел с фиксированной запятой — это обычные сложение и вычитание: <math>(x \pm y)' = x' \pm y'</math>.
- Аналогично с умножением и делением на целочисленную константу: <math>(cx)' = c\cdot x'</math>.
- Умножение и деление отличаются от целочисленных на константу.
- <math>(x \cdot y)' = \left[ x' \cdot y' \cdot z \right] = \left[ \frac {x' \cdot y'} u \right]</math>
- <math>\left(\frac x y \right)' = \left[ \frac {x'} {z \cdot y'} \right] = \left[ \frac {x' \cdot u} {y'} \right] </math>,
- где [ ] — операция округления до целого. В частности, если в дробной части f бит:
- <math>
(x \cdot y)' = (x' \cdot y') \, \operatorname{shr} \, f, \,\,\,\, \left(\frac x y \right)' = \frac {x' \, \operatorname{shl} \, f} {y'} </math>.
- Для других операций, помимо обычных рядов Тейлора и итерационных методов, широко применяются вычисления по таблице.
Если операнды и результат имеют разную цену (вес) младшего разряда, формулы более сложны — но иногда такое приходится делать из-за большой разницы в порядке величин.
Для перевода чисел из формата с фиксированной запятой в человекочитаемый формат и наоборот применяются обычные правила перевода дробных чисел из одной позиционной системы счисления в другую.
Примечания