Являются ли операции с плавающей запятой в Delphi детерминированными?

Являются ли операции с плавающей запятой в Delphi детерминированными?

I.E. получу ли я тот же результат от идентичной математической операции с плавающей запятой в том же исполняемом файле, скомпилированном с помощью компилятора Delphi Win32, как и с компилятором Win64, или компилятором OS X, или компилятором iOS, или компилятором Android?

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

Следствием этого может быть появление «запаздывания» или «рывков» на стороне клиента, когда достоверные данные о состоянии игры преобладают над прогнозируемым состоянием на стороне клиента.

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


person LaKraven    schedule 22.06.2014    source источник
comment
Что вы имеете в виду под «операциями с плавающей запятой»? Если вы включите трансцендентные функции, такие как sin или cos, я не думаю, что вы можете ожидать таких же результатов. Если вы ограничите вопрос 4 арифметическими операциями для типа Double или Single, возможно, вы сможете добиться тех же результатов, но мне не нравится идея полагаться на него, потому что изменение режима плавающей операции может изменить результат плавающей операции даже для одного Платформа.   -  person kludg    schedule 22.06.2014
comment
Я не понимаю, почему для вас это проблема. Типы данных и операции с плавающей запятой всегда являются приблизительными.   -  person David Heffernan    schedule 22.06.2014
comment
Рекомендуемое чтение, Проблемы округления с плавающей запятой и Контроль точности с плавающей запятой (Delphi для x64). Есть так много способов, которые могут пойти не так, что результат должен быть одинаковым на всех платформах.   -  person LU RD    schedule 22.06.2014
comment
@DavidHeffernan: Неверно.   -  person tmyklebu    schedule 22.06.2014
comment
Обеспокоенность заключается в том, что прогноз на стороне клиента может быть настолько далек от согласования с расчетом на стороне сервера, что игрок продолжает фиксировать позицию, когда данные на стороне клиента обновляются окончательными (авторитетными) данными на стороне сервера.   -  person LaKraven    schedule 22.06.2014
comment
@tmyklebu Нет. Истинным результатом вычислений может быть число, которое невозможно представить точно.   -  person David Heffernan    schedule 22.06.2014
comment
@DavidHeffernan: Может и не быть. Многие тщательно написанные коды с плавающей запятой полагаются на арифметические операции с плавающей запятой.   -  person tmyklebu    schedule 22.06.2014
comment
@tmyklebu Арифметика с плавающей запятой работает, как определено. Но не все числа могут быть представлены. Никакое тщательное кодирование не может изменить этот факт. Мне бы хотелось увидеть, как вы оцениваете 1.0/10.0 без приближения.   -  person David Heffernan    schedule 22.06.2014
comment
@DavidHeffernan: Я могу очень хорошо оценить 1.0 / 1.0, что служит отличным контрпримером к вашему широкому и всеобъемлющему утверждению о математике с плавающей запятой. Здесь нет необходимости рассматривать 1.0 / 10.0.   -  person tmyklebu    schedule 22.06.2014
comment
@tmyklebu ОК. Я понимаю что ты имеешь ввиду. Я имел в виду и совершенно не смог выразить то, что, учитывая, что арифметика с плавающей запятой неточна, имеет ли значение, что различное оборудование ведет себя по-разному. Но я выразил это ужасно плохо.   -  person David Heffernan    schedule 22.06.2014
comment
@DavidHeffernan: Это действительно для приложения плаката; ему интересно, может ли он доверять математике с плавающей запятой на стороне клиента, чтобы точно воспроизвести список вычислений. Могут ли два конечных автомата, идентичных на уровне Delphi, расходиться в результате того, что разные платформы по-разному обрабатывают числа с плавающей запятой.   -  person tmyklebu    schedule 23.06.2014
comment
@tmyklebu Мы все согласны с тем, что результаты будут разными. Интересно, имеет это значение или нет. Может и нет.   -  person David Heffernan    schedule 23.06.2014
comment
@DavidHeffernan: В этом контексте это явно так.   -  person tmyklebu    schedule 23.06.2014
comment
@tmtklebu Я ожидаю, что дрейф будет незначительным. Это, конечно, правдоподобно. Разрешение экрана намного грубее, чем арифметика с двойной точностью или даже с арифметикой с одинарной точностью. Если вы не думаете, что вы или я знаем что-либо о реальной специфике этой проблемы. Я предполагаю, что, возможно, какой-то дрейф не будет иметь значения. Не думаю, что вы можете быть уверены, что это будет иметь значение.   -  person David Heffernan    schedule 23.06.2014
comment
FWIW, взгляните сюда: два равных значения с плавающей запятой (они являются результатом одной и той же функции с точно такими же параметрами) сравниваются как неравные, когда вставлен фрагмент кода, который только ОТОБРАЖАЕТ эти значения: stackoverflow.com/ questions / 24321265 /   -  person Rudy Velthuis    schedule 23.06.2014
comment
Вскоре я буду проверять, насколько значительным является дрейф (я полагаю, мы можем спорить с учеными до тех пор, пока коровы не вернутся домой, но на самом деле мы узнаем, только проверив его на самом деле)   -  person LaKraven    schedule 23.06.2014
comment
Просто предложение, почему бы вам не позволить клиенту быть авторитетным в государстве, а затем иметь право на ошибку? Пока клиент не отклоняется слишком далеко от курса, сервер исправит себя. Игроки могут прыгать в глазах других игроков, но это намного менее резко, чем прыгает сам игрок.   -  person Graymatter    schedule 24.06.2014
comment
Проблема с тем, чтобы позволить клиенту быть каким-либо образом авторитетным, заключается в том, что это позволит игрокам очень легко обмануть, просто выковыривая память, связанную с их положением, здоровьем, скоростью и количеством инвентаря. Вот почему сервер должен быть авторитетным, чтобы любая попытка мошенничества со стороны игроков была бесплодной (цифры сервера являются фактом).   -  person LaKraven    schedule 24.06.2014


