О точности с плавающей запятой и почему мы до сих пор ее используем

38

С плавающей точкой всегда было трудно из-за точности в больших мирах.

Эта статья объясняет закулисные и предлагает очевидную альтернативу - числа с фиксированной запятой. Некоторые факты действительно впечатляют, например:

«Точность 64 бита дает вам расстояние до Плутона от Солнца (7,4 млрд. Км) с точностью до субмикрометра».

Точность субмикрометра больше, чем нужно для fps (для позиций и даже скоростей), и это позволит вам создавать действительно большие миры.

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

Они намного медленнее?

Кроме того, как вы думаете, масштабируемые планетарные двигатели, такие как externalra или infinity, справляются с большими масштабами? Используют ли они фиксированную точку для позиций или у них есть некоторый алгоритм разделения пространства?

system_is_b0rken
источник
3
Последний «дополнительный» бит, вероятно, должен быть отдельным вопросом, чтобы основной не отвлекался.
Тетрад
Я хочу понять, как заставить фиксированную точку ... В моей игре есть много странных ошибок, потому что Lua использует FPU, а DirectX тоже играет с FPU ... Я видел такие вещи, как 2 * 9000 = 17995 или 500 * 10. = 4897 это действительно глупо. Но наихудшая ошибка, вероятно, та, которая обсуждается на форумах Ogre3D, где 1 + 5 = 4.
спидер
3
Не оправдал комментарий; но если вы решите использовать Q-Float с фиксированной точкой ( en.wikipedia.org/wiki/Q_(number_format) ) - ваш друг; они смехотворно быстры и просты в реализации.
Джонатан Дикинсон
Итак, чтобы подвести итог ¿я должен придерживаться с плавающей запятой (если я работаю в Java или Python)? - Гастон 26 минут назад
Гастон

Ответы:

20

Если вы позволите мне бесстыдный плагин, я приведу вам пример из реальной игры, над которой я работаю (ссылка на видео YouTube).

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

Мое решение? Каждые 200 м или около того я перемещаю весь мир назад на 200 м к исходной точке (если вы захотите найти и попробовать один из прототипов на моем сайте и вызвать наложение [w] orld debug, вы можете увидеть, как это происходит).

Почему бы не использовать фиксированную точку? Или двойная точность? Вместо одинарной точности? Потому что все остальное использует одинарную точность с плавающей точкой!

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

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

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

Эндрю Рассел
источник
Я всегда задавался вопросом, может ли некоторым приложениям легче переместить все остальное и сохранить «проигрыватель» в начале координат. Интересно, что я не единственный!
dash-tom-bang
Мне нравятся твои рассуждения. Я просто хотел бы отметить, что когда речь заходит об играх, которые используют сетевую фиксированную точку, кажется, есть меньше причуд / отклонений (прогноз клиента более точен).
Джонатан Дикинсон
Я не очень хорошо понимаю ваш аргумент. И, кстати, почему языки еще не реализовали фиксированную точку? Конечно, это причина для использования поплавков, но это не объясняет, почему фиксированная точка не была реализована повсеместно.
Jokoon
@jokoon Я думал, что мой ответ был совершенно ясен. Относительно того, почему фиксированная точка не везде реализована? Просто посмотрите на Википедию: «Очень немногие компьютерные языки включают встроенную поддержку значений с фиксированной точкой, потому что для большинства приложений двоичные или десятичные представления с плавающей точкой обычно проще в использовании и достаточно точны ». Хороший дизайнер знает, что пропустить - и то, что дублирует функциональность таким образом, что программисту очень легко выстрелить себе в ногу, является хорошим кандидатом.
Эндрю Рассел
Согласовано. Современные процессоры выполняют инструкции с плавающей запятой очень легко, инструкции имеют отличную пропускную способность, и большинство из них имеют задержку всего на несколько циклов больше, чем целочисленные инструкции.
doug65536
11

