确定性浮点和.NET

发布于 2024-08-23 22:33:23 字数 543 浏览 5 评论 0原文

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

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

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

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

不可以选择的是:

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

有什么想法吗?

How can I guarantee that floating point calculations in a .NET application (say in C#) always produce the same bit-exact result? Especially when using different versions of .NET and running on different platforms (x86 vs x86_64). Inaccuracies of floating point operations do not matter.

In Java I'd use strictfp. In C/C++ and other low level languages this problem is essentially solved by accessing the FPU / SSE control registers but that's probably not possible in .NET.

Even with control of the FPU control register the JIT of .NET will generate different code on different platforms. Something like HotSpot would be even worse in this case...

Why do I need it? I'm thinking about writing a real-time strategy (RTS) game which heavily depends on fast floating point math together with a lock stepped simulation. Essentially I will only transmit user input across the network. This also applies to other games which implement replays by storing the user input.

Not an option are:

  • decimals (too slow)
  • fixed point values (too slow and cumbersome when using sqrt, sin, cos, tan, atan...)
  • update state across the network like an FPS: Sending position information for hundreds or a few thousand units is not an option

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

等风也等你 2024-08-30 22:33:23

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

I'm not sure of the exact answer for your question but you could use C++ and do all your float work in a c++ dll and then return the result to .Net through an interopt.

尸血腥色 2024-08-30 22:33:23

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

四个基本操作不应给出不同的结果,但您的虚拟机可能会
优化表达式,这可能会产生不同的结果。所以正如蚂蚁提议的那样,
为了安全起见,将您的 add/mul/div/sub 例程编写为非托管代码。

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

Bitexact results for different platforms are a pain in the a**.
If you only use x86, it should not matter because the FPU does not change from
32 to 64bit. But the problem is that the transcendental functions may be more
accurate on new processors.

The four base operations should not give different results, but your VM may
optimize expressions and that may give different results. So as Ants proposed,
write your add/mul/div/sub routines as unmanaged code to be on the safe side.

For the transcendental functions I am afraid you must use a lookup table to
guarantee bit exactness. Calculate the result of e.g. 4096 values, store them
as constants and if you need a value between them, interpolate.
This does not give you great accuracy, but it will be bitexact.

沉默的熊 2024-08-30 22:33:23

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

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

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

If you want floating-point determinism you need to eliminate all variables. This is possible if you restrict your scope somewhat.

  1. Make your application 64-bit only. This way you don't have to deal with x87 vs SSE (x86 JIT still emits x87 fp code, other JITs emit SSE).
  2. Use .NET Core and bundle the runtime with your application. This way you guarantee the same codegen for any given version of your application. This is crucial, the slightest codegen differences can cause fp calculations to give different results.
  3. Stick with one operating system. Seriously, how many cross-platforms RTSes are out there? Yeah, there's Starcraft 2; that's it AFAIK. Blizzard has mastering this art for a long time and very few could replicate this feat. If you truly want to support Mac-PC multiplayer, you'll have to painstakingly verify that your .NET runtime generates the same fp code on both platforms. And if it doesn't you're out of luck.

One point I am still unsure of is whether you can trust the Math class to give consistent results, given the above restrictions; but I suppose it should.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文