Фон
Мы работаем над игровым движком RTS с использованием C # и .NET Core.В отличие от большинства других многопользовательских игр в реальном времени, игры RTS, как правило, работают путем синхронизации входов игроков с другими игроками и одновременного запуска симуляции игры на всех клиентах.Это требует, чтобы игровая логика была детерминированной, чтобы игры не выходили из синхронизации.
Одним из потенциальных источников недетерминизма являются операции с плавающей запятой.Из того, что я понял, основная проблема связана со старыми инструкциями x87 FPU - они используют внутренний 80-разрядный регистр, в то время как значения с плавающей запятой IEEE-754 являются 32-разрядными или 64-разрядными, поэтому значения усекаются при перемещении из регистров.в память.Небольшие изменения в коде и / или компиляторе могут привести к усечению в разное время, что приведет к несколько иным результатам.Недетерминизм также может быть вызван случайным использованием различных режимов округления FP, хотя, если я правильно понял, это в основном решенная проблема.
У меня также сложилось впечатление , что SSE (2) инструкции не страдают от проблемы усечения, так как они выполняют всю арифметику с плавающей запятой в 32- или 64-битном формате без регистра с более высокой точностью.
Наконец, насколько мне известно, CLR использует инструкции FPU x87 дляx86 (или, по крайней мере, так было до RyuJIT) и инструкции SSE для x86-64.Я не уверен, что это означает для всех или для большинства операций.
Поддержка точной математики с одинарной точностью была недавно добавлена в .NET Core, если это имеет значение.
Но при исследовании возможности детерминированного использования с плавающей запятой в .NET есть много ответов, которые говорят «нет», хотя в основном они касаются более старых версий среды выполнения.
- В Ответ StackOverflow от 2013 г. Эрик Липперт сказал, что если вы хотите гарантировать воспроизводимую арифметику в .NET, вам следует «Использовать целые числа».
- В обсуждении этой темы на странице Roslyn GitHub разработчик игры сказал в комментарии в 2017 году, что им не удалось достичь повторяющихся операций с плавающей запятой в C #, хотя он не указал, какие среды выполнения они использовали.
- В обмене стеками разработки игр 2011 года answer автор приходит к выводу, что ему не удалось получить надежную арифметику FP в .NET.Он предоставляет программную реализацию с плавающей запятой для .NET, которая двоично совместима с плавающей запятой IEEE754.
Вопрос
Итак, если CoreCLR использует инструкции SSE FP на x86-64, означает ли это, что он не страдает от проблем усечения и / или любого другого недетерминизма, связанного с FP?Мы поставляем .NET Core с движком, чтобы каждый клиент использовал одну и ту же среду выполнения, и мы бы требовали, чтобы игроки использовали точно такую же версию игрового клиента.Ограничение работы ядра только на x86-64 (на ПК) также является приемлемым ограничением.
Если во время выполнения все еще используются инструкции x87 с ненадежными результатами, имеет ли смысл использовать программную реализацию с плавающей запятой (например,один связан в ответе выше) для вычислений, касающихся отдельных значений, и ускорения векторных операций с SSE с использованием новой аппаратной встроенной функции ?Я прототипировал это, и это похоже на работу, но не нужно ли это?
Если мы можем просто использовать обычные операции с плавающей запятой, есть ли что-то, чего нам следует избегать, например тригонометрические функции?
Наконец, если все в порядке, как это будет работать, когда разные клиенты используют разные операционные системы или даже разные архитектуры ЦП?Страдают ли современные процессоры ARM от проблемы 80-битного усечения, или же тот же код выполняется идентично x86 (если исключить более сложные вещи, такие как тригонометрия), при условии, что в реализации нет ошибок?