Детерминированная плавающая точка и .NET - PullRequest
11 голосов
/ 04 марта 2010

Как я могу гарантировать, что вычисления с плавающей запятой в приложении .NET (скажем, в C #) всегда дают один и тот же точный битовый результат? Особенно при использовании разных версий .NET и на разных платформах (x86 против x86_64). Неточности операций с плавающей запятой не имеют значения.

В Java я бы использовал strictfp. В C / C ++ и других языках низкого уровня эта проблема в основном решается путем доступа к управляющим регистрам FPU / SSE, но это, вероятно, невозможно в .NET.

Даже с контролем регистра управления FPU JIT .NET будет генерировать разный код на разных платформах. Что-то вроде HotSpot было бы еще хуже в этом случае ...

Зачем мне это нужно? Я думаю о написании стратегии в реальном времени (RTS), которая в большой степени зависит от быстрой математики с плавающей запятой вместе с симуляцией ступенчатой ​​блокировки. По сути, я буду передавать только пользовательский ввод по сети. Это также относится к другим играм, которые реализуют повторы, сохраняя пользовательский ввод.

Не вариант:

  • десятичные дроби (слишком медленно)
  • значения с фиксированной точкой (слишком медленные и громоздкие при использовании sqrt, sin, cos, tan, atan ...)
  • Обновление состояния по сети, например, FPS: отправка информации о местоположении для сотен или нескольких тысяч единиц невозможна

Есть идеи?

Ответы [ 3 ]

2 голосов
/ 04 марта 2010

Я не уверен в точном ответе на ваш вопрос, но вы могли бы использовать C ++ и выполнить всю свою работу с плавающей точкой в ​​d ++ c ++, а затем вернуть результат в .Net через взаимодействие.

1 голос
/ 12 марта 2010

Результаты Bitexact для разных платформ - боль в а **. Если вы используете только x86, это не должно иметь значения, потому что FPU не меняется с От 32 до 64 бит. Но проблема в том, что трансцендентные функции могут быть более Точность на новых процессорах.

Четыре базовые операции не должны давать разные результаты, но ваша виртуальная машина может оптимизировать выражения и это может дать разные результаты. Так как Муравьи предложили, напишите свои подпрограммы add / mul / div / sub как неуправляемый код, чтобы быть в безопасности.

Для трансцендентных функций, я боюсь, вы должны использовать справочную таблицу для гарантия точности бит Рассчитать результат, например, 4096 значений, хранить их как константы, и если вам нужно значение между ними, интерполируйте. Это не даст вам большой точности, но это будет укус.

0 голосов
/ 08 сентября 2016

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

  1. Сделайте ваше приложение только 64-битным.Таким образом, вам не нужно иметь дело с x87 против SSE (x86 JIT по-прежнему генерирует код x87 fp, другие JIT - SSE).
  2. Используйте .NET Core и связывайте среду выполнения с вашим приложением .Таким образом, вы гарантируете тот же коден для любой версии вашего приложения.Это очень важно, малейшие различия в коде могут привести к тому, что вычисления fp будут давать разные результаты.
  3. Придерживайтесь одной операционной системы.Серьезно, сколько кроссплатформенных RTS существует?Да, есть Starcraft 2;это все AFAIK.Blizzard уже давно овладевает этим искусством, и очень немногие могут повторить этот подвиг.Если вы действительно хотите поддерживать многопользовательский режим Mac-PC, вам придется тщательно проверить, что среда выполнения .NET генерирует один и тот же код fp на обеих платформах.И если это не так, вам не повезло.

В одном вопросе, в котором я до сих пор не уверен, можно ли доверять классу Math для получения последовательных результатов, учитывая указанные выше ограничения;но я полагаю, что должно.

...