Ні, це не інше питання "Чому це (1 / 3.0) * 3! = 1" .
Останнім часом я багато читав про плаваючі точки; конкретно, як один і той же розрахунок може давати різні результати в різних архітектурах або налаштуваннях оптимізації.
Це проблема для відеоігор, які зберігають повторення або є одноранговими мережевими (на відміну від сервера-клієнта), які покладаються на всіх клієнтів, що створюють однакові результати щоразу, коли вони запускають програму - невелика розбіжність в одному Обчислення з плаваючою комою може призвести до різко різного стану гри на різних машинах (або навіть на одній машині! )
Це трапляється навіть серед процесорів, які «слідують» за 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)?
Якщо це так, чи є який-небудь спосіб змусити мою програму працювати у звичайній подвійній точності?
Якщо ні, то чи існують бібліотеки, які допомогли б підтримувати обчислення з плаваючою комою?
strictfp
ключове слово, яке примушує всі обчислення робити у вказаному розмірі ( float
або double
), а не розширеному розмірі. Однак у Java все ще багато проблем з підтримкою IEE-754. Дуже (дуже, дуже) небагато мов програмування добре підтримують IEE-754.