【发布时间】:2011-10-04 17:06:49
【问题描述】:
不,这不是另一个“为什么是 (1/3.0)*3 != 1” 问题。
我最近读了很多关于浮点的文章;具体来说,相同的计算如何在不同的架构或优化设置上产生不同的结果。
对于存储回放或peer-to-peer networked(与服务器客户端相反)的视频游戏来说,这是一个问题,它们依赖于所有客户端在每次运行程序时生成完全相同的结果 - 一个小差异浮点计算会导致不同机器上的游戏状态截然不同(甚至on the same machine!)
即使在“遵循”IEEE-754 的处理器中也会发生这种情况,主要是因为某些处理器(即 x86)使用double extended precision。也就是说,它们使用 80 位寄存器进行所有计算,然后截断为 64 位或 32 位,导致舍入结果与使用 64 位或 32 位进行计算的机器不同。
我在网上看到了几个解决这个问题的方法,但都是针对 C++,而不是 C#:
- 使用
_controlfp_s(Windows)、_FPU_SETCW(Linux?) 或fpsetprec(BSD) 禁用双扩展精度模式(以便所有double计算使用 IEEE-754 64 位)。 - 始终以相同的优化设置运行相同的编译器,并要求所有用户具有相同的 CPU 架构(不能跨平台播放)。因为我的“编译器”实际上是 JIT,每次运行程序时可能会进行不同的优化,我认为这是不可能的。
- 使用定点算法,完全避免
float和double。decimal可以用于此目的,但速度会慢得多,而且System.Math库函数都不支持它。
那么,这在 C# 中是否是个问题?如果我只打算支持 Windows(而不是 Mono)怎么办?
如果是,有什么方法可以强制我的程序以正常的双精度运行?
如果没有,是否有任何库可以帮助保持浮点计算的一致性?
【问题讨论】:
-
我见过this question,但是每个答案要么重复问题而没有解决方案,要么说“忽略它”,这不是一个选项。我问了a similar question on gamedev,但是(因为观众)大多数答案似乎都是针对C++的。
-
不是一个答案,但我敢肯定,在大多数领域中,您都可以将系统设计为所有共享状态都是确定性的,并且不会因此而显着降低性能
-
@Peter 你知道 .net 的任何快速浮点仿真吗?
-
Java有这个问题吗?
-
@Josh:Java 有
strictfp关键字,它强制所有计算以规定的大小(float或double)而不是扩展大小进行。但是,Java 在 IEE-754 支持方面仍然存在许多问题。非常(非常、非常)少数编程语言能够很好地支持 IEE-754。
标签: c# .net floating-point precision ieee-754