Согласована ли математика с плавающей запятой в C #? Может ли это быть?

Нет, это не другой вопрос «Почему (1 / 3,0) * 3! = 1» .

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

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

Это происходит даже среди процессоров, которые «следуют» IEEE-754 , в первую очередь потому, что некоторые процессоры (а именно x86) используют двойной расширенной точности . То есть они используют 80-битные регистры для выполнения всех вычислений, а затем усекают до 64- или 32-битных, что приводит к другим результатам округления, чем машины, которые используют 64- или 32-битные вычисления.

видел несколько решений этой проблемы в Интернете, но все для C ++, а не C #:

  • Отключить режим двойной расширенной точности (чтобы все вычисления double использовали 64-битные IEEE-754) с помощью _controlfp_s (Windows), _FPU_SETCW (Linux?) Или fpsetprec (BSD).
  • Всегда запускайте один и тот же компилятор с одинаковыми настройками оптимизации и требуйте, чтобы все пользователи имеют одинаковую архитектуру ЦП (нет кроссплатформенной игры). Поскольку мой "компилятор" на самом деле является JIT, который может оптимизировать по-разному каждый раз при запуске программы , я не думаю, что это возможно.
  • Используйте арифметику с фиксированной точкой и избегайте float и double вместе. decimal подойдет для этой цели, но будет намного медленнее, и ни одна из библиотечных функций System.Math не поддерживает его.

Итак, это даже проблема в C #? Что, если я намереваюсь поддерживать только Windows (а не Mono)?

Если да, есть ли способ заставить мою программу работать с нормальной двойной точностью?

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

152
задан Community 13 April 2017 в 12:18
поделиться