Во-первых - да, они значительно быстрее. Даже если вы можете заставить фиксированную точку работать так же быстро, как и «обычный» FPU, реальная плавающая точка имеет полезные инструкции, такие как fsel, чтобы остановить ветвление, или SIMD, чтобы работать на многих поплавках одновременно. Графические процессоры также используют числа с плавающей запятой, по крайней мере, в своих пользовательских интерфейсах.

Во-вторых, 64-битная система дает вам достаточно большие результаты с плавающей запятой - большинство людей по-прежнему используют 32-разрядную версию, но основное преимущество заключается в том, что она масштабируется. Эта шкала с фиксированной точкой имеет фиксированную точность. Измеряете ли вы Солнце до Плутона или через улицу, вы получаете одинаковую точность. Плавающая точка даст вам гораздо более точные результаты, когда все значения меньше. Поскольку библиотеки общей физики, как ожидается, будут работать по крайней мере сносно с большим количеством игр в разных масштабах - а сами игры могут иметь совершенно разные масштабы - им нужно использовать некое число, которое работает во многих масштабах.


источник
5

Еще один важный момент: поплавки не так неточны, как думают люди здесь. 32-разрядное число с плавающей запятой имеет 24-разрядную целочисленную точность. Это означает, что оно является по меньшей мере таким же точным, как 24-битное значение с фиксированной точкой для любого заданного диапазона. В то время как значения с плавающей точкой становятся менее точными, чем больше значение, тем больше значение с фиксированной точкой будет просто переполнено и обернуто в некоторой точке Снижение точности - лучший запасной вариант. Поплавки тоже могут переполниться, но далеко-далеко позже. Я хотел бы видеть ваши лица, когда ваш мир внезапно приближается к -2 ^ 31 из-за переполнения фиксированной точки.

64-битные значения с плавающей запятой имеют 53-битную целочисленную точность, поэтому они действительно точные.

Расмус
источник
Значения с плавающей точкой на самом деле не переполняются; если результат вычисления слишком велик по величине, чтобы его можно было представить, то результатом является положительная или отрицательная бесконечность.
ананас
3

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

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

IIRC, разработчик Infinity, заявил, что в одном из своих интервью он постоянно перебирал вопросы масштаба.

Rushyo
источник
Вряд ли в любой игре вам понадобится точность с плавающей точкой, близкая к нулю. Если у вас единица измерения в один метр, точность в 10 битов дает вам субмиллиметровую точность и все же позволяет вам моделировать более 4000 км в каждом направлении, если вы застряли с 32-битными значениями. Если вам нужно больше точности, чем миллиметр, то вы можете наверняка сдвинуть еще на несколько бит. Переход к 64-битным значениям в космической игре даст вам солнечную систему (или больше?) С постоянной точностью по всему объему.
dash-tom-bang
Верно. И именно поэтому вы бы использовали Солнце Солнечной системы как точку отсчета в мире размером с галактику! Суть в том, что выбранный вами метод обработки точности ни к чему не приводит. Это спорный вопрос, так что вы можете использовать тот, на который настроена ваша библиотека / оборудование.
Rushyo
Кстати, я работал над игрой, в которой нам нужно было моделировать более 4000 км в каждом направлении. Для совместимости с кодом в других проектах пришлось использовать 32 бита для позиций. Это не теоретическая проблема, учитывая коммерческие требования, предъявляемые к повторному использованию кода, и размер игровых миров сегодня.
1

Если вы еще этого не сделали, вам обязательно нужно ознакомиться с руководством по рендерингу планет на GameDev.net. Что касается разделения пространства, одним из решений является сохранение двух отдельных переменных положения - одного макромасштаба и одного микромасштаба. Это работает довольно хорошо (проверено).

Точное решение зависит от того, как вы планируете обрабатывать экстремальные расстояния в двигателе - планируете ли вы прыжковые ворота или сжатие времени?

Корнел Киселевич
источник
1

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

Пока вы знаете об ограничениях арифметики с плавающей запятой и меняете свои алгоритмы, чтобы справиться с ними (см. Ответ Эндрю Рассела), вы будете создавать код, который «работает».

ChrisF
источник
-1

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

user1727819
источник