Ответы (3)


Думаю, однозначного ответа нет. Подобная задача обсуждалась здесь. В общем, существует два стандарта для представления чисел с плавающей запятой: IEEE 754-1985 и EEE 754-2008. Все современные (и на самом деле довольно старые) процессоры соответствуют стандартам, и это гарантирует некоторые вещи:

  • Двоичное представление одного и того же стандартного плавающего типа будет равно
  • Результат некоторых операций (не всех, только базовых!) Гарантированно будет одинаковым, но только если компилятор будет использовать тот же тип команды, я не уверен, что это правда.

Но если вы используете некоторые расширенные операции, такие как извлечение квадратного корня, результат может отличаться даже для разных моделей настольных процессоров. Вы можете прочитать эту статью для получения некоторых подробностей: http://randomascii.wordpress.com/2013/07/16/floating-point-determinism/

P.S. Как упоминал tmyklebu, квадратный корень также определяется IEEE 754, поэтому можно гарантировать тот же результат для одного и того же ввода для сложения, вычитания, умножения, деления и квадратного корня. Некоторые другие операции также определены IEEE, но для получения всех подробностей лучше прочитать IEEE.

person Andrei Galatyn    schedule 22.06.2014
comment
Это то, что я предполагал (и хотел убедиться). Досадно, что физический движок использует практически все сложные операции с плавающей запятой (включая синус, косинус, я использую тангенс, чтобы определить, на каком трехмерном слое визуализировать спрайты, и квадратный корень). Возможно, мне придется полагаться на сглаживание на основе обратного буфера, чтобы игровой процесс казался плавным на стороне клиента, хотя на самом деле он постоянно корректируется (даже если на тысячные доли единицы) по расчету авторитетного сервера. Неэлегантно, но сейчас кажется необходимым. - person LaKraven; 22.06.2014
comment
sqrt в порядке. Вы играете с огнем, используя триггерные и экспоненциальные функции. На самом деле страшно то, что на x86-32 обычно используется FPU вместо инструкций SSE. Чтобы добиться от этого какой-либо производительности, компиляторам необходимо сгенерировать код, который округляется не так, как указано в программе. - person tmyklebu; 22.06.2014
comment
Вы уверены, что IEEE754 указывает sqrt? - person David Heffernan; 22.06.2014
comment
@DavidHeffernan Да. 6 основных операций +, -, *, /, sqrt, fma должны быть правильно округлены. - person Pascal Cuoq; 22.06.2014
comment
Повторяю, sqrt полностью определяется стандартом IEEE 754 и не «меняется для разных моделей процессоров настольных ПК». - person Pascal Cuoq; 22.06.2014
comment
@ Дэвид Хеффернан: Да; посмотрите на первый абзац раздела 5. - person tmyklebu; 22.06.2014

Отложив на мгновение стандарты вычислений с плавающей запятой, учтите, что 32- и 64-битные компиляторы компилируются для использования старого FPU и более новых инструкций SSE. Мне было бы трудно поверить в то, что все вычисления всегда будут выполняться одинаково на разных аппаратных реализациях. Лучше пойти по безопасному пути и предположить, что если разница в дельте pf небольшая, вы оцениваете ее как равную.

person NexusDB Expert    schedule 24.06.2014
comment
Это лучший сценарий, на который я надеюсь. В идеальном мире значения были бы точными, но поскольку мы знаем, что мир далеко не идеален, я просто надеюсь, что результаты многопользовательского теста, который я сейчас готовлю, покажут, что различия между значениями настолько незначительны, что результат рендеринга остается прежним. - person LaKraven; 24.06.2014
comment
Стандарт существует для обеспечения согласованности результатов - person David Heffernan; 25.06.2014

По опыту могу сказать, что результаты разные: 32-разрядная версия работает с расширенной точностью по умолчанию, а 64-разрядная версия работает с двойной точностью по умолчанию.

Рассмотрим заявление

x, y, z: двойной; х: = у * г;

в Win32 это будет выполняться как «x: = double (Extended (y) * Extended (z)); в Win64 это будет выполняться как» x: = double (double (y) * double (z));

вы прикладываете много усилий, чтобы использовать ту же точность и режим. Однако всякий раз, когда вы вызываете сторонние библиотеки, вы должны учитывать, что они могут внутренне изменять эти флаги.

person Daniel    schedule 24.06.2014
comment
Мне очень повезло в том, что этот игровой движок полностью использует значения Double внутри, а Single используется FMX только для рендеринга спрайтов (если на то пошло, никаких сложных математических вычислений для значений Single не выполняется) Спасибо за информацию :) - person LaKraven; 24.06.2014
comment
@La Ответ говорит о промежуточных значениях на x87, которые вы не можете контролировать - person David Heffernan; 25.06.2014