gpt4 book ai didi

c++ - 跨平台浮点一致性

转载 作者:行者123 更新时间:2023-12-02 07:51:03 25 4
gpt4 key购买 nike

我正在开发一种跨平台游戏,该游戏使用锁步模型在网络上玩。简要概述一下,这意味着只交流输入,并且在每个客户端的计算机上模拟所有游戏逻辑。因此,一致性和确定性非常重要。

我在使用GCC 4.8.1的MinGW32上编译Windows版本,在Linux上使用GCC 4.8.2进行编译。

最近让我震惊的是,当我的Linux版本连接到Windows版本时,即使两台计算机上都编译了相同的代码,该程序也会立即发散或不同步!原来的问题是Linux版本是通过64位编译的,而Windows版本是32位的。

编译完Linux 32位版本后,很高兴我解决了该问题。但是,这让我开始思考和研究浮点确定性。

这是我收集的:

如果满足以下条件,程序通常将保持一致:

  • ran on the same architecture
  • compiled using the same compiler


因此,如果我假设针对个人计算机市场,每个人都拥有x86处理器,那么就可以满足要求。但是,第二个要求似乎有些愚蠢。

MinGW,GCC和Clang(分别为Windows,Linux和Mac)都是基于/兼容于/于GCC的不同编译器。这是否意味着不可能实现跨平台的确定性?还是仅适用于Visual C++与GCC?

同样,优化标志-O1或-O2是否会影响此确定性?离开他们会更安全吗?

