11

如何保证 .NET 应用程序(例如 C#)中的浮点计算总是产生相同的位精确结果?尤其是在使用不同版本的 .NET 并在不同平台上运行时(x86 与 x86_64)。浮点运算的不准确性无关紧要。

在 Java 中,我会使用 strictfp。在 C/C++ 和其他低级语言中,这个问题基本上是通过访问 FPU / SSE 控制寄存器来解决的,但这在 .NET 中可能是不可能的。

即使控制了 FPU 控制寄存器,.NET 的 JIT 也会在不同的平台上生成不同的代码。在这种情况下,像 HotSpot 这样的东西会更糟......

为什么我需要它?我正在考虑编写一个实时策略 (RTS) 游戏,它在很大程度上依赖于快速浮点数学以及锁步模拟。本质上,我只会通过网络传输用户输入。这也适用于通过存储用户输入来实现回放的其他游戏。

不是一个选项是:

  • 小数(太慢)
  • 定点值(使用 sqrt、sin、cos、tan、atan 时太慢且太麻烦……)
  • 像 FPS 一样通过网络更新状态:发送数百或数千个单位的位置信息不是一种选择

有任何想法吗?

4

3 回答 3

2

我不确定您的问题的确切答案,但您可以使用 C++ 并在 c++ dll 中完成所有浮动工作,然后通过互选将结果返回给 .Net。

于 2010-03-04T16:59:03.273 回答
1

不同平台的 Bitexact 结果令人痛苦。如果您只使用 x86,那应该没关系,因为 FPU 不会从 32 位更改为 64 位。但问题是超越函数在新处理器上可能更准确。

四个基本操作不应该给出不同的结果,但是您的 VM 可能会优化表达式并且可能会给出不同的结果。因此,正如 Ants 建议的那样,将您的 add/mul/div/sub 例程编写为非托管代码以确保安全。

对于超越函数,恐怕您必须使用查找表来保证位的准确性。计算例如 4096 个值的结果,将它们存储为常量,如果需要它们之间的值,则进行插值。这不会给你很大的准确性,但它会很精确。

于 2010-03-11T21:24:10.733 回答
0

如果您想要浮点确定性,则需要消除所有变量。如果您稍微限制您的范围,这是可能的。

  1. 使您的应用程序仅 64 位。这样您就不必处理 x87 与 SSE(x86 JIT 仍然发出 x87 fp 代码,其他 JIT 发出 SSE)。
  2. 使用 .NET Core 并将运行时与您的应用程序捆绑在一起。这样,您就可以保证应用程序的任何给定版本都具有相同的代码生成。这是至关重要的,最轻微的 codegen 差异可能会导致 fp 计算给出不同的结果。
  3. 坚持使用一个操作系统。说真的,有多少跨平台RTS?是的,有星际争霸2;就是这样。暴雪已经掌握了这项艺术很长一段时间,很少有人能复制这一壮举。如果您真的想支持 Mac-PC 多人游戏,您将不得不煞费苦心地验证您的 .NET 运行时是否在两个平台上生成相同的 fp 代码。如果没有,你就不走运了。

我仍然不确定的一点是,考虑到上述限制,您是否可以信任 Math 类给出一致的结果;但我想它应该。

于 2016-09-07T23:01:09.453 回答