【问题标题】:Sources of non-determinism [closed]非确定性的来源[关闭]
【发布时间】:2011-04-06 06:50:54
【问题描述】:

我所谓的确定性程序会在不同的运行中产生一些略有不同的输出之一。输入、编译器和计算机是不变的。我不确定哪个输出是正确的,因为它看起来总是合理的。

除了对 rand() 的杂散调用之外,这怎么可能?

【问题讨论】:

  • 在胡乱猜测之前,我们需要先看一些代码。
  • 您的代码是否包含任何误入未定义行为领域的内容?
  • 谁说编译器是确定性的?
  • @AshleysBrain - 看到这个问题stackoverflow.com/questions/3053904/…
  • @Andy_Vulhop - 以前从未阻止过任何人,但我同意我们会更有效率地查看代码。

标签: c++ random deterministic non-deterministic


【解决方案1】:

在几个方面:

  • 以涉及data race 的方式使用多个线程,
  • 使用当前系统时间作为输入,
  • 使用未初始化的变量,
  • ...

我们当然可以做出更多的猜测,但是如果您想获得有意义的帮助,也许您最好发布代码的相关部分:-)

【讨论】:

  • 是的;我们需要代码!当然,所有这些因素以及小数错误和伪随机化在技术上都是确定性的,因为它们在确定性机器上运行。在个人控制较少的分时系统的背景下,当我们无法跟踪或理解程序的输入和数百万个渐进状态时,它们对我们来说似乎是不确定的。这就是为什么理论和计算机科学与具体的编程技能一起教授总是很重要的原因。
  • 我应该明确表示我只想要一个常见可能性的列表,这就是我得到的。谢谢。
  • 顺便说一句,除非您附加调试器,否则未初始化的变量实际上是确定性的;但是它们是确定性的,就像单线程堆损坏是确定性的一样,这不是您想要的确定性。
【解决方案2】:

如果你的输出依赖于堆上分配的地址:

int main(int argc, char* argv[])
{
   printf("%p", malloc(42));
   return 0;
}

对于每次运行,malloc() 可能会返回不同的虚拟地址 - 更不用说 NULL 以防分配失败。

【讨论】:

  • 好收获。堆/堆栈地址随机化是当今非常标准的功能。如果在某处将指针用作键,那将会产生影响。我曾多次使用它来使排序稳定(如果键相等,则比较指针)。
  • 不过,您必须非常不幸/在非常低的内存上运行才能分配失败。
  • 如果堆分配的对象按它们的地址排序,则输出将取决于堆上分配的地址,例如,如果指向它们的指针存储在像集合这样的有序容器中。
【解决方案3】:

可能是:

  • 线程计时
  • 任何类型的输入(用户、文件、网络等)

【讨论】:

    【解决方案4】:

    如果你的程序使用float/double,如果在某些架构上有上下文切换,结果可能会有所不同。

    在 x86 上,FPU 对中间结果使用扩展精度,但是当保存在内存中时(当进程或线程发生上下文切换时会发生这种情况),这种精度会丢失。这可能会导致结果出现一些小的差异(我们在程序中检测到了这样的问题)。避免此问题的一种方法是要求编译器不要使用 FPU 而是使用 SSE 进行浮点运算。

    http://www.network-theory.co.uk/docs/gccintro/gccintro_70.html

    【讨论】:

      【解决方案5】:

      除了对 rand() 的杂散调用

      rand() 完全是确定性的,只要您为其提供相同的初始种子。

      【讨论】:

        【解决方案6】:

        没有看到一些代码(提示提示),我能想到的最好的方法就是寻找一个模式。可能是特定日期时间的。

        另外,请尝试寻找竞争条件。这看起来是不确定的。

        【讨论】:

          【解决方案7】:

          使用指针的值而不是它所指向的值总是会产生有趣的结果。

          【讨论】:

            【解决方案8】:

            在与“外部世界”交互不多的程序中,不确定性的流行来源是对指针比较的依赖。有时您可能会在代码中看到它:当字典比较函数用完要比较的东西(一切都相等)时,它会比较对象的 地址 作为最后的手段。如果在动态内存中分配对象,这可能会产生不同的顺序,因为实际分配位置可能因平台和运行而异。

            【讨论】:

              【解决方案9】:

              显然是Phase of the Moon 错误的一个新实例。

              【讨论】:

                【解决方案10】:
                • 来自网络/互联网的输入。
                • 日期/时间

                【讨论】:

                  【解决方案11】:

                  你没有提供很多信息。然而,作为一个以实时编程为生的人,当这种事情发生时,我寻找的最有可能的罪魁祸首是:

                  • 使用未初始化的内存。
                  • 竞争条件。
                  • 上述一些模糊的组合。

                  例如,我曾经遇到的一个这样的麻烦归结为共享库不像我想象的那样“共享”,并试图使用来自一个进程的句柄来索引一个尚未在第二个进程中初始化的表。取决于事情的启动方式,可能会或可能不会导致第三个进程中的重要数据被丢弃。

                  【讨论】:

                    【解决方案12】:

                    任何未定义的行为。即:需要数百页来解释输出更改的每个可能来源。尝试调试以查找发生更改的位置,或阅读一些 C++ 规范。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-03-31
                      • 2016-12-29
                      • 2016-05-14
                      • 1970-01-01
                      • 2013-02-18
                      相关资源
                      最近更新 更多