跨平台浮点一致性
- 2024-11-04 08:43:00
- admin 原创
- 32
问题描述:
我正在开发一款跨平台游戏,该游戏使用同步模型在网络上进行游戏。简单来说,这意味着只传递输入,并且所有游戏逻辑都在每个客户端的计算机上模拟。因此,一致性和确定性非常重要。
我在 MinGW32 上编译 Windows 版本,使用 GCC 4.8.1,在 Linux 上编译使用 GCC 4.8.2。
最近让我震惊的是,当我的 Linux 版本连接到 Windows 版本时,程序会立即出现分歧或不同步,即使两台机器上编译的是相同的代码!原来问题是 Linux 版本是通过 64 位编译的,而 Windows 版本是 32 位。
编译完 Linux 32 位版本后,问题终于解决了,我感到很欣慰。但是,这也让我开始思考和研究浮点确定性。
这是我所收集到的信息:
如果程序满足以下条件,则它通常是一致的:
运行在相同的架构上
使用相同的编译器编译
因此,如果我假设,针对 PC 市场,每个人都拥有 x86 处理器,那么第一个要求就得到了满足。然而,第二个要求似乎有点愚蠢。
MinGW、GCC 和 Clang(分别为 Windows、Linux、Mac)都是基于/兼容 GCC 的不同编译器。这是否意味着无法实现跨平台确定性?还是它仅适用于 Visual C++ 而非 GCC?
另外,优化标志 -O1 或 -O2 是否会影响这种确定性?不使用这些标志会更安全吗?
最后我有三个问题想问:
1)使用MinGW,GCC和Clang作为编译器时,是否可以实现跨平台确定性?
2) 在这些编译器之间应设置哪些标志以确保操作系统/CPU 之间的最大一致性?
3) 浮点精度对我来说并不那么重要——重要的是它们的一致性。是否有任何方法可以将浮点数降低到较低的精度(例如 3-4 位小数),以确保系统之间的小舍入误差不存在?(到目前为止,我尝试编写的每个实现都失败了)
编辑:我做了一些跨平台实验。
使用浮点表示速度和位置,我让 Linux Intel 笔记本电脑和 Windows AMD 台式电脑保持同步,浮点值最多可精确到小数点后 15 位。不过,这两个系统都是 x86_64。不过,测试很简单——只是通过网络移动实体,试图确定任何可见的错误。
如果 x86 计算机连接到 x86_64 计算机,假设会出现相同的结果,这有意义吗?(32 位与 64 位操作系统)
解决方案 1:
跨平台和跨编译器的一致性当然是可能的。只要有足够的知识和时间,一切皆有可能!但这可能非常困难,或者非常耗时,或者确实不切实际。
以下是我可以预见的问题(无特定顺序):
请记住,即使是正负 1/10^15 的极小误差也可能变得非常大(将该数字乘以该误差幅度十亿,现在您有一个正负 0.000001 的误差,这可能是一个很大的误差。)这些错误会随着时间的推移、在许多帧中累积,直到您得到一个不同步的模拟。或者它们可以在您比较值时显现出来(即使在浮点比较中天真地使用“epsilons”也可能无济于事;只会取代或延迟表现。)
上述问题并不是分布式确定性模拟(像您的模拟)所独有的。涉及“数值稳定性”问题,这是一个困难且经常被忽视的主题。
不同的编译器优化开关和不同的浮点行为确定开关可能会导致编译器为相同的语句生成略有不同的 CPU 指令序列。显然,这些必须在使用完全相同的编译器的编译过程中保持一致,否则必须严格比较和验证生成的代码。
32 位和 64 位程序(注意:我说的是程序而不是 CPU)可能会表现出略有不同的浮点行为。默认情况下,32 位程序不能依赖于 CPU 中比 x87 指令集更高级的任何指令(没有 SSE、SSE2、AVX 等),除非您在编译器命令行上指定这一点(或在代码中使用内在函数/内联汇编指令)。另一方面,64 位程序保证在支持 SSE2 的 CPU 上运行,因此编译器将默认使用这些指令(同样,除非被用户覆盖。)虽然 x87 和 SSE2 浮点数据类型及其操作相似,但据我所知,它们并不相同。如果一个程序使用一个指令集而另一个程序使用另一个指令集,这将导致模拟不一致。
x87 指令集包含一个“控制字”寄存器,其中包含控制浮点运算某些方面(例如精确舍入行为等)的标志。这是运行时的事情,您的程序可以执行一组计算,然后更改此寄存器,之后执行完全相同的计算并得到不同的结果。显然,必须检查和处理此寄存器,并在不同的机器上保持一致。编译器(或您在程序中使用的库)可能会生成在运行时在程序之间不一致地更改这些标志的代码。
同样,就 x87 指令集而言,英特尔和 AMD 历来在实现方面略有不同。例如,一家供应商的 CPU 可能在内部使用比另一家供应商更多的位进行某些计算(因此得出更准确的结果),这意味着如果您碰巧在两个不同供应商的两个不同 CPU(均为 x86)上运行,简单计算的结果可能不一样。我不知道这些更高精度的计算是如何以及在什么情况下启用的,也不知道它们是在正常操作条件下发生的还是您必须专门要求它们,但我知道这些差异是存在的。
随机数以及在程序中一致且确定地生成随机数与浮点一致性无关。它很重要,也是许多错误的根源,但最终它只是您必须保持同步的几个状态位。
以下几种技巧或许能有所帮助:
一些项目使用“定点”数字和定点算法来避免舍入误差和浮点数的一般不可预测性。阅读维基百科文章了解更多信息和外部链接。
在我自己的一个项目中,在开发过程中,我曾经对所有游戏实例中的所有相关状态(包括大量浮点数)进行哈希处理,并在每一帧通过网络发送哈希值,以确保该状态的哪怕一位在不同机器上都不会不同。这也有助于调试,我不用依靠眼睛来判断何时何地存在不一致(反正眼睛也无法告诉我不一致的来源),而是在某台机器上的游戏状态的某个部分开始与其他机器出现分歧时,我就能知道,而且确切知道它是什么(如果哈希检查失败,我会停止模拟并开始比较整个状态)。
该功能从一开始就在代码库中实现,并且仅在开发过程中用于帮助调试(因为它有性能和内存成本)。
更新(回答下面第一条评论):正如我在第 1 点中所说,以及其他人在其他答案中所说,这并不能保证任何事情。如果你这样做,你可能会降低发生不一致的概率和频率,但可能性不会变为零。如果你不仔细、系统地分析代码中发生的事情和可能的问题来源,那么无论你如何“四舍五入”你的数字,仍然有可能遇到错误。
例如,如果您有两个数字(例如,作为两个本应产生相同结果的计算的结果),即 1.111499999 和 1.111500001,并且您将它们四舍五入到小数点后三位,它们分别变为 1.111 和 1.112。原始数字的差异仅为 2E-9,但现在已变为 1E-3。事实上,您的错误增加了 500'000 倍。即使四舍五入,它们仍然不相等。您加剧了问题。
确实,这种情况并不多见,我给出的例子是在这种情况下得到的两个不吉利的数字,但你仍然有可能遇到这些数字。当你遇到这些数字时,你就有麻烦了。即使你使用定点算法或其他算法,唯一万无一失的解决方案是对所有可能的问题区域进行严格而系统的数学分析,并证明它们在各个程序中保持一致。
除此之外,对于我们这些凡人来说,你需要有一种严密的方法来监控情况,并准确地找到何时以及如何发生最轻微的差异,以便能够在事后解决问题(而不是依靠你的眼睛来发现游戏动画或物体运动或物理行为中的问题。)
解决方案 2:
不,实际上不是。例如,
sin()
可能来自库或编译器内部函数,并且在舍入方面有所不同。当然,那只是一位,但这已经不同步了。而且那一位错误可能会随着时间的推移而累积,因此即使不精确的比较也可能不够。不适用
您无法降低给定类型的 FP 精度,我甚至看不出这会对您有什么帮助。您会将偶尔出现的 1E-6 差异变成偶尔出现的 1E-4 差异。
解决方案 3:
除了您对确定性问题的担忧之外,我还有另一条评论:如果您担心分布式系统的计算一致性,那么您可能遇到了设计问题。
你可以将你的应用程序视为一组节点,每个节点负责自己的计算。如果需要有关另一个节点的信息,则该节点应将其发送给你。
解决方案 4:
1.)
原则上,跨平台、操作系统和硬件兼容是可能的,但在实践中却很麻烦。
一般来说,您的结果将取决于您使用的操作系统、编译器和硬件。更改其中任何一个,您的结果都可能发生变化。您必须测试所有更改。我使用 Qt Creator 和 qmake(cmake 可能更好,但 qmake 对我来说很管用),并在 Windows 上的 MSVC、Linux 上的 GCC 和 Windows 上的 MinGW-w64 中测试我的代码。我测试 32 位和 64 位。每当代码更改时都必须这样做。
2.) 和 3.)
在浮点方面,一些编译器将在 32 位模式下使用 x87 而不是 SSE。将此视为发生这种情况的后果的示例。为什么数字运算程序在发散为 NaN 时开始运行得慢得多? 所有 64 位系统都有 SSE,所以我认为大多数在 64 位中使用 SSE/AVX,否则,例如在 32 位模式下,您可能需要使用类似-mfpmath=sse and -msse2
.
但是,如果您想要在 Windows 上使用更兼容的 GCC 版本,那么我会使用 32 位的 MingGW-w64(又名 MinGW-w32)或 64 位的 MinGW-w64。这与 MinGW(又名 mingw32)不同。这两个项目已经分道扬镳。MinGW 依赖于MSVCRT
(MSVC C 运行时库),而 MinGW-w64 则不依赖。Qt 项目对 MinGW-w64 和安装有相当好的描述。http ://qt-project.org/wiki/MinGW-64-bit
您可能还需要考虑为Visual Studio 编写适用于 AVX 和 SSE 的 CPU 调度程序 cpu 调度程序。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件