Нет, это не другой вопрос «Почему (1 / 3.0) * 3! = 1» .
В последнее время я много читаю о числах с плавающей запятой; в частности, как один и тот же расчет может дать разные результаты для разных архитектур или настроек оптимизации.
Это проблема для видеоигр, в которых хранятся повторы или они работают в одноранговой сети (в отличие от сервера-клиента), в которых все клиенты получают одинаковые результаты при каждом запуске программы - небольшое расхождение в одном Вычисление с плавающей точкой может привести к совершенно разному игровому состоянию на разных машинах (или даже на одной машине! )
Это происходит даже среди процессоров, которые «следуют» IEEE-754 , главным образом потому, что некоторые процессоры (а именно x86) используют двойную расширенную точность . То есть они используют 80-битные регистры для выполнения всех вычислений, а затем усекаются до 64- или 32-битных, что приводит к результатам округления, отличным от тех, которые используют 64- или 32-битные для расчетов.
Я видел несколько решений этой проблемы в Интернете, но все для C ++, а не для C #:
- Отключите режим двойной расширенной точности (чтобы во всех
double
вычислениях использовался IEEE-754 64 -битный режим ) с использованием_controlfp_s
(Windows),_FPU_SETCW
(Linux?) Илиfpsetprec
(BSD). - Всегда запускайте один и тот же компилятор с одинаковыми настройками оптимизации и требуйте, чтобы все пользователи имели одинаковую архитектуру ЦП (без межплатформенного воспроизведения). Поскольку мой «компилятор» на самом деле является JIT, который может оптимизироваться по-разному при каждом запуске программы , я не думаю, что это возможно.
- Используйте арифметику с фиксированной запятой, избегайте
float
иdouble
вообще.decimal
будет работать для этой цели, но будет намного медленнее, и ни одна изSystem.Math
функций библиотеки не поддерживает его.
Так это вообще проблема в C #? Что если я собираюсь поддерживать только Windows (не Mono)?
Если это так, есть ли способ заставить мою программу работать с нормальной двойной точностью?
Если нет, то есть ли библиотеки, которые помогли бы поддерживать согласованность вычислений с плавающей точкой?
strictfp
ключевое слово, которое заставляет все вычисления выполняться в указанном размере ( float
или double
), а не в расширенном размере. Однако у Java все еще много проблем с поддержкой IEE-754. Очень (очень, очень) немногие языки программирования хорошо поддерживают IEE-754.