【发布时间】:2014-01-24 15:37:25
【问题描述】:
我正在开发一款跨平台游戏,该游戏使用锁步模型在网络上播放。作为一个简要的概述,这意味着只有输入被传达,所有的游戏逻辑都是在每个客户端的计算机上模拟的。因此,一致性和确定性非常重要。
我正在使用 GCC 4.8.1 的 MinGW32 上编译 Windows 版本,而在 Linux 上我正在使用 GCC 4.8.2 进行编译。
最近让我印象深刻的是,当我的 Linux 版本连接到我的 Windows 版本时,即使在两台机器上编译了相同的代码,程序也会立即出现分歧或不同步!原来问题是 Linux 版本是通过 64 位编译的,而 Windows 版本是 32 位的。
在编译了一个 32 位的 Linux 版本后,我很庆幸问题得到了解决。然而,它让我开始思考和研究浮点确定性。
这是我收集到的:
一个程序通常是一致的,如果它是:
- 在相同的架构上运行
- 使用相同的编译器编译
因此,如果我假设,针对 PC 市场,每个人都有一个 x86 处理器,那么这就解决了需求一。但是,第二个要求似乎有点傻。
MinGW、GCC 和 Clang(分别是 Windows、Linux、Mac)都是基于/兼容/基于 GCC 的不同编译器。这是否意味着不可能实现跨平台确定性?还是仅适用于 Visual C++ vs GCC?
同样,优化标志 -O1 或 -O2 会影响这种确定性吗?离开它们会更安全吗?
最后,我要问三个问题:
- 1) 将 MinGW、GCC 和 Clang 用于编译器时是否可以实现跨平台确定性?
- 2) 应在这些编译器之间设置哪些标志以确保操作系统/CPU 之间的最大一致性?
- 3) 浮点精度对我来说并不重要——重要的是它们是一致的。有什么方法可以将浮点数降低到较低的精度(如小数点后 3-4 位)以确保不存在跨系统的小舍入误差? (到目前为止,我尝试编写的每个实现都失败了)
编辑:我做了一些跨平台实验。
使用浮点数表示速度和位置,我使 Linux Intel 笔记本电脑和 Windows AMD 台式电脑保持同步,浮点值最多保留 15 位小数。然而,这两个系统都是 x86_64。不过测试很简单——它只是通过网络移动实体,试图确定任何可见的错误。
如果 x86 计算机连接到 x86_64 计算机,假设相同的结果会成立是否有意义? (32 位与 64 位操作系统)
【问题讨论】:
-
我认为不同的优化标志会使您的模拟不一致,因为编译器可能选择生成不同的公式和计算以达到相同的结果(尤其是在针对大小与. 速度。)还有用于舍入模式和错误处理模式的运行时 CPU 浮点标志(编译器有时会在您不知情的情况下生成代码来设置这些标志。)但是,我绝不是这方面的专家,所以......
-
第三个问题,你应该研究“定点算法”。这意味着您基本上将所有数字乘以一个固定值(例如 1000 或 65536 或其他;将其视为使用毫米和毫秒而不是米和秒),并使用整数变量和值进行所有计算。但是,您应该非常小心“数值稳定性”以及错误累积和错误界限。定点数可以非常有效地实现,并且使它们具有确定性要容易得多。
-
所以定点算术基本上就是对一个普通的int进行膨胀,然后在使用值的时候再放气?
-
我支持使用定点算法的建议;以我的经验,让不同的编译器(甚至同一台机器上的不同版本的相同编译器)为浮点运算返回相同的结果几乎是不可能的。
-
@BWG:不完全是,但这也不是太离谱。 You can read the Wikipedia article of fixed-point arithmetic.