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