最后,我有三个问题要问:

  • 1) Is cross-platform determinism possible when using MinGW, GCC, and Clang for compilers?
  • 2) What flags should be set across these compilers to ensure the most consistency between operating systems / CPUs?
  • 3) Floating point accuracy isn't that important for me -- what's important is that they are consistent. Is there any method to reducing floating point numbers to a lower precision (like 3-4 decimal places) to ensure that the little rounding errors across systems become non-existent? (Every implementation I've tried to write so far has failed)


编辑:我已经做了一些跨平台的实验。

使用浮点数的速度和位置,我可以使Linux Intel笔记本电脑和Windows AMD台式机保持同步,最多可保留15个小数点的浮点值。但是,两个系统都是x86_64。尽管测试很简单-只是通过网络移动实体,试图确定任何可见的错误。

如果将x86计算机连接到x86_64计算机,可以假定相同的结果是否有意义? (32位和64位操作系统)

最佳答案

跨平台和跨编译器的一致性当然是可能的。只要有足够的知识和时间,一切皆有可能!但这可能很困难,或者很耗时,或者实际上是不切实际的。

以下是我可以预见的问题,没有特别的顺序:

  • 请记住,即使是很小的正负1/10 ^ 15的误差也可能会变得非常大(将这个数字乘以十亿的误差幅度,现在就会有正负0.000001的误差)这些错误可能会随着时间,在许多帧上累积,直到您出现不同步的仿真为止。或者它们可以在您比较值时显示(即使在浮点比较中天真地使用“epsilons”也可能无济于事;仅替换或延迟显示)。
  • 上面的问题并不是分布式确定性模拟(像您一样)所独有的。关于“数值稳定性”的问题,这是一个困难且经常被忽略的主题。
  • 不同的编译器优化开关和不同的浮点行为确定开关可能会导致编译器为同一语句生成稍微不同的CPU指令序列。显然,在所有编译中,使用完全相同的编译器,这些代码必须相同,或者必须对生成的代码进行严格的比较和验证。
  • 32位和64位程序(注意:我是说程序而不是CPU)可能会表现出稍微不同的浮点行为。默认情况下,除非您在编译器命令行上指定(或使用以下命令中的内在函数/内联汇编指令),否则32位程序不能依赖比CPU的x87指令集更高级的内容(无SSE,SSE2,AVX等)。另一方面,可以保证64位程序可以在具有SSE2支持的CPU上运行,因此,编译器将默认使用这些指令(同样,除非由用户覆盖)。x87和SSE2浮点数据类型时。并且它们的操作类似,它们是-AFAIK-不相同。如果一个程序使用一个指令集而另一程序使用另一个指令集,则会导致仿真不一致。
  • x87指令集包含一个“控制字”寄存器,其中包含一些标志,这些标志控制浮点运算的某些方面(例如确切的舍入行为等)。这是运行时的事情,您的程序可以执行一组计算,然后更改该寄存器,然后进行完全相同的计算并获得不同的结果。显然,必须检查和处理该寄存器,并在不同的机器上保持相同。编译器(或您在程序中使用的库)可能会生成代码,这些代码会在运行时在整个程序中不一致地更改这些标志。
  • 同样,在使用x87指令集的情况下,英特尔和AMD历来在实现方面有所不同。例如,一个供应商的CPU可能在内部使用比另一个供应商更多的位来进行一些计算(因此得出更准确的结果),这意味着如果您碰巧在两个不同供应商的两个不同CPU(均为x86)上运行,则简单计算的结果可能会不同。我不知道如何以及在何种情况下可以启用这些更高的精度计算,以及它们是否在正常运行条件下发生,或者您是否需要特别要求,但我确实知道这些差异存在。
  • 随机数以及在程序之间一致且确定地生成它们与浮点一致性无关。它很重要,并且是许多错误的源头,但最后,您仅需要保持同步状态就多了一些。

  • 以下是一些可能会有所帮助的技术:
  • 一些项目使用“定点”数字和定点算法来避免舍入错误和浮点数的一般不可预测性。 Read the Wikipedia article了解更多信息和外部链接。
  • 在我自己的一个项目中,在开发过程中,我曾经对游戏所有实例中的所有相关状态(包括许多浮点数)进行哈希处理,并在网络上每一帧发送哈希值,以确保甚至在不同的计算机上,该状态的位没有什么不同。这也有助于进行调试,而不是让我不敢看我的眼睛去查看何时何地存在不一致(无论如何也不会告诉我它们起源于何处),我会立即知道在一台机器上游戏状态的某些部分开始出现差异从其他对象,并确切地知道它是什么(如果哈希检查失败,我将停止模拟并开始比较整个状态。)
    此功能从一开始就在该代码库中实现,并且仅在开发过程中用于帮助调试(因为它具有性能和内存成本)。

  • 更新(作为对下面第一条评论的回答):正如我在第1点中所说的,其他人在其他答案中所说,这并不能保证任何事情。如果这样做,可能会降低发生不一致的可能性和频率,但是可能性不会变为零。如果您不仔细,系统地分析代码中正在发生的事情以及可能的问题根源,那么无论您如何“舍入”多少数字,仍然有可能遇到错误。

    例如,如果您有两个数字(例如,两个应该产生相同结果的计算结果)分别为1.111499999和1.111500001,并将它们四舍五入到小数点后三位,则它们分别变为1.111和1.112。原始数字的差异仅为2E-9,但现在变成1E-3。实际上,您已将错误增加了500'000次。即使四舍五入,它们仍然不相等。您加剧了这个问题。

    没错,这种情况发生得并不多,我给出的例子是在这种情况下遇到的两个不幸数字,但是仍然可以用这些数字找到自己。而当您这样做时,您就会遇到麻烦。即使您使用定点算术或其他方法,唯一可行的解​​决方案是对所有可能出现的问题区域进行严格而系统的数学分析,并证明它们在程序之间保持一致。

    简而言之,对于我们这些凡人,您需要有一种不透水的方式来监控情况,并确切地发现何时以及如何发生最小的差异,以便事后解决问题(而不是依靠您的眼睛)以查看游戏动画或对象移动或 body 行为方面的问题。)

    关于c++ - 跨平台浮点一致性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20963419